diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/Makefile.am | 2 | ||||
-rw-r--r-- | zebra/connected.c | 105 | ||||
-rw-r--r-- | zebra/connected.h | 11 | ||||
-rw-r--r-- | zebra/if_ioctl.c | 6 | ||||
-rw-r--r-- | zebra/if_ioctl_solaris.c | 4 | ||||
-rw-r--r-- | zebra/if_proc.c | 2 | ||||
-rw-r--r-- | zebra/interface.c | 356 | ||||
-rw-r--r-- | zebra/interface.h | 14 | ||||
-rw-r--r-- | zebra/ioctl.c | 63 | ||||
-rw-r--r-- | zebra/kernel_null.c | 2 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 54 | ||||
-rw-r--r-- | zebra/main.c | 22 | ||||
-rw-r--r-- | zebra/redistribute.c | 46 | ||||
-rw-r--r-- | zebra/rib.h | 31 | ||||
-rw-r--r-- | zebra/rt_ioctl.c | 2 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 227 | ||||
-rw-r--r-- | zebra/rt_socket.c | 7 | ||||
-rw-r--r-- | zebra/rtadv.c | 137 | ||||
-rw-r--r-- | zebra/rtadv.h | 14 | ||||
-rw-r--r-- | zebra/test_main.c | 11 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 294 | ||||
-rw-r--r-- | zebra/zebra_vty.c | 504 | ||||
-rw-r--r-- | zebra/zserv.c | 96 | ||||
-rw-r--r-- | zebra/zserv.h | 7 |
24 files changed, 1386 insertions, 631 deletions
diff --git a/zebra/Makefile.am b/zebra/Makefile.am index 542f36f4..828e88ff 100644 --- a/zebra/Makefile.am +++ b/zebra/Makefile.am @@ -1,7 +1,7 @@ ## Process this file with automake to produce Makefile.in. INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DMULTIPATH_NUM=@MULTIPATH_NUM@ +DEFS = @DEFS@ -DMULTIPATH_NUM=@MULTIPATH_NUM@ INSTALL_SDATA=@INSTALL@ -m 600 LIB_IPV6 = @LIB_IPV6@ diff --git a/zebra/connected.c b/zebra/connected.c index 95399fa1..0c22582d 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -36,6 +36,53 @@ #include "zebra/interface.h" #include "zebra/connected.h" extern struct zebra_t zebrad; + +#ifdef HAVE_NETLINK +static const struct message rtscope_str[] = { + {RT_SCOPE_UNIVERSE, "global"}, + {RT_SCOPE_SITE, "site"}, + {RT_SCOPE_LINK, "link"}, + {RT_SCOPE_HOST, "host"}, + {RT_SCOPE_NOWHERE, "nowhere"}, + {0, NULL} +}; + +/* for use in show interface */ +const char * +connected_scope_name(unsigned value) +{ + const char *str; + static char buf[16]; + + str = lookup (rtscope_str, value); + if (!str || !*str) { + snprintf (buf, sizeof(buf), "%d", value); + str = buf; + } + return str; +} + +int +connected_scope_number(const char *name) +{ + const struct message *m; + char *errptr; + unsigned value; + + if (!name || !*name) + return -1; + + for (m = rtscope_str; m->str; m++) + if (!strcmp (m->str, name)) + return m->key; + + value = strtoul (name, &errptr, 0); + if (*errptr || value > 255) + return -1; + + return value; +} +#endif /* HAVE_NETLINK */ /* withdraw a connected address */ static void @@ -112,6 +159,30 @@ connected_check (struct interface *ifp, struct prefix *p) return NULL; } +/* same, but with peer address */ +struct connected * +connected_check_ptp (struct interface *ifp, struct prefix *p, struct prefix *d) +{ + struct connected *ifc; + struct listnode *node; + + /* ignore broadcast addresses */ + if (p->prefixlen != IPV4_MAX_PREFIXLEN) + d = NULL; + + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) + { + if (!prefix_same (ifc->address, p)) + continue; + if (!CONNECTED_PEER(ifc) && !d) + return ifc; + if (CONNECTED_PEER(ifc) && d && prefix_same (ifc->destination, d)) + return ifc; + } + + return NULL; +} + /* Check if two ifc's describe the same address */ static int connected_same (struct connected *ifc1, struct connected *ifc2) @@ -148,7 +219,7 @@ connected_implicit_withdraw (struct interface *ifp, struct connected *ifc) struct connected *current; /* Check same connected route. */ - if ((current = connected_check (ifp, (struct prefix *) ifc->address))) + if ((current = connected_check_ptp (ifp, ifc->address, ifc->destination))) { if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); @@ -198,7 +269,7 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) void connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad, - const char *label) + const char *label, unsigned scope, int preference) { struct prefix_ipv4 *p; struct connected *ifc; @@ -212,7 +283,8 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, p = prefix_ipv4_new (); p->family = AF_INET; p->prefix = *addr; - p->prefixlen = prefixlen; + p->prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) + ? IPV4_MAX_PREFIXLEN : prefixlen; ifc->address = (struct prefix *) p; /* If there is broadcast or peer address. */ @@ -269,6 +341,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); + ifc->scope = scope; + ifc->preference = preference; + /* nothing to do? */ if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) return; @@ -305,15 +380,27 @@ void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad) { - struct prefix_ipv4 p; + struct prefix_ipv4 p, d; struct connected *ifc; memset (&p, 0, sizeof (struct prefix_ipv4)); p.family = AF_INET; p.prefix = *addr; - p.prefixlen = prefixlen; + p.prefixlen = CHECK_FLAG(flags, ZEBRA_IFA_PEER) + ? IPV4_MAX_PREFIXLEN : prefixlen; + + if (broad) + { + memset (&d, 0, sizeof (struct prefix_ipv4)); + d.family = AF_INET; + d.prefix = *broad; + d.prefixlen = prefixlen; + ifc = connected_check_ptp (ifp, (struct prefix *) &p, + (struct prefix *) &d); + } + else + ifc = connected_check_ptp (ifp, (struct prefix *) &p, NULL); - ifc = connected_check (ifp, (struct prefix *) &p); if (! ifc) return; @@ -352,7 +439,7 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) void connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, u_char prefixlen, struct in6_addr *broad, - const char *label) + const char *label, unsigned scope) { struct prefix_ipv6 *p; struct connected *ifc; @@ -395,7 +482,9 @@ connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr, /* Label of this address. */ if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); - + + ifc->scope = scope; + if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) return; diff --git a/zebra/connected.h b/zebra/connected.h index 9595ddb1..ede75120 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -25,11 +25,13 @@ extern struct connected * connected_check (struct interface *ifp, struct prefix *p); +extern struct connected * +connected_check_ptp (struct interface *ifp, struct prefix *p, struct prefix *d); extern void connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, struct in_addr *broad, - const char *label); + const char *label, unsigned scope, int preference); extern void connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, @@ -42,7 +44,7 @@ extern void connected_down_ipv4 (struct interface *, struct connected *); extern void connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *address, u_char prefixlen, struct in6_addr *broad, - const char *label); + const char *label, unsigned scope); extern void connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address, u_char prefixlen, struct in6_addr *broad); @@ -52,4 +54,9 @@ extern void connected_down_ipv6 (struct interface *ifp, struct connected *); #endif /* HAVE_IPV6 */ +#ifdef HAVE_NETLINK +extern const char *connected_scope_name (unsigned value); +extern int connected_scope_number (const char *name); +#endif /* HAVE_NETLINK */ + #endif /*_ZEBRA_CONNECTED_H */ diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index f357e154..36732704 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -276,7 +276,7 @@ if_getaddrs (void) } connected_add_ipv4 (ifp, flags, &addr->sin_addr, - prefixlen, dest_pnt, NULL); + prefixlen, dest_pnt, NULL, 0, 0); } #ifdef HAVE_IPV6 if (ifap->ifa_addr->sa_family == AF_INET6) @@ -321,7 +321,7 @@ if_getaddrs (void) #endif connected_add_ipv6 (ifp, flags, &addr->sin6_addr, prefixlen, - dest_pnt, NULL); + dest_pnt, NULL, 0); } #endif /* HAVE_IPV6 */ } @@ -412,7 +412,7 @@ if_get_addr (struct interface *ifp) /* Set address to the interface. */ - connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL); + connected_add_ipv4 (ifp, flags, &addr.sin_addr, prefixlen, dest_pnt, NULL, 0, 0); return 0; } diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c index fc384ea2..736232e8 100644 --- a/zebra/if_ioctl_solaris.c +++ b/zebra/if_ioctl_solaris.c @@ -327,11 +327,11 @@ if_get_addr (struct interface *ifp, struct sockaddr *addr, const char *label) /* 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); + (struct in_addr *) dest_pnt, label, 0, 0); #ifdef HAVE_IPV6 else if (af == AF_INET6) connected_add_ipv6 (ifp, flags, &SIN6 (addr)->sin6_addr, prefixlen, - (struct in6_addr *) dest_pnt, label); + (struct in6_addr *) dest_pnt, label, 0); #endif /* HAVE_IPV6 */ return 0; diff --git a/zebra/if_proc.c b/zebra/if_proc.c index 3aec530b..6c538116 100644 --- a/zebra/if_proc.c +++ b/zebra/if_proc.c @@ -240,7 +240,7 @@ ifaddr_proc_ipv6 () str2in6_addr (addr, &p.prefix); p.prefixlen = plen; - connected_add_ipv6 (ifp, 0, &p.prefix, p.prefixlen, NULL, ifname); + connected_add_ipv6 (ifp, 0, &p.prefix, p.prefixlen, NULL, ifname, 0); } fclose (fp); return 0; diff --git a/zebra/interface.c b/zebra/interface.c index ba4cf25f..e19648d7 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -83,6 +83,10 @@ if_zebra_new_hook (struct interface *ifp) rtadv->DefaultPreference = RTADV_PREF_MEDIUM; rtadv->AdvPrefixList = list_new (); + + rtadv->AdvRDNSSFlag = 0; + rtadv->AdvRDNSSLifetime = RTADV_RDNSS_DEFAULT_LIFETIME; + rtadv->AdvRDNSSList = list_new (); } #endif /* RTADV */ @@ -127,7 +131,7 @@ if_subnet_add (struct interface *ifp, struct connected *ifc) /* Get address derived subnet node and associated address list, while marking address secondary attribute appropriately. */ - cp = *ifc->address; + cp = *CONNECTED_PREFIX(ifc); apply_mask (&cp); rn = route_node_get (zebra_if->ipv4_subnets, &cp); @@ -154,12 +158,16 @@ if_subnet_delete (struct interface *ifp, struct connected *ifc) struct route_node *rn; struct zebra_if *zebra_if; struct list *addr_list; + struct prefix cp; assert (ifp && ifp->info && ifc); zebra_if = ifp->info; + cp = *CONNECTED_PREFIX(ifc); + apply_mask (&cp); + /* Get address derived subnet node. */ - rn = route_node_lookup (zebra_if->ipv4_subnets, ifc->address); + rn = route_node_lookup (zebra_if->ipv4_subnets, &cp); if (! (rn && rn->info)) return -1; route_unlock_node (rn); @@ -588,8 +596,18 @@ connected_dump_vty (struct vty *vty, struct connected *connected) { vty_out (vty, (CONNECTED_PEER(connected) ? " peer " : " broadcast ")); prefix_vty_out (vty, connected->destination); + vty_out (vty, "/%d", connected->destination->prefixlen); } +#ifdef HAVE_NETLINK + if (connected->scope != 0) + vty_out (vty, " scope %s", connected_scope_name (connected->scope)); +#endif +#ifdef SIOCSIFADDRPREF + if (connected->preference != 0) + vty_out (vty, " preference %d", connected->preference); +#endif + if (CHECK_FLAG (connected->flags, ZEBRA_IFA_SECONDARY)) vty_out (vty, " secondary"); @@ -641,6 +659,9 @@ nd_dump_vty (struct vty *vty, struct interface *ifp) vty_out (vty, " ND router advertisements with " "Home Agent flag bit set.%s", VTY_NEWLINE); + if (rtadv->AdvRDNSSFlag) + vty_out (vty, " ND router advertisements with " + "RDNSS information.%s", VTY_NEWLINE); if (rtadv->AdvIntervalOption) vty_out (vty, " ND router advertisements with Adv. Interval option.%s", VTY_NEWLINE); @@ -1002,6 +1023,53 @@ DEFUN (no_multicast, return CMD_SUCCESS; } +DEFUN (unnumbered, + unnumbered_cmd, + "unnumbered", + "Set interface to IP Unnumbered mode\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + + zlog_debug("VTY: interface %s, Setting ifp->status |= ZEBRA_INTERFACE_UNNUMBERED", + ifp->name); + + SET_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED); + + /* force protocols to recalculate routes due to IP change */ + if (if_is_operative (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + +DEFUN (no_unnumbered, + no_unnumbered_cmd, + "no unnumbered", + NO_STR + "Set interface to IP Numbered mode\n") +{ + int ret; + struct interface *ifp; + struct zebra_if *if_data; + + ifp = (struct interface *) vty->index; + + zlog_debug("VTY: interface %s, Setting ifp->status &= ~ZEBRA_INTERFACE_UNNUMBERED;", + ifp->name); + + UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED); + + /* force protocols to recalculate routes due to IP change */ + if (if_is_operative (ifp)) + zebra_interface_up_update (ifp); + + return CMD_SUCCESS; +} + DEFUN (linkdetect, linkdetect_cmd, "link-detect", @@ -1149,21 +1217,62 @@ ALIAS (no_bandwidth_if, static int ip_address_install (struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, - const char *label) + const char *label, const char *scope, + const char *preference) { - struct prefix_ipv4 cp; + struct prefix_ipv4 lp, pp; struct connected *ifc; struct prefix_ipv4 *p; int ret; + int scopev = 0, preferencev = 0; - ret = str2prefix_ipv4 (addr_str, &cp); + ret = str2prefix_ipv4 (addr_str, &lp); if (ret <= 0) + { + vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); + return CMD_WARNING; + } + + if (peer_str) { - vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); - return CMD_WARNING; + if (lp.prefixlen != 32) + { + vty_out (vty, "%% Local prefix length for P-t-P address " + "must be /32%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_ipv4 (peer_str, &pp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed peer address %s", VTY_NEWLINE); + return CMD_WARNING; + } } - ifc = connected_check (ifp, (struct prefix *) &cp); +#ifdef HAVE_NETLINK + if (scope) + { + scopev = connected_scope_number (scope); + if (scopev < 0) + { + vty_out (vty, "%% Malformed scope %s", VTY_NEWLINE); + return CMD_WARNING; + } + } +#endif + if (preference) + { + preferencev = atoi (preference); + if (preferencev < -32768 || preferencev > 32767) + { + vty_out (vty, "%% Invalid preference %s", VTY_NEWLINE); + return CMD_WARNING; + } + } + + ifc = connected_check_ptp (ifp, (struct prefix *) &lp, + (struct prefix *)(peer_str ? &pp : NULL)); if (! ifc) { ifc = connected_new (); @@ -1171,14 +1280,23 @@ ip_address_install (struct vty *vty, struct interface *ifp, /* Address. */ p = prefix_ipv4_new (); - *p = cp; + *p = lp; ifc->address = (struct prefix *) p; + ifc->scope = scopev; + ifc->preference = preferencev; - /* Broadcast. */ - if (p->prefixlen <= IPV4_MAX_PREFIXLEN-2) + if (peer_str) { + SET_FLAG(ifc->flags, ZEBRA_IFA_PEER); p = prefix_ipv4_new (); - *p = cp; + *p = pp; + ifc->destination = (struct prefix *) p; + } + else if (p->prefixlen <= IPV4_MAX_PREFIXLEN-2) + { + /* Broadcast. */ + p = prefix_ipv4_new (); + *p = lp; p->prefix.s_addr = ipv4_broadcast_addr(p->prefix.s_addr,p->prefixlen); ifc->destination = (struct prefix *) p; } @@ -1233,23 +1351,40 @@ ip_address_install (struct vty *vty, struct interface *ifp, static int ip_address_uninstall (struct vty *vty, struct interface *ifp, - const char *addr_str, const char *peer_str, - const char *label) + const char *addr_str, const char *peer_str) { - struct prefix_ipv4 cp; + struct prefix_ipv4 lp, pp; struct connected *ifc; int ret; /* Convert to prefix structure. */ - ret = str2prefix_ipv4 (addr_str, &cp); + ret = str2prefix_ipv4 (addr_str, &lp); if (ret <= 0) { vty_out (vty, "%% Malformed address %s", VTY_NEWLINE); return CMD_WARNING; } + if (peer_str) + { + if (lp.prefixlen != 32) + { + vty_out (vty, "%% Local prefix length for P-t-P address " + "must be /32%s", VTY_NEWLINE); + return CMD_WARNING; + } + + ret = str2prefix_ipv4 (peer_str, &pp); + if (ret <= 0) + { + vty_out (vty, "%% Malformed peer address %s", VTY_NEWLINE); + return CMD_WARNING; + } + } + /* Check current interface address. */ - ifc = connected_check (ifp, (struct prefix *) &cp); + ifc = connected_check_ptp (ifp, (struct prefix *) &lp, + (struct prefix *)(peer_str ? &pp : NULL)); if (! ifc) { vty_out (vty, "%% Can't find address%s", VTY_NEWLINE); @@ -1279,70 +1414,169 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, safe_strerror(errno), VTY_NEWLINE); return CMD_WARNING; } + /* success! now update all internal state... */ + + /* Remove connected route. */ + connected_down_ipv4 (ifp, ifc); -#if 0 /* Redistribute this information. */ zebra_interface_address_delete_update (ifp, ifc); - /* Remove connected route. */ - connected_down_ipv4 (ifp, ifc); + /* IP address propery set. */ + UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL); + + /* remove from interface, remark secondaries */ + if_subnet_delete (ifp, ifc); /* Free address information. */ listnode_delete (ifp->connected, ifc); connected_free (ifc); -#endif return CMD_SUCCESS; } +#define IP_ADDR_STR \ + "Interface Internet Protocol config commands\n" \ + "Set the IP address of an interface\n" \ + "IP address (e.g. 10.0.0.1/8)\n" +#define IP_ADDR_PEER_STR \ + "Interface Internet Protocol config commands\n" \ + "Set the IP address of an interface\n" \ + "Local IP (e.g. 10.0.0.1) for P-t-P address\n" \ + "Specify P-t-P address\n" \ + "Peer IP address (e.g. 10.0.0.1/8)\n" + DEFUN (ip_address, ip_address_cmd, "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") + IP_ADDR_STR) { - return ip_address_install (vty, vty->index, argv[0], NULL, NULL); + return ip_address_install (vty, vty->index, argv[0], NULL, + NULL, NULL, NULL); } DEFUN (no_ip_address, no_ip_address_cmd, "no ip address A.B.C.D/M", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP Address (e.g. 10.0.0.1/8)") + NO_STR IP_ADDR_STR) +{ + return ip_address_uninstall (vty, vty->index, argv[0], NULL); +} + +DEFUN (ip_address_peer, + ip_address_peer_cmd, + "ip address A.B.C.D peer A.B.C.D/M", + IP_ADDR_PEER_STR) +{ + return ip_address_install (vty, vty->index, argv[0], argv[1], + NULL, NULL, NULL); +} + +DEFUN (no_ip_address_peer, + no_ip_address_peer_cmd, + "no ip address A.B.C.D peer A.B.C.D/M", + NO_STR IP_ADDR_PEER_STR) { - return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL); + return ip_address_uninstall (vty, vty->index, argv[0], argv[1]); } #ifdef HAVE_NETLINK DEFUN (ip_address_label, ip_address_label_cmd, "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" + IP_ADDR_STR "Label of this address\n" "Label\n") { - return ip_address_install (vty, vty->index, argv[0], NULL, argv[1]); + return ip_address_install (vty, vty->index, argv[0], NULL, + argv[1], NULL, NULL); } -DEFUN (no_ip_address_label, - no_ip_address_label_cmd, - "no ip address A.B.C.D/M label LINE", - NO_STR - "Interface Internet Protocol config commands\n" - "Set the IP address of an interface\n" - "IP address (e.g. 10.0.0.1/8)\n" +DEFUN (ip_address_peer_label, + ip_address_peer_label_cmd, + "ip address A.B.C.D peer A.B.C.D/M label LINE", + IP_ADDR_PEER_STR "Label of this address\n" "Label\n") { - return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1]); + return ip_address_install (vty, vty->index, argv[0], argv[1], + argv[2], NULL, NULL); +} + +DEFUN (ip_address_scope, + ip_address_scope_cmd, + "ip address A.B.C.D/M scope WORD", + IP_ADDR_STR + "Scope of this address\n" + "Scope (e.g. 0-255 or global,site,link,host,nowhere)\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, + NULL, argv[1], NULL); +} + +DEFUN (ip_address_peer_scope, + ip_address_peer_scope_cmd, + "ip address A.B.C.D peer A.B.C.D/M scope WORD", + IP_ADDR_PEER_STR + "Scope of this address\n" + "Scope (e.g. 0-255 or global,site,link,host,nowhere)\n") +{ + return ip_address_install (vty, vty->index, argv[0], argv[1], + NULL, argv[2], NULL); } + +DEFUN (ip_address_scope_label, + ip_address_scope_label_cmd, + "ip address A.B.C.D/M scope WORD label LINE", + IP_ADDR_STR + "Scope of this address\n" + "Scope (e.g. 0-255 or global,site,link,host,nowhere)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, + argv[2], argv[1], NULL); +} + +DEFUN (ip_address_peer_scope_label, + ip_address_peer_scope_label_cmd, + "ip address A.B.C.D peer A.B.C.D/M scope WORD label LINE", + IP_ADDR_PEER_STR + "Scope of this address\n" + "Scope (e.g. 0-255 or global,site,link,host,nowhere)\n" + "Label of this address\n" + "Label\n") +{ + return ip_address_install (vty, vty->index, argv[0], argv[1], + argv[3], argv[2], NULL); +} + #endif /* HAVE_NETLINK */ +#ifdef SIOCSIFADDRPREF +DEFUN (ip_address_pref, + ip_address_pref_cmd, + "ip address A.B.C.D/M preference WORD", + IP_ADDR_STR + "specify IPSRCSEL preference\n" + "preference value, higher is preferred\n") +{ + return ip_address_install (vty, vty->index, argv[0], NULL, + NULL, NULL, argv[1]); +} + +DEFUN (ip_address_peer_pref, + ip_address_peer_pref_cmd, + "ip address A.B.C.D peer A.B.C.D/M preference WORD", + IP_ADDR_PEER_STR + "specify IPSRCSEL preference\n" + "preference value, higher is preferred\n") +{ + return ip_address_install (vty, vty->index, argv[0], argv[1], + NULL, NULL, argv[2]); +} +#endif + #ifdef HAVE_IPV6 static int ipv6_address_install (struct vty *vty, struct interface *ifp, @@ -1531,6 +1765,9 @@ if_config_write (struct vty *vty) if (ifp->bandwidth != 0) vty_out(vty, " bandwidth %u%s", ifp->bandwidth, VTY_NEWLINE); + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_UNNUMBERED)) + vty_out (vty, " unnumbered%s", VTY_NEWLINE); + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) vty_out(vty, " link-detect%s", VTY_NEWLINE); @@ -1540,14 +1777,27 @@ if_config_write (struct vty *vty) { char buf[INET6_ADDRSTRLEN]; p = ifc->address; - vty_out (vty, " ip%s address %s/%d", + vty_out (vty, " ip%s address %s", p->family == AF_INET ? "" : "v6", - inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf)), - p->prefixlen); + inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf))); + if (CONNECTED_PEER (ifc)) + { + p = ifc->destination; + vty_out (vty, " peer %s", + inet_ntop (p->family, &p->u.prefix, buf, sizeof(buf))); + } + vty_out (vty, "/%d", p->prefixlen); +#ifdef HAVE_NETLINK + if (ifc->scope) + vty_out (vty, " scope %s", connected_scope_name (ifc->scope)); if (ifc->label) vty_out (vty, " label %s", ifc->label); - +#endif +#ifdef SIOCSIFADDRPREF + if (ifc->preference) + vty_out (vty, " preference %d", ifc->preference); +#endif vty_out (vty, "%s", VTY_NEWLINE); } } @@ -1598,6 +1848,8 @@ zebra_if_init (void) install_element (INTERFACE_NODE, &no_interface_desc_cmd); install_element (INTERFACE_NODE, &multicast_cmd); install_element (INTERFACE_NODE, &no_multicast_cmd); + install_element (INTERFACE_NODE, &unnumbered_cmd); + install_element (INTERFACE_NODE, &no_unnumbered_cmd); install_element (INTERFACE_NODE, &linkdetect_cmd); install_element (INTERFACE_NODE, &no_linkdetect_cmd); install_element (INTERFACE_NODE, &shutdown_if_cmd); @@ -1607,12 +1859,22 @@ zebra_if_init (void) install_element (INTERFACE_NODE, &no_bandwidth_if_val_cmd); install_element (INTERFACE_NODE, &ip_address_cmd); install_element (INTERFACE_NODE, &no_ip_address_cmd); + install_element (INTERFACE_NODE, &ip_address_peer_cmd); + install_element (INTERFACE_NODE, &no_ip_address_peer_cmd); #ifdef HAVE_IPV6 install_element (INTERFACE_NODE, &ipv6_address_cmd); install_element (INTERFACE_NODE, &no_ipv6_address_cmd); #endif /* HAVE_IPV6 */ #ifdef HAVE_NETLINK install_element (INTERFACE_NODE, &ip_address_label_cmd); - install_element (INTERFACE_NODE, &no_ip_address_label_cmd); + install_element (INTERFACE_NODE, &ip_address_scope_cmd); + install_element (INTERFACE_NODE, &ip_address_scope_label_cmd); + install_element (INTERFACE_NODE, &ip_address_peer_label_cmd); + install_element (INTERFACE_NODE, &ip_address_peer_scope_cmd); + install_element (INTERFACE_NODE, &ip_address_peer_scope_label_cmd); #endif /* HAVE_NETLINK */ +#ifdef SIOCSIFADDRPREF + install_element (INTERFACE_NODE, &ip_address_pref_cmd); + install_element (INTERFACE_NODE, &ip_address_peer_pref_cmd); +#endif } diff --git a/zebra/interface.h b/zebra/interface.h index 0cf66403..305abaac 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -178,6 +178,20 @@ struct rtadvconf Default: 0 (medium) */ int DefaultPreference; #define RTADV_PREF_MEDIUM 0x0 /* Per RFC4191. */ + + /* A list of Recursive DNS server addresses specified in + RFC 5006 */ + int AdvRDNSSFlag; + struct list *AdvRDNSSList; + + /* the maximum lifetime in seconds over which the RDNSS entry + * may be used. After this time a host may send a router solicitation + * message to refresh the RDNSS information. + * + * Default is infinity lifetime (0xffffffff) */ + uint32_t AdvRDNSSLifetime; +#define RTADV_RDNSS_INFINITY_LIFETIME (0xffffffff) +#define RTADV_RDNSS_DEFAULT_LIFETIME RTADV_RDNSS_INFINITY_LIFETIME }; #endif /* RTADV */ diff --git a/zebra/ioctl.c b/zebra/ioctl.c index d783b0a3..6cb428a7 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -191,10 +191,16 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* don't configure PtP addresses on broadcast ifs or reverse */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER (ifc)) + { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *) ifc->address; rib_lookup_and_pushup (p); @@ -209,6 +215,18 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + if (CONNECTED_PEER (ifc)) + { + p = (struct prefix_ipv4 *) ifc->destination; + memset (&mask, 0, sizeof (struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_broadaddr, &peer, sizeof (struct sockaddr_in)); + } + memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; @@ -216,10 +234,27 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) 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; + +#ifdef SIOCSIFADDRPREF + if (ifc->preference != 0) + { + struct if_addrprefreq ifapr; + + memset (&ifapr, 0, sizeof ifapr); + strncpy ((char *)&ifapr.ifap_name, ifp->name, sizeof ifapr.ifap_name); + ifapr.ifap_preference = ifc->preference; + memcpy (&ifapr.ifap_addr, &addr, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCSIFADDRPREF, (caddr_t) &ifapr); + if (ret < 0) + zlog_err("if_ioctl(SIOCSIFADDRPREF) failed: %s", + safe_strerror(errno)); + } +#endif return 0; } @@ -230,10 +265,16 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc) { int ret; struct ifaliasreq addreq; - struct sockaddr_in addr; - struct sockaddr_in mask; + struct sockaddr_in addr, mask, peer; struct prefix_ipv4 *p; + /* this would probably wreak havoc */ + if (!(ifp->flags & IFF_POINTOPOINT) != !CONNECTED_PEER (ifc)) + { + errno = EINVAL; + return -1; + } + p = (struct prefix_ipv4 *)ifc->address; memset (&addreq, 0, sizeof addreq); @@ -247,6 +288,18 @@ if_unset_prefix (struct interface *ifp, struct connected *ifc) #endif memcpy (&addreq.ifra_addr, &addr, sizeof (struct sockaddr_in)); + if (CONNECTED_PEER (ifc)) + { + p = (struct prefix_ipv4 *) ifc->destination; + memset (&mask, 0, sizeof (struct sockaddr_in)); + peer.sin_addr = p->prefix; + peer.sin_family = p->family; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + peer.sin_len = sizeof (struct sockaddr_in); +#endif + memcpy (&addreq.ifra_broadaddr, &peer, sizeof (struct sockaddr_in)); + } + memset (&mask, 0, sizeof (struct sockaddr_in)); masklen2ip (p->prefixlen, &mask.sin_addr); mask.sin_family = p->family; diff --git a/zebra/kernel_null.c b/zebra/kernel_null.c index 6b96c6df..f83c2345 100644 --- a/zebra/kernel_null.c +++ b/zebra/kernel_null.c @@ -25,7 +25,7 @@ int kernel_address_add_ipv4 (struct interface *a, struct connected *b) SET_FLAG (b->conf, ZEBRA_IFC_REAL); connected_add_ipv4 (a, 0, &b->address->u.prefix4, b->address->prefixlen, (b->destination ? &b->destination->u.prefix4 : NULL), - NULL); + NULL, 0, 0); return 0; } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index feeaf5d0..d0908115 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -253,6 +253,25 @@ rtm_flag_dump (int flag) zlog_debug ("Kernel: %s", buf); } +/* NetBSD IPSRCSEL preference readback */ +static int +if_get_addrpref (const char *ifname, struct sockaddr_in *addr) +{ +#ifdef SIOCSIFADDRPREF + int ret; + struct if_addrprefreq ifapr; + + memset (&ifapr, 0, sizeof ifapr); + strncpy ((char *)&ifapr.ifap_name, ifname, sizeof ifapr.ifap_name); + memcpy (&ifapr.ifap_addr, addr, sizeof (struct sockaddr_in)); + + ret = if_ioctl (SIOCGIFADDRPREF, (caddr_t) &ifapr); + if (ret == 0) + return ifapr.ifap_preference; +#endif + return 0; +} + #ifdef RTM_IFANNOUNCE /* Interface adding function */ static int @@ -319,6 +338,7 @@ int ifm_read (struct if_msghdr *ifm) { struct interface *ifp = NULL; + struct sockaddr_dl *sdl; char ifname[IFNAMSIZ]; short ifnlen = 0; caddr_t *cp; @@ -356,6 +376,7 @@ ifm_read (struct if_msghdr *ifm) 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); @@ -454,6 +475,16 @@ ifm_read (struct if_msghdr *ifm) #endif /* __bsdi__ */ if_get_metric (ifp); + /* + * XXX sockaddr_dl contents can be larger than the structure + * definition, so the user of the stored structure must be + * careful not to read off the end. + * + * a nonzero ifnlen from RTA_NAME_GET() means sdl is valid + */ + if (ifnlen) + memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl)); + if_add_update (ifp); } else @@ -619,6 +650,7 @@ ifam_read (struct ifa_msghdr *ifam) short ifnlen = 0; char isalias = 0; int flags = 0; + int preference = 0; ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0'; @@ -649,6 +681,9 @@ ifam_read (struct ifa_msghdr *ifam) */ ifp->metric = ifam->ifam_metric; #endif + if (sockunion_family (&addr) == AF_INET + && ifam->ifam_type == RTM_NEWADDR) + preference = if_get_addrpref (ifp->name, &addr.sin); /* Add connected address. */ switch (sockunion_family (&addr)) @@ -658,7 +693,7 @@ ifam_read (struct ifa_msghdr *ifam) connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), &brd.sin.sin_addr, - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), 0, preference); else connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr, ip_masklen (mask.sin.sin_addr), @@ -675,7 +710,7 @@ ifam_read (struct ifa_msghdr *ifam) connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr, ip6_masklen (mask.sin6.sin6_addr), &brd.sin6.sin6_addr, - (isalias ? ifname : NULL)); + (isalias ? ifname : NULL), 0); else connected_delete_ipv6 (ifp, &addr.sin6.sin6_addr, @@ -804,9 +839,9 @@ rtm_read (struct rt_msghdr *rtm) /* This is a reject or blackhole route */ if (flags & RTF_REJECT) - SET_FLAG (zebra_flags, ZEBRA_FLAG_REJECT); + SET_FLAG (zebra_flags, RIB_ZF_REJECT << 8); if (flags & RTF_BLACKHOLE) - SET_FLAG (zebra_flags, ZEBRA_FLAG_BLACKHOLE); + SET_FLAG (zebra_flags, RIB_ZF_BLACKHOLE << 8); if (dest.sa.sa_family == AF_INET) { @@ -1037,11 +1072,12 @@ rtm_write (int message, 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; - + if (RIB_ZF_BLACKHOLE_FLAGS (zebra_flags >> 8)) + { + unsigned bh_type = RIB_ZF_BLACKHOLE_FLAGS(zebra_flags >> 8); + msg.rtm.rtm_flags |= (bh_type == RIB_ZF_REJECT) + ? RTF_REJECT : RTF_BLACKHOLE; + } #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN #define SOCKADDRSET(X,R) \ diff --git a/zebra/main.c b/zebra/main.c index d829c046..b58fed12 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -32,6 +32,7 @@ #include "plist.h" #include "privs.h" #include "sigevent.h" +#include "paths.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -68,6 +69,7 @@ struct option longopts[] = { { "batch", no_argument, NULL, 'b'}, { "daemon", no_argument, NULL, 'd'}, + { "namespace", required_argument, NULL, 'N'}, { "keep_kernel", no_argument, NULL, 'k'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, @@ -108,10 +110,13 @@ struct zebra_privs_t zserv_privs = }; /* Default configuration file path. */ -char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; +char config_default[MAXPATHLEN]; + +/* pid_file default value */ +static char pid_file_default[MAXPATHLEN]; /* Process ID saved for use by init system */ -const char *pid_file = PATH_ZEBRA_PID; +const char *pid_file = pid_file_default; /* Help information display. */ static void @@ -126,6 +131,7 @@ usage (char *progname, int status) "redistribution between different routing protocols.\n\n"\ "-b, --batch Runs in batch mode\n"\ "-d, --daemon Runs in daemon mode\n"\ + "-N, --namespace Insert argument into all paths\n"\ "-f, --config_file Set configuration file name\n"\ "-i, --pid_file Set process identifier file name\n"\ "-k, --keep_kernel Don't delete old routes which installed by "\ @@ -229,9 +235,9 @@ main (int argc, char **argv) int opt; #ifdef HAVE_NETLINK - opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vs:C", longopts, 0); + opt = getopt_long (argc, argv, "bdN:kf:i:hA:P:ru:g:vs:C", longopts, 0); #else - opt = getopt_long (argc, argv, "bdkf:i:hA:P:ru:g:vC", longopts, 0); + opt = getopt_long (argc, argv, "bdN:kf:i:hA:P:ru:g:vC", longopts, 0); #endif /* HAVE_NETLINK */ if (opt == EOF) @@ -246,6 +252,9 @@ main (int argc, char **argv) case 'd': daemon_mode = 1; break; + case 'N': + path_set_namespace (optarg); + break; case 'k': keep_kernel_mode = 1; break; @@ -300,6 +309,9 @@ main (int argc, char **argv) } } + strcpy (config_default, path_config (ZEBRA_CONFIG_NAME)); + strcpy (pid_file_default, path_state (ZEBRA_PID_NAME)); + /* Make master thread emulator. */ zebrad.master = thread_master_create (); @@ -389,7 +401,7 @@ main (int argc, char **argv) zebra_zserv_socket_init (); /* Make vty server socket. */ - vty_serv_sock (vty_addr, vty_port, ZEBRA_VTYSH_PATH); + vty_serv_sock (vty_addr, vty_port, path_state (ZEBRA_VTY_NAME)); /* Print banner. */ zlog_notice ("Zebra %s starting: vty@%d", QUAGGA_VERSION, vty_port); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index a8107aeb..4276f1d0 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -245,26 +245,15 @@ zebra_redistribute_add (int command, struct zserv *client, int length) type = stream_getc (client->ibuf); - switch (type) + if (type == 0 || type >= ZEBRA_ROUTE_MAX) + return; + + if (! client->redist[type]) { - case ZEBRA_ROUTE_KERNEL: - case ZEBRA_ROUTE_CONNECT: - case ZEBRA_ROUTE_STATIC: - case ZEBRA_ROUTE_RIP: - case ZEBRA_ROUTE_RIPNG: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_BGP: - if (! client->redist[type]) - { - client->redist[type] = 1; - zebra_redistribute (client, type); - } - break; - default: - break; + client->redist[type] = 1; + zebra_redistribute (client, type); } -} +} void zebra_redistribute_delete (int command, struct zserv *client, int length) @@ -273,22 +262,11 @@ zebra_redistribute_delete (int command, struct zserv *client, int length) type = stream_getc (client->ibuf); - switch (type) - { - case ZEBRA_ROUTE_KERNEL: - case ZEBRA_ROUTE_CONNECT: - case ZEBRA_ROUTE_STATIC: - case ZEBRA_ROUTE_RIP: - case ZEBRA_ROUTE_RIPNG: - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - case ZEBRA_ROUTE_BGP: - client->redist[type] = 0; - break; - default: - break; - } -} + if (type == 0 || type >= ZEBRA_ROUTE_MAX) + return; + + client->redist[type] = 0; +} void zebra_redistribute_default_add (int command, struct zserv *client, int length) diff --git a/zebra/rib.h b/zebra/rib.h index 887ed3c2..2abfed19 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -73,6 +73,15 @@ struct rib */ u_char flags; + /* flags internal to zebra, not sent to clients */ + unsigned zflags; + /* blackhole route zflags, for static routes: */ +#define RIB_ZF_REJECT 1 +#define RIB_ZF_PROHIBIT 2 +#define RIB_ZF_BLACKHOLE 3 + +#define RIB_ZF_BLACKHOLE_FLAGS(zflags) ((zflags) & RIB_ZF_BLACKHOLE) + /* RIB internal status */ u_char status; #define RIB_ENTRY_REMOVED (1 << 0) @@ -120,12 +129,8 @@ struct static_ipv4 char *ifname; } gate; - /* bit flags */ - u_char flags; -/* - see ZEBRA_FLAG_REJECT - ZEBRA_FLAG_BLACKHOLE - */ + /* zflags for rib */ + unsigned zflags; }; #ifdef HAVE_IPV6 @@ -144,17 +149,14 @@ struct static_ipv6 #define STATIC_IPV6_GATEWAY 1 #define STATIC_IPV6_GATEWAY_IFNAME 2 #define STATIC_IPV6_IFNAME 3 +#define STATIC_IPV6_BLACKHOLE 4 /* Nexthop value. */ struct in6_addr ipv6; char *ifname; - /* bit flags */ - u_char flags; -/* - see ZEBRA_FLAG_REJECT - ZEBRA_FLAG_BLACKHOLE - */ + /* zflags for rib */ + unsigned zflags; }; #endif /* HAVE_IPV6 */ @@ -262,6 +264,7 @@ extern struct rib *rib_match_ipv4 (struct in_addr); extern struct rib *rib_lookup_ipv4 (struct prefix_ipv4 *); extern void rib_update (void); +extern void rib_update_background (void); extern void rib_weed_tables (void); extern void rib_sweep_route (void); extern void rib_close (void); @@ -269,7 +272,7 @@ extern void rib_init (void); extern int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id); + unsigned zflags, u_char distance, u_int32_t vrf_id); extern int static_delete_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, @@ -293,7 +296,7 @@ extern struct route_table *rib_table_ipv6; extern int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, unsigned zflags, u_char distance, u_int32_t vrf_id); extern int diff --git a/zebra/rt_ioctl.c b/zebra/rt_ioctl.c index a5d588c7..390e6a1d 100644 --- a/zebra/rt_ioctl.c +++ b/zebra/rt_ioctl.c @@ -183,7 +183,7 @@ kernel_ioctl_ipv4 (u_long cmd, struct prefix *p, struct rib *rib, int family) #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ sin_dest.sin_addr = p->u.prefix4; - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) + if (RIB_ZF_BLACKHOLE_FLAGS (rib->zflags)) { SET_FLAG (rtentry.rt_flags, RTF_REJECT); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 7652f80a..23acd5f3 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -85,6 +85,28 @@ extern struct zebra_privs_t zserv_privs; extern u_int32_t nl_rcvbufsize; +/* dispatch rtm_type field, return 1 if we want to process this */ +static int +get_discard_or_unicast (unsigned char rtm_type, unsigned *zflags) +{ + switch (rtm_type) + { + case RTN_UNICAST: + *zflags = 0; + return 1; + case RTN_UNREACHABLE: + *zflags = RIB_ZF_REJECT; + return 1; + case RTN_PROHIBIT: + *zflags = RIB_ZF_PROHIBIT; + return 1; + case RTN_BLACKHOLE: + *zflags = RIB_ZF_BLACKHOLE; + return 1; + } + return 0; +} + /* Note: on netlink systems, there should be a 1-to-1 mapping between interface names and ifindex values. */ static void @@ -549,6 +571,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) char buf[BUFSIZ]; zlog_debug ("netlink_interface_addr %s %s:", lookup (nlmsg_str, h->nlmsg_type), ifp->name); + zlog_debug (" ifa_scope %s", connected_scope_name (ifa->ifa_scope)); if (tb[IFA_LOCAL]) zlog_debug (" IFA_LOCAL %s/%d", inet_ntop (ifa->ifa_family, RTA_DATA (tb[IFA_LOCAL]), @@ -616,7 +639,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, - (struct in_addr *) broad, label); + (struct in_addr *) broad, label, ifa->ifa_scope, 0); else connected_delete_ipv4 (ifp, flags, (struct in_addr *) addr, ifa->ifa_prefixlen, @@ -628,7 +651,7 @@ netlink_interface_addr (struct sockaddr_nl *snl, struct nlmsghdr *h) if (h->nlmsg_type == RTM_NEWADDR) connected_add_ipv6 (ifp, flags, (struct in6_addr *) addr, ifa->ifa_prefixlen, - (struct in6_addr *) broad, label); + (struct in6_addr *) broad, label, ifa->ifa_scope); else connected_delete_ipv6 (ifp, (struct in6_addr *) addr, ifa->ifa_prefixlen, @@ -647,6 +670,7 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) struct rtmsg *rtm; struct rtattr *tb[RTA_MAX + 1]; u_char flags = 0; + unsigned discard = 0; char anyaddr[16] = { 0 }; @@ -662,7 +686,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) if (h->nlmsg_type != RTM_NEWROUTE) return 0; - if (rtm->rtm_type != RTN_UNICAST) + + if (!get_discard_or_unicast (rtm->rtm_type, &discard)) return 0; table = rtm->rtm_table; @@ -723,7 +748,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 4); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags | (discard << 8), &p, + gate, src, index, table, metric, 0); } #ifdef HAVE_IPV6 if (rtm->rtm_family == AF_INET6) @@ -733,8 +759,8 @@ netlink_routing_table (struct sockaddr_nl *snl, struct nlmsghdr *h) memcpy (&p.prefix, dest, 16); p.prefixlen = rtm->rtm_dst_len; - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, index, table, - metric, 0); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, flags | (discard << 8), &p, + gate, index, table, metric, 0); } #endif /* HAVE_IPV6 */ @@ -771,6 +797,7 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) void *dest; void *gate; void *src; + unsigned discard = 0; rtm = NLMSG_DATA (h); @@ -787,10 +814,10 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) h->nlmsg_type == RTM_NEWROUTE ? "RTM_NEWROUTE" : "RTM_DELROUTE", rtm->rtm_family == AF_INET ? "ipv4" : "ipv6", - rtm->rtm_type == RTN_UNICAST ? "unicast" : "multicast", + rtm->rtm_type == RTN_UNICAST ? "unicast" : "!unicast", lookup (rtproto_str, rtm->rtm_protocol)); - if (rtm->rtm_type != RTN_UNICAST) + if (!get_discard_or_unicast (rtm->rtm_type, &discard)) { return 0; } @@ -861,9 +888,11 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0); + rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, discard << 8, &p, + gate, src, index, table, 0, 0); else - rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); + rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, discard << 8, &p, + gate, index, table); } #ifdef HAVE_IPV6 @@ -889,9 +918,11 @@ netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h) } if (h->nlmsg_type == RTM_NEWROUTE) - rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, 0, 0); + rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, discard << 8, &p, + gate, index, table, 0, 0); else - rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table); + rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, discard << 8, &p, + gate, index, table); } #endif /* HAVE_IPV6 */ @@ -1218,80 +1249,6 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *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[1024]; - } req; - - memset (&req, 0, sizeof req); - - 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; -} - -/* Routing table change via netlink interface. */ -static int netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, int family) { @@ -1299,7 +1256,7 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, struct sockaddr_nl snl; struct nexthop *nexthop = NULL; int nexthop_num = 0; - int discard; + unsigned discard; struct { @@ -1321,24 +1278,29 @@ netlink_route_multipath (int cmd, struct prefix *p, struct rib *rib, 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; + discard = RIB_ZF_BLACKHOLE_FLAGS (rib->zflags); 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; + switch (discard) + { + case RIB_ZF_REJECT: + req.r.rtm_type = RTN_UNREACHABLE; + break; + /* IPv6 only supports RTN_UNREACHABLE on Linux, it seems */ + case RIB_ZF_PROHIBIT: + req.r.rtm_type = RTN_PROHIBIT; + if (family == AF_INET6) + req.r.rtm_type = RTN_UNREACHABLE; + break; + case RIB_ZF_BLACKHOLE: + req.r.rtm_type = RTN_BLACKHOLE; + if (family == AF_INET6) + req.r.rtm_type = RTN_UNREACHABLE; + break; + default: + req.r.rtm_type = RTN_UNICAST; + } } addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); @@ -1742,13 +1704,50 @@ kernel_delete_ipv6 (struct prefix *p, struct rib *rib) return netlink_route_multipath (RTM_DELROUTE, p, rib, AF_INET6); } -/* Delete IPv6 route from the kernel. */ +/* Delete IPv6 route from the kernel. + * only called from rib_bogus_ipv6 */ int kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate, unsigned int index, int flags, int table) { - return netlink_route (RTM_DELROUTE, AF_INET6, &dest->prefix, - dest->prefixlen, gate, index, flags, table); + int ret; + struct sockaddr_nl snl; + + struct + { + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; + } req; + + memset (&req, 0, sizeof req); + + req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELROUTE; + req.r.rtm_family = AF_INET6; + req.r.rtm_table = table; + req.r.rtm_dst_len = dest->prefixlen; + req.r.rtm_protocol = RTPROT_ZEBRA; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + + addattr_l (&req.n, sizeof req, RTA_DST, &dest->prefix, 16); + + if (gate) + addattr_l (&req.n, sizeof req, RTA_GATEWAY, gate, 16); + 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; } #endif /* HAVE_IPV6 */ @@ -1778,20 +1777,30 @@ netlink_address (int cmd, int family, struct interface *ifp, req.ifa.ifa_family = family; req.ifa.ifa_index = ifp->ifindex; - req.ifa.ifa_prefixlen = p->prefixlen; + req.ifa.ifa_scope = ifc->scope; addattr_l (&req.n, sizeof req, IFA_LOCAL, &p->u.prefix, bytelen); - if (family == AF_INET && cmd == RTM_NEWADDR) + if (family == AF_INET) { - if (!CONNECTED_PEER(ifc) && ifc->destination) + if (CONNECTED_PEER(ifc)) { p = ifc->destination; - addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, + addattr_l (&req.n, sizeof req, IFA_ADDRESS, &p->u.prefix, bytelen); } + else + if (cmd == RTM_NEWADDR && ifc->destination) + { + p = ifc->destination; + addattr_l (&req.n, sizeof req, IFA_BROADCAST, &p->u.prefix, + bytelen); + } } + /* p is now either ifc->address or ifc->destination */ + req.ifa.ifa_prefixlen = p->prefixlen; + if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY)) SET_FLAG (req.ifa.ifa_flags, IFA_F_SECONDARY); diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 1b8ded7e..4fadc7e9 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -163,7 +163,7 @@ kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family) (union sockunion *)mask, gate ? (union sockunion *)&sin_gate : NULL, ifindex, - rib->flags, + rib->flags | (rib->zflags << 8), rib->metric); if (IS_ZEBRA_DEBUG_RIB) @@ -286,7 +286,8 @@ sin6_masklen (struct in6_addr mask) return len; } -/* Interface between zebra message and rtm message. */ +/* Interface between zebra message and rtm message. + * only called by kernel_delete_ipv6_old by rib_bogus_ipv6 */ static int kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest, struct in6_addr *gate, int index, int flags) @@ -453,7 +454,7 @@ kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib, (union sockunion *) mask, gate ? (union sockunion *)&sin_gate : NULL, ifindex, - rib->flags, + rib->flags | (rib->zflags << 8), rib->metric); #if 0 diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 8cc3c4cb..e8c223f2 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -233,6 +233,32 @@ rtadv_send_packet (int sock, struct interface *ifp) len += sizeof(struct nd_opt_homeagent_info); } + if (zif->rtadv.AdvRDNSSFlag) + { + char *addr_ptr; + struct nd_opt_rdnss *ndopt_rdnss; + struct prefix *rdnss_prefix; + unsigned int rdnss_entries = 1; + + ndopt_rdnss = (struct nd_opt_rdnss *) (buf + len); + ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS; + ndopt_rdnss->nd_opt_rdnss_reserved = 0; + ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(zif->rtadv.AdvRDNSSLifetime); + + len += sizeof(struct nd_opt_rdnss); + + /* Fill in all RDNS server entries */ + for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvRDNSSList, node, rdnss_prefix)) + { + addr_ptr = (char *)(buf + len); + memcpy(addr_ptr, &rdnss_prefix->u.prefix6, sizeof (struct in6_addr)); + len += sizeof (struct in6_addr); + rdnss_entries += 2; + } + + ndopt_rdnss->nd_opt_rdnss_len = rdnss_entries; + } + if (zif->rtadv.AdvIntervalOption) { struct nd_opt_adv_interval *ndopt_adv = @@ -1430,6 +1456,115 @@ DEFUN (no_ipv6_nd_router_preference, return CMD_SUCCESS; } +static struct prefix * +rtadv_rdnss_lookup (struct list *list, struct prefix *p) +{ + struct listnode *node; + struct prefix *prefix; + + for (ALL_LIST_ELEMENTS_RO (list, node, prefix)) + if (prefix_same (prefix, p)) + return prefix; + return NULL; +} + +static void +rtadv_rdnss_set (struct zebra_if *zif, struct prefix *p) +{ + struct prefix *prefix; + struct list *rdnsslist = zif->rtadv.AdvRDNSSList; + + prefix = rtadv_rdnss_lookup (rdnsslist, p); + if (prefix) + return; + + prefix = prefix_new (); + memcpy (prefix, p, sizeof (struct prefix)); + listnode_add (rdnsslist, prefix); + + return; +} + +static int +rtadv_rdnss_reset (struct zebra_if *zif, struct prefix *rp) +{ + struct prefix *prefix; + + prefix = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rp); + if (prefix != NULL) + { + listnode_delete (zif->rtadv.AdvRDNSSList, (void *) prefix); + prefix_free (prefix); + return 1; + } + else + return 0; +} + +DEFUN (ipv6_nd_rdnss, + ipv6_nd_rdnss_cmd, + "ipv6 nd rdnss X:X::X:X (<0-4294967295>|infinite)", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "RDNSS Option\n" + "IPv6 address of recursive DNS server\n") +{ + int ret; + char *pnt; + struct interface *ifp; + struct zebra_if *zif; + struct prefix rp; + + ifp = (struct interface *) vty->index; + zif = ifp->info; + + /* make sure no slash exists in the argument */ + pnt = strchr (argv[0], '/'); + if (pnt != NULL) + { + vty_out (vty, "Malformed IPv6 RDNS address - no prefix notation allowed%s", + VTY_NEWLINE); + return CMD_WARNING; + } + + /* now we can abuse str2prefix_ipv6 for a sanity check + * because IPv6 addresses with missing prefix + * slashes '/' are treated as host routes */ + ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &rp); + if (!ret) + { + vty_out (vty, "Malformed IPv6 RDNS address%s", VTY_NEWLINE); + return CMD_WARNING; + } + + rtadv_rdnss_set(zif, &rp); + zif->rtadv.AdvRDNSSFlag = 1; + + if (argc > 1) + { + if ( strncmp (argv[1], "i", 1) == 0) + { + zif->rtadv.AdvRDNSSLifetime = RTADV_RDNSS_INFINITY_LIFETIME; + } + else + { + zif->rtadv.AdvRDNSSLifetime = + (u_int32_t) strtoll (argv[1], (char **)NULL, 10); + } + } + + return CMD_SUCCESS; +} + +ALIAS (ipv6_nd_rdnss, + ipv6_nd_rdnss_nolife_cmd, + "ipv6 nd rdnss X:X::X:X", + "Interface IPv6 config commands\n" + "Neighbor discovery\n" + "RDNSS Option\n" + "IPv6 address of recursive DNS server\n") + + /* Write configuration about router advertisement. */ void rtadv_config_write (struct vty *vty, struct interface *ifp) @@ -1605,6 +1740,8 @@ rtadv_init (void) 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, &ipv6_nd_rdnss_cmd); + install_element (INTERFACE_NODE, &ipv6_nd_rdnss_nolife_cmd); } static int diff --git a/zebra/rtadv.h b/zebra/rtadv.h index d8d263d0..6bd342e3 100644 --- a/zebra/rtadv.h +++ b/zebra/rtadv.h @@ -66,6 +66,9 @@ extern void rtadv_init (void); #ifndef ND_OPT_HA_INFORMATION #define ND_OPT_HA_INFORMATION 8 /* HA Information Option */ #endif +#ifndef ND_OPT_RDNSS +#define ND_OPT_RDNSS 25 /* RDNSS option (RFC 5006) */ +#endif #ifndef HAVE_STRUCT_ND_OPT_ADV_INTERVAL struct nd_opt_adv_interval { /* Advertisement interval option */ @@ -94,6 +97,17 @@ struct nd_opt_homeagent_info { /* Home Agent info */ } __attribute__((__packed__)); #endif +#ifndef HAVE_STRUCT_ND_OPT_RDNSS +/* see RFC 5006, section 5.1 */ +struct nd_opt_rdnss { + uint8_t nd_opt_rdnss_type; + uint8_t nd_opt_rdnss_len; + uint16_t nd_opt_rdnss_reserved; + uint32_t nd_opt_rdnss_lifetime; + /* followed by n (16 byte) entries */ +} __attribute__((__packed__)); +#endif + extern const char *rtadv_pref_strs[]; #endif /* _ZEBRA_RTADV_H */ diff --git a/zebra/test_main.c b/zebra/test_main.c index 70a1a3a6..4e1002e8 100644 --- a/zebra/test_main.c +++ b/zebra/test_main.c @@ -29,6 +29,7 @@ #include "log.h" #include "privs.h" #include "sigevent.h" +#include "paths.h" #include "zebra/rib.h" #include "zebra/zserv.h" @@ -73,10 +74,13 @@ zebra_capabilities_t _caps_p [] = }; /* Default configuration file path. */ -char config_default[] = SYSCONFDIR DEFAULT_CONFIG_FILE; +char config_default[MAXPATHLEN]; + +/* pid_file default value */ +static char pid_file_default[MAXPATHLEN]; /* Process ID saved for use by init system */ -const char *pid_file = PATH_ZEBRA_PID; +const char *pid_file = pid_file_default; /* Help information display. */ static void @@ -276,6 +280,9 @@ main (int argc, char **argv) usage (progname, 1); } + strcpy (config_default, path_config (ZEBRA_CONFIG_NAME)); + strcpy (pid_file_default, path_state (ZEBRA_PID_NAME)); + /* Make master thread emulator. */ zebrad.master = thread_master_create (); diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 12f3fa5a..a10ca84b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -67,6 +67,7 @@ static const struct {ZEBRA_ROUTE_OSPF6, 110}, {ZEBRA_ROUTE_ISIS, 115}, {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} + /* no entry/default: 150 */ }; /* Vector for routing table. */ @@ -298,7 +299,6 @@ nexthop_blackhole_add (struct rib *rib) nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; - SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); nexthop_add (rib, nexthop); @@ -352,6 +352,17 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, break; } + if (IS_ZEBRA_DEBUG_RIB) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug("%s: %s/%d: nexthop match %p: %s type=%d sel=%d int=%d", + __func__, buf, rn->p.prefixlen, match, + match ? zebra_route_string(match->type) : "<?>", + match ? match->type : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED) : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_INTERNAL) : -1); + } + /* If there is no selected route or matched route is EGP, go up tree. */ if (! match @@ -365,7 +376,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } else { - if (match->type == ZEBRA_ROUTE_CONNECT) + if (match->type == ZEBRA_ROUTE_CONNECT + || (match->nexthop && match->nexthop->type == NEXTHOP_TYPE_IFINDEX)) { /* Directly point connected route. */ newhop = match->nexthop; @@ -374,7 +386,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 1; } - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || + match->type == ZEBRA_ROUTE_KERNEL) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) @@ -755,6 +768,43 @@ rib_match_ipv6 (struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +static void nexthop_dump(struct nexthop *nexthop, + char *type_str_buf, + int type_str_buf_size, + char *addr_str_buf, + int addr_str_buf_size, + char *via_str_buf, + int via_str_buf_size) +{ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "ipv4"); + snprintf(addr_str_buf, addr_str_buf_size, "%s", inet_ntoa(nexthop->gate.ipv4)); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifindex ? ifindex2ifname(nexthop->ifindex) : "<?>"); + break; + case NEXTHOP_TYPE_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, "<connected>"); + snprintf(via_str_buf, via_str_buf_size, "%s", ifindex2ifname(nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, "<connected>"); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + snprintf(type_str_buf, type_str_buf_size, "blackhole"); + snprintf(addr_str_buf, addr_str_buf_size, "<blackhole>"); + snprintf(via_str_buf, via_str_buf_size, "Null0"); + break; + default: + snprintf(type_str_buf, type_str_buf_size, "unknown"); + snprintf(addr_str_buf, addr_str_buf_size, "<unknown>"); + snprintf(via_str_buf, via_str_buf_size, "<?>"); + } +} + #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -808,10 +858,27 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active_ipv4 (rib, nexthop, set, rn)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + { + int nh_active = nexthop_active_ipv4 (rib, nexthop, set, rn); + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d nexthop_active_ipv4=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + nh_active); + } + if (nh_active) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: @@ -891,8 +958,23 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) + new_active = nexthop_active_check (rn, rib, nexthop, set); + if (new_active) rib->nexthop_active_num++; + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d act=%d total_act=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + new_active, rib->nexthop_active_num); + } if (prev_active != new_active || prev_index != nexthop->ifindex) SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); @@ -992,6 +1074,15 @@ rib_process (struct route_node *rn) * may be passed to rib_unlink() in the middle of iteration. */ next = rib->next; + + if (IS_ZEBRA_DEBUG_RIB) { + zlog_debug("%s: %s/%d: scan rib %p: type=%d sel=%d rem=%d nh_act=%d dist=%d", + __func__, buf, rn->p.prefixlen, rib, rib->type, + CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED), + CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED), + nexthop_active_update(rn, rib, 0), + rib->distance); + } /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) @@ -1332,7 +1423,6 @@ rib_queue_init (struct zebra_t *zebra) zebra->ribq->spec.errorfunc = NULL; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; - zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new ())) zlog_err ("%s: could not initialise meta queue!", __func__); @@ -1511,7 +1601,10 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Set default distance by route type. */ if (distance == 0) { - distance = route_info[type].distance; + if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) + distance = 150; + else + distance = route_info[type].distance; /* iBGP distance is 200. */ if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) @@ -1551,13 +1644,16 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, rib->type = type; rib->distance = distance; rib->flags = flags; + rib->zflags = flags >> 8; rib->metric = metric; rib->table = vrf_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ - if (gate) + if (RIB_ZF_BLACKHOLE_FLAGS (rib->zflags)) + nexthop_blackhole_add (rib); + else if (gate) { if (ifindex) nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); @@ -1830,6 +1926,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; + unsigned discard = RIB_ZF_BLACKHOLE_FLAGS (flags >> 8); /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); @@ -1839,12 +1936,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Apply mask. */ apply_mask_ipv4 (p); - if (IS_ZEBRA_DEBUG_KERNEL && gate) - zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, - inet_ntoa (*gate), - ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + if (gate) + zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntoa (*gate), + ifindex); + else + zlog_debug ("rib_delete_ipv4(): route delete %s/%d ifname %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex2ifname(ifindex), + ifindex); /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); @@ -1878,11 +1982,37 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (rib->type != type) continue; - if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + + if (rib->zflags == discard) { - if (rib->refcnt) + same = rib; + break; + } + if (gate) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || + IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)) + /* make sure ifindex matches if specified */ + if (!ifindex || ifindex == nexthop->ifindex) + break; + + if (nexthop) { + same = rib; + break; + } + } + else + { + nexthop = rib->nexthop; + if (nexthop && nexthop->ifindex != ifindex) + continue; + if (nexthop && + rib->type == ZEBRA_ROUTE_CONNECT && + nexthop->type == NEXTHOP_TYPE_IFINDEX && + rib->refcnt) + { /* Duplicated connected route. */ rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); @@ -1891,15 +2021,6 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, same = rib; break; } - /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || - IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) - { - same = rib; - break; - } } /* If same type of route can't be found and this message is from @@ -2011,7 +2132,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) } /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; + rib->zflags = si->zflags; /* Link this rib to the tree. */ rib_addnode (rn, rib); @@ -2099,7 +2220,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Add static route into static route configuration. */ int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id) + unsigned zflags, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2118,12 +2239,14 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, rn = route_node_get (stable, p); /* Make flags. */ - if (gate) + if (RIB_ZF_BLACKHOLE_FLAGS (zflags)) + type = STATIC_IPV4_BLACKHOLE; + else if (gate) type = STATIC_IPV4_GATEWAY; else if (ifname) type = STATIC_IPV4_IFNAME; else - type = STATIC_IPV4_BLACKHOLE; + return -1; /* Do nothing if there is a same static route. */ for (si = rn->info; si; si = si->next) @@ -2151,7 +2274,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, si->type = type; si->distance = distance; - si->flags = flags; + si->zflags = zflags; if (gate) si->gate.ipv4 = *gate; @@ -2340,6 +2463,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, rib->type = type; rib->distance = distance; rib->flags = flags; + rib->zflags = flags >> 8; rib->metric = metric; rib->table = vrf_id; rib->nexthop_num = 0; @@ -2385,6 +2509,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; + unsigned discard = RIB_ZF_BLACKHOLE_FLAGS (flags >> 8); /* Apply mask. */ apply_mask_ipv6 (p); @@ -2426,11 +2551,37 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (rib->type != type) continue; - if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + + if (rib->zflags == discard) + { + same = rib; + break; + } + if (gate) { - if (rib->refcnt) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || + IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)) + /* make sure ifindex matches if specified */ + if (!ifindex || ifindex == nexthop->ifindex) + break; + + if (nexthop) { + same = rib; + break; + } + } + else + { + nexthop = rib->nexthop; + if (nexthop && nexthop->ifindex != ifindex) + continue; + if (nexthop && + rib->type == ZEBRA_ROUTE_CONNECT && + nexthop->type == NEXTHOP_TYPE_IFINDEX && + rib->refcnt) + { /* Duplicated connected route. */ rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); @@ -2439,15 +2590,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, same = rib; break; } - /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || - IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) - { - same = rib; - break; - } + } /* If same type of route can't be found and this message is from @@ -2533,6 +2676,9 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; } rib_queue_add (&zebrad, rn); } @@ -2557,10 +2703,13 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; } /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; + rib->zflags = si->zflags; /* Link this rib to the tree. */ rib_addnode (rn, rib); @@ -2583,6 +2732,9 @@ static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) && strcmp (nexthop->ifname, si->ifname) == 0) return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV6_BLACKHOLE) + return 1; return 0; } @@ -2651,7 +2803,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, unsigned zflags, u_char distance, u_int32_t vrf_id) { struct route_node *rn; @@ -2694,7 +2846,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->type = type; si->distance = distance; - si->flags = flags; + si->zflags = zflags; switch (type) { @@ -2708,6 +2860,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->ipv6 = *gate; si->ifname = XSTRDUP (0, ifname); break; + case STATIC_IPV6_BLACKHOLE: + break; } /* Add new static route information to the tree with sort by @@ -2791,23 +2945,45 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, #endif /* HAVE_IPV6 */ /* RIB update function. */ -void -rib_update (void) +static void +rib_update_table (struct table *table) { struct route_node *rn; - struct route_table *table; - - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info) rib_queue_add (&zebrad, rn); +} - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); - if (table) - for (rn = route_top (table); rn; rn = route_next (rn)) - if (rn->info) - rib_queue_add (&zebrad, rn); +void +rib_update (void) +{ + if (zebrad.update) + { + thread_cancel (zebrad.update); + zebrad.update = NULL; + } + + rib_update_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + +#ifdef HAVE_IPV6 + rib_update_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +#endif +} + +static int +rib_update_thread (struct thread *self) +{ + rib_update (); + return 0; +} + +void +rib_update_background (void) +{ + if (!zebrad.update) + zebrad.update = thread_add_background (zebrad.master, rib_update_thread, + NULL, rib_process_hold_time); } diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ecb5d10a..db56a335 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -30,6 +30,50 @@ #include "zebra/zserv.h" +/* small helper for blackhole routes */ +static const struct message blackhole_str[] = { + {RIB_ZF_REJECT, "reject"}, + {RIB_ZF_PROHIBIT, "prohibit"}, + {RIB_ZF_BLACKHOLE, "blackhole"}, + {0, NULL} +}; + +#define BLACKHOLE_NAME(type) \ + lookup (blackhole_str, RIB_ZF_BLACKHOLE_FLAGS(type)) + +#define BLACKHOLE_CMD "(reject|prohibit|blackhole)" +#define BLACKHOLE_STR \ + "Emit ICMP unreachable when matched\n" \ + "Emit ICMP prohibited when matched\n" \ + "Silently discard packets\n" + +static unsigned +zebra_static_parse_flags (const char *gate_str, const char *flag_str) +{ + unsigned zflags = 0; + + /* Null0 static route. */ + if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) + zflags = RIB_ZF_BLACKHOLE; + + /* Route flags. override RIB_ZF_BLACKHOLE from above if given. */ + if (flag_str) { + switch (tolower (flag_str[0])) { + case 'r': + zflags = RIB_ZF_REJECT; + break; + case 'p': + zflags = RIB_ZF_PROHIBIT; + break; + case 'b': + zflags = RIB_ZF_BLACKHOLE; + break; + /* syntax checking happens in vty code */ + } + } + return zflags; +} + /* General fucntion for static route. */ static int zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, @@ -42,7 +86,7 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, struct in_addr gate; struct in_addr mask; const char *ifname; - u_char flag = 0; + unsigned zflags; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -72,42 +116,13 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; - /* Null0 static route. */ - if ((gate_str != NULL) && (strncasecmp (gate_str, "Null0", strlen (gate_str)) == 0)) - { - if (flag_str) - { - vty_out (vty, "%% can not have flag %s with Null0%s", flag_str, VTY_NEWLINE); - return CMD_WARNING; - } - if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, ZEBRA_FLAG_BLACKHOLE, distance, 0); - else - static_delete_ipv4 (&p, NULL, NULL, distance, 0); - return CMD_SUCCESS; - } - - /* Route flags */ - if (flag_str) { - switch(flag_str[0]) { - case 'r': - case 'R': /* XXX */ - SET_FLAG (flag, ZEBRA_FLAG_REJECT); - break; - case 'b': - case 'B': /* XXX */ - SET_FLAG (flag, ZEBRA_FLAG_BLACKHOLE); - break; - default: - vty_out (vty, "%% Malformed flag %s %s", flag_str, VTY_NEWLINE); - return CMD_WARNING; - } - } + zflags = zebra_static_parse_flags (gate_str, flag_str); - if (gate_str == NULL) + /* blackhole with nexthop makes no sense, don't add nexthop */ + if (gate_str == NULL || RIB_ZF_BLACKHOLE_FLAGS (zflags)) { if (add_cmd) - static_add_ipv4 (&p, NULL, NULL, flag, distance, 0); + static_add_ipv4 (&p, NULL, NULL, zflags, distance, 0); else static_delete_ipv4 (&p, NULL, NULL, distance, 0); @@ -123,7 +138,7 @@ zebra_static_ipv4 (struct vty *vty, int add_cmd, const char *dest_str, ifname = gate_str; if (add_cmd) - static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, flag, distance, 0); + static_add_ipv4 (&p, ifname ? NULL : &gate, ifname, 0, distance, 0); else static_delete_ipv4 (&p, ifname ? NULL : &gate, ifname, distance, 0); @@ -146,26 +161,25 @@ DEFUN (ip_route, DEFUN (ip_route_flags, ip_route_flags_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD, IP_STR "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") + "Null interface\n" + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], NULL); } DEFUN (ip_route_flags2, ip_route_flags2_cmd, - "ip route A.B.C.D/M (reject|blackhole)", + "ip route A.B.C.D/M " BLACKHOLE_CMD, IP_STR "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") + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], NULL); } @@ -187,28 +201,27 @@ DEFUN (ip_route_mask, DEFUN (ip_route_mask_flags, ip_route_mask_flags_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD, IP_STR "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") + "Null interface\n" + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL); } DEFUN (ip_route_mask_flags2, ip_route_mask_flags2_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole)", + "ip route A.B.C.D A.B.C.D " BLACKHOLE_CMD, IP_STR "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") + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); } @@ -230,14 +243,14 @@ DEFUN (ip_route_distance, DEFUN (ip_route_flags_distance, ip_route_flags_distance_cmd, - "ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + "ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD " <1-255>", IP_STR "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" + "Null interface\n" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], NULL, argv[1], argv[2], argv[3]); @@ -245,12 +258,11 @@ DEFUN (ip_route_flags_distance, DEFUN (ip_route_flags_distance2, ip_route_flags_distance2_cmd, - "ip route A.B.C.D/M (reject|blackhole) <1-255>", + "ip route A.B.C.D/M " BLACKHOLE_CMD " <1-255>", IP_STR "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" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], NULL, NULL, argv[1], argv[2]); @@ -273,30 +285,29 @@ DEFUN (ip_route_mask_distance, DEFUN (ip_route_mask_flags_distance, ip_route_mask_flags_distance_cmd, - "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + "ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD " <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" "IP gateway address\n" "IP gateway interface name\n" - "Distance value for this route\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n") + "Null interface\n" + BLACKHOLE_STR + "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); } DEFUN (ip_route_mask_flags_distance2, ip_route_mask_flags_distance2_cmd, - "ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", + "ip route A.B.C.D A.B.C.D " BLACKHOLE_CMD " <1-255>", IP_STR "Establish static routes\n" "IP destination prefix\n" "IP destination prefix mask\n" - "Distance value for this route\n" - "Emit an ICMP unreachable when matched\n" - "Silently discard pkts when matched\n") + BLACKHOLE_STR + "Distance value for this route\n") { return zebra_static_ipv4 (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); } @@ -317,25 +328,24 @@ DEFUN (no_ip_route, ALIAS (no_ip_route, no_ip_route_flags_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole)", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD, NO_STR IP_STR "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") + "Null interface\n" + BLACKHOLE_STR) DEFUN (no_ip_route_flags2, no_ip_route_flags2_cmd, - "no ip route A.B.C.D/M (reject|blackhole)", + "no ip route A.B.C.D/M " BLACKHOLE_CMD, NO_STR IP_STR "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") + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, NULL, NULL); } @@ -357,7 +367,7 @@ DEFUN (no_ip_route_mask, ALIAS (no_ip_route_mask, no_ip_route_mask_flags_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole)", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD, NO_STR IP_STR "Establish static routes\n" @@ -365,19 +375,18 @@ ALIAS (no_ip_route_mask, "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") + "Null interface\n" + BLACKHOLE_STR) DEFUN (no_ip_route_mask_flags2, no_ip_route_mask_flags2_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole)", + "no ip route A.B.C.D A.B.C.D " BLACKHOLE_CMD, NO_STR IP_STR "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") + BLACKHOLE_STR) { return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, NULL, NULL); } @@ -399,15 +408,15 @@ DEFUN (no_ip_route_distance, DEFUN (no_ip_route_flags_distance, no_ip_route_flags_distance_cmd, - "no ip route A.B.C.D/M (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + "no ip route A.B.C.D/M (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD " <1-255>", NO_STR IP_STR "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" + "Null interface\n" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], NULL, argv[1], argv[2], argv[3]); @@ -415,13 +424,12 @@ DEFUN (no_ip_route_flags_distance, DEFUN (no_ip_route_flags_distance2, no_ip_route_flags_distance2_cmd, - "no ip route A.B.C.D/M (reject|blackhole) <1-255>", + "no ip route A.B.C.D/M " BLACKHOLE_CMD " <1-255>", NO_STR IP_STR "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" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], NULL, NULL, argv[1], argv[2]); @@ -445,7 +453,7 @@ DEFUN (no_ip_route_mask_distance, DEFUN (no_ip_route_mask_flags_distance, no_ip_route_mask_flags_distance_cmd, - "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE) (reject|blackhole) <1-255>", + "no ip route A.B.C.D A.B.C.D (A.B.C.D|INTERFACE|null0) " BLACKHOLE_CMD " <1-255>", NO_STR IP_STR "Establish static routes\n" @@ -453,8 +461,8 @@ DEFUN (no_ip_route_mask_flags_distance, "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" + "Null interface\n" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); @@ -462,14 +470,13 @@ DEFUN (no_ip_route_mask_flags_distance, DEFUN (no_ip_route_mask_flags_distance2, no_ip_route_mask_flags_distance2_cmd, - "no ip route A.B.C.D A.B.C.D (reject|blackhole) <1-255>", + "no ip route A.B.C.D A.B.C.D " BLACKHOLE_CMD " <1-255>", NO_STR IP_STR "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" + BLACKHOLE_STR "Distance value for this route\n") { return zebra_static_ipv4 (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]); @@ -546,10 +553,6 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) vty_out (vty, ", best"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", blackhole"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", reject"); vty_out (vty, "%s", VTY_NEWLINE); #define ONE_DAY_SECOND 60*60*24 @@ -603,10 +606,10 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn) case NEXTHOP_TYPE_IFNAME: vty_out (vty, " directly connected, %s", nexthop->ifname); break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out (vty, " directly connected, Null0"); - break; - default: + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " Null0, %s", BLACKHOLE_NAME (rib->zflags)); + break; + default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -713,10 +716,10 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) case NEXTHOP_TYPE_IFNAME: vty_out (vty, " is directly connected, %s", nexthop->ifname); break; - case NEXTHOP_TYPE_BLACKHOLE: - vty_out (vty, " is directly connected, Null0"); - break; - default: + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " Null0, %s", BLACKHOLE_NAME (rib->zflags)); + break; + default: break; } if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -767,11 +770,6 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) break; } - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", bh"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", rej"); - if (rib->type == ZEBRA_ROUTE_RIP || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_ISIS @@ -802,10 +800,6 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) } } -#define SHOW_ROUTE_V4_HEADER "Codes: K - kernel route, C - connected, " \ - "S - static, R - RIP, O - OSPF,%s I - ISIS, B - BGP, " \ - "> - selected route, * - FIB route%s%s" - DEFUN (show_ip_route, show_ip_route_cmd, "show ip route", @@ -828,8 +822,7 @@ DEFUN (show_ip_route, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, VTY_NEWLINE, - VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -871,8 +864,7 @@ DEFUN (show_ip_route_prefix_longer, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -910,8 +902,7 @@ DEFUN (show_ip_route_supernets, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, VTY_NEWLINE, - VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -922,17 +913,11 @@ DEFUN (show_ip_route_supernets, DEFUN (show_ip_route_protocol, show_ip_route_protocol_cmd, - "show ip route (bgp|connected|isis|kernel|ospf|rip|static)", + "show ip route " QUAGGA_IP_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - "Border Gateway Protocol (BGP)\n" - "Connected\n" - "ISO IS-IS (ISIS)\n" - "Kernel\n" - "Open Shortest Path First (OSPF)\n" - "Routing Information Protocol (RIP)\n" - "Static routes\n") + QUAGGA_IP_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -940,21 +925,8 @@ DEFUN (show_ip_route_protocol, struct rib *rib; int first = 1; - if (strncmp (argv[0], "b", 1) == 0) - type = ZEBRA_ROUTE_BGP; - else if (strncmp (argv[0], "c", 1) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "k", 1) ==0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "o", 1) == 0) - type = ZEBRA_ROUTE_OSPF; - else if (strncmp (argv[0], "i", 1) == 0) - type = ZEBRA_ROUTE_ISIS; - else if (strncmp (argv[0], "r", 1) == 0) - type = ZEBRA_ROUTE_RIP; - else if (strncmp (argv[0], "s", 1) == 0) - type = ZEBRA_ROUTE_STATIC; - else + type = proto_redistnum (AFI_IP, argv[0]); + if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -971,8 +943,7 @@ DEFUN (show_ip_route_protocol, { if (first) { - vty_out (vty, SHOW_ROUTE_V4_HEADER, - VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } vty_show_ip_route (vty, rn, rib); @@ -1168,19 +1139,9 @@ static_config_ipv4 (struct vty *vty) case STATIC_IPV4_IFNAME: vty_out (vty, " %s", si->gate.ifname); break; - case STATIC_IPV4_BLACKHOLE: - vty_out (vty, " Null0"); - break; - } - - /* flags are incompatible with STATIC_IPV4_BLACKHOLE */ - if (si->type != STATIC_IPV4_BLACKHOLE) - { - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, " %s", "reject"); - - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, " %s", "blackhole"); + case STATIC_IPV4_BLACKHOLE: + vty_out (vty, " Null0 %s", BLACKHOLE_NAME (si->zflags)); + break; } if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) @@ -1237,7 +1198,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, struct in6_addr gate_addr; u_char type = 0; int table = 0; - u_char flag = 0; + unsigned zflags; ret = str2prefix (dest_str, &p); if (ret <= 0) @@ -1249,22 +1210,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, /* Apply mask for given prefix. */ apply_mask (&p); - /* Route flags */ - if (flag_str) { - switch(flag_str[0]) { - case 'r': - case 'R': /* XXX */ - SET_FLAG (flag, ZEBRA_FLAG_REJECT); - break; - case 'b': - case 'B': /* XXX */ - SET_FLAG (flag, ZEBRA_FLAG_BLACKHOLE); - break; - default: - vty_out (vty, "%% Malformed flag %s %s", flag_str, VTY_NEWLINE); - return CMD_WARNING; - } - } + zflags = zebra_static_parse_flags (gate_str, flag_str); /* Administrative distance. */ if (distance_str) @@ -1272,6 +1218,17 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, else distance = ZEBRA_STATIC_DISTANCE_DEFAULT; + /* blackhole routes don't have nexthops */ + if (RIB_ZF_BLACKHOLE_FLAGS (zflags)) + { + type = STATIC_IPV6_BLACKHOLE; + if (add_cmd) + static_add_ipv6 (&p, type, NULL, NULL, zflags, distance, table); + else + static_delete_ipv6 (&p, type, NULL, NULL, distance, table); + return CMD_SUCCESS; + } + /* When gateway is valid IPv6 addrees, then gate is treated as nexthop address other case gate is treated as interface name. */ ret = inet_pton (AF_INET6, gate_str, &gate_addr); @@ -1303,7 +1260,7 @@ static_ipv6_func (struct vty *vty, int add_cmd, const char *dest_str, } if (add_cmd) - static_add_ipv6 (&p, type, gate, ifname, flag, distance, table); + static_add_ipv6 (&p, type, gate, ifname, zflags, distance, table); else static_delete_ipv6 (&p, type, gate, ifname, distance, table); @@ -1322,20 +1279,6 @@ DEFUN (ipv6_route, return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, NULL); } -DEFUN (ipv6_route_flags, - ipv6_route_flags_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", - IP_STR - "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") -{ - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); -} - DEFUN (ipv6_route_ifname, ipv6_route_ifname_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE", @@ -1348,20 +1291,6 @@ DEFUN (ipv6_route_ifname, return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, NULL); } -DEFUN (ipv6_route_ifname_flags, - ipv6_route_ifname_flags_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", - IP_STR - "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") -{ - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], NULL); -} - DEFUN (ipv6_route_pref, ipv6_route_pref_cmd, "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", @@ -1375,21 +1304,6 @@ DEFUN (ipv6_route_pref, return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, NULL, argv[2]); } -DEFUN (ipv6_route_flags_pref, - ipv6_route_flags_pref_cmd, - "ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", - IP_STR - "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") -{ - return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); -} - DEFUN (ipv6_route_ifname_pref, ipv6_route_ifname_pref_cmd, "ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", @@ -1403,21 +1317,6 @@ DEFUN (ipv6_route_ifname_pref, return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], NULL, argv[3]); } -DEFUN (ipv6_route_ifname_flags_pref, - ipv6_route_ifname_flags_pref_cmd, - "ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", - IP_STR - "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") -{ - return static_ipv6_func (vty, 1, argv[0], argv[1], argv[2], argv[3], argv[4]); -} - DEFUN (no_ipv6_route, no_ipv6_route_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE)", @@ -1431,18 +1330,6 @@ DEFUN (no_ipv6_route, return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, NULL); } -ALIAS (no_ipv6_route, - no_ipv6_route_flags_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole)", - NO_STR - IP_STR - "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") - DEFUN (no_ipv6_route_ifname, no_ipv6_route_ifname_cmd, "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE", @@ -1456,18 +1343,6 @@ DEFUN (no_ipv6_route_ifname, return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, NULL); } -ALIAS (no_ipv6_route_ifname, - no_ipv6_route_ifname_flags_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole)", - NO_STR - IP_STR - "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") - DEFUN (no_ipv6_route_pref, no_ipv6_route_pref_cmd, "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) <1-255>", @@ -1482,53 +1357,70 @@ DEFUN (no_ipv6_route_pref, return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, NULL, argv[2]); } -DEFUN (no_ipv6_route_flags_pref, - no_ipv6_route_flags_pref_cmd, - "no ipv6 route X:X::X:X/M (X:X::X:X|INTERFACE) (reject|blackhole) <1-255>", +DEFUN (no_ipv6_route_ifname_pref, + no_ipv6_route_ifname_pref_cmd, + "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", NO_STR IP_STR "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") { - /* We do not care about argv[2] */ - return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], argv[3]); + return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]); } -DEFUN (no_ipv6_route_ifname_pref, - no_ipv6_route_ifname_pref_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE <1-255>", - NO_STR +DEFUN (ipv6_route_blackhole, + ipv6_route_blackhole_cmd, + "ipv6 route X:X::X:X/M Null0 " BLACKHOLE_CMD, IP_STR "Establish static routes\n" "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" - "IPv6 gateway address\n" - "IPv6 gateway interface name\n" + "Specify blackhole route\n" + BLACKHOLE_STR) +{ + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], NULL); +} + +DEFUN (ipv6_route_blackhole_pref, + ipv6_route_blackhole_pref_cmd, + "ipv6 route X:X::X:X/M Null0 " BLACKHOLE_CMD " <1-255>", + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "Specify blackhole route\n" + BLACKHOLE_STR "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], NULL, argv[3]); + return static_ipv6_func (vty, 1, argv[0], argv[1], NULL, argv[2], argv[3]); } -DEFUN (no_ipv6_route_ifname_flags_pref, - no_ipv6_route_ifname_flags_pref_cmd, - "no ipv6 route X:X::X:X/M X:X::X:X INTERFACE (reject|blackhole) <1-255>", +DEFUN (no_ipv6_route_blackhole_pref, + no_ipv6_route_blackhole_pref_cmd, + "no ipv6 route X:X::X:X/M Null0 " BLACKHOLE_CMD " <1-255>", NO_STR IP_STR "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" + "Specify blackhole route\n" + BLACKHOLE_STR "Distance value for this prefix\n") { - return static_ipv6_func (vty, 0, argv[0], argv[1], argv[2], argv[3], argv[4]); + const char *dist = argc > 3 ? argv[3] : NULL; + return static_ipv6_func (vty, 0, argv[0], argv[1], NULL, argv[2], dist); } +ALIAS (no_ipv6_route_blackhole_pref, + no_ipv6_route_blackhole_cmd, + "no ipv6 route X:X::X:X/M Null0 " BLACKHOLE_CMD, + NO_STR + IP_STR + "Establish static routes\n" + "IPv6 destination prefix (e.g. 3ffe:506::/32)\n" + "Specify blackhole route\n" + BLACKHOLE_STR) + /* New RIB. Detailed information for IPv6 route. */ static void vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) @@ -1549,10 +1441,6 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn) vty_out (vty, ", best"); if (rib->refcnt) vty_out (vty, ", refcnt %ld", rib->refcnt); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", blackhole"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", reject"); vty_out (vty, "%s", VTY_NEWLINE); #define ONE_DAY_SECOND 60*60*24 @@ -1700,6 +1588,9 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, vty_out (vty, " is directly connected, %s", nexthop->ifname); break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out (vty, " Null0, %s", BLACKHOLE_NAME (rib->zflags)); + break; default: break; } @@ -1731,11 +1622,6 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, } } - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, ", bh"); - if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, ", rej"); - if (rib->type == ZEBRA_ROUTE_RIPNG || rib->type == ZEBRA_ROUTE_OSPF6 || rib->type == ZEBRA_ROUTE_ISIS @@ -1766,8 +1652,6 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn, } } -#define SHOW_ROUTE_V6_HEADER "Codes: K - kernel route, C - connected, S - static, R - RIPng, O - OSPFv3,%s I - ISIS, B - BGP, * - FIB route.%s%s" - DEFUN (show_ipv6_route, show_ipv6_route_cmd, "show ipv6 route", @@ -1790,7 +1674,7 @@ DEFUN (show_ipv6_route, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -1832,7 +1716,7 @@ DEFUN (show_ipv6_route_prefix_longer, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -1842,17 +1726,11 @@ DEFUN (show_ipv6_route_prefix_longer, DEFUN (show_ipv6_route_protocol, show_ipv6_route_protocol_cmd, - "show ipv6 route (bgp|connected|isis|kernel|ospf6|ripng|static)", + "show ipv6 route " QUAGGA_IP6_REDIST_STR_ZEBRA, SHOW_STR IP_STR "IP routing table\n" - "Border Gateway Protocol (BGP)\n" - "Connected\n" - "ISO IS-IS (ISIS)\n" - "Kernel\n" - "Open Shortest Path First (OSPFv3)\n" - "Routing Information Protocol (RIPng)\n" - "Static routes\n") + QUAGGA_IP6_REDIST_HELP_STR_ZEBRA) { int type; struct route_table *table; @@ -1860,21 +1738,8 @@ DEFUN (show_ipv6_route_protocol, struct rib *rib; int first = 1; - if (strncmp (argv[0], "b", 1) == 0) - type = ZEBRA_ROUTE_BGP; - else if (strncmp (argv[0], "c", 1) == 0) - type = ZEBRA_ROUTE_CONNECT; - else if (strncmp (argv[0], "k", 1) ==0) - type = ZEBRA_ROUTE_KERNEL; - else if (strncmp (argv[0], "o", 1) == 0) - type = ZEBRA_ROUTE_OSPF6; - else if (strncmp (argv[0], "i", 1) == 0) - type = ZEBRA_ROUTE_ISIS; - else if (strncmp (argv[0], "r", 1) == 0) - type = ZEBRA_ROUTE_RIPNG; - else if (strncmp (argv[0], "s", 1) == 0) - type = ZEBRA_ROUTE_STATIC; - else + type = proto_redistnum (AFI_IP6, argv[0]); + if (type < 0) { vty_out (vty, "Unknown route type%s", VTY_NEWLINE); return CMD_WARNING; @@ -1891,7 +1756,7 @@ DEFUN (show_ipv6_route_protocol, { if (first) { - vty_out (vty, SHOW_ROUTE_V6_HEADER, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE); + vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } vty_show_ipv6_route (vty, rn, rib); @@ -2031,14 +1896,11 @@ static_config_ipv6 (struct vty *vty) vty_out (vty, " %s %s", inet_ntop (AF_INET6, &si->ipv6, buf, BUFSIZ), si->ifname); break; + case STATIC_IPV6_BLACKHOLE: + vty_out (vty, " Null0 %s", BLACKHOLE_NAME (si->zflags)); + break; } - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_REJECT)) - vty_out (vty, " %s", "reject"); - - if (CHECK_FLAG(si->flags, ZEBRA_FLAG_BLACKHOLE)) - vty_out (vty, " %s", "blackhole"); - if (si->distance != ZEBRA_STATIC_DISTANCE_DEFAULT) vty_out (vty, " %d", si->distance); vty_out (vty, "%s", VTY_NEWLINE); @@ -2139,21 +2001,17 @@ zebra_vty_init (void) #ifdef HAVE_IPV6 install_element (CONFIG_NODE, &ipv6_route_cmd); - install_element (CONFIG_NODE, &ipv6_route_flags_cmd); install_element (CONFIG_NODE, &ipv6_route_ifname_cmd); - install_element (CONFIG_NODE, &ipv6_route_ifname_flags_cmd); install_element (CONFIG_NODE, &no_ipv6_route_cmd); - install_element (CONFIG_NODE, &no_ipv6_route_flags_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_cmd); - install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_cmd); install_element (CONFIG_NODE, &ipv6_route_pref_cmd); - install_element (CONFIG_NODE, &ipv6_route_flags_pref_cmd); install_element (CONFIG_NODE, &ipv6_route_ifname_pref_cmd); - install_element (CONFIG_NODE, &ipv6_route_ifname_flags_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_pref_cmd); - install_element (CONFIG_NODE, &no_ipv6_route_flags_pref_cmd); install_element (CONFIG_NODE, &no_ipv6_route_ifname_pref_cmd); - install_element (CONFIG_NODE, &no_ipv6_route_ifname_flags_pref_cmd); + install_element (CONFIG_NODE, &ipv6_route_blackhole_cmd); + install_element (CONFIG_NODE, &ipv6_route_blackhole_pref_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_blackhole_cmd); + install_element (CONFIG_NODE, &no_ipv6_route_blackhole_pref_cmd); install_element (VIEW_NODE, &show_ipv6_route_cmd); install_element (VIEW_NODE, &show_ipv6_route_summary_cmd); install_element (VIEW_NODE, &show_ipv6_route_protocol_cmd); diff --git a/zebra/zserv.c b/zebra/zserv.c index cb5e411c..ced8fa5a 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1,5 +1,6 @@ /* Zebra daemon server routine. * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro + * Portions Copyright (c) 2008 Everton da Silva Marques <everton.marques@gmail.com> * * This file is part of GNU Zebra. * @@ -36,6 +37,7 @@ #include "privs.h" #include "network.h" #include "buffer.h" +#include "paths.h" #include "zebra/zserv.h" #include "zebra/router-id.h" @@ -595,6 +597,77 @@ zsend_ipv4_nexthop_lookup (struct zserv *client, struct in_addr addr) return zebra_server_send_message(client); } +/* + Modified version of zsend_ipv4_nexthop_lookup(): + 1) Returns both nexthop address and nexthop ifindex + (with ZEBRA_NEXTHOP_IPV4_IFINDEX). + 2) Returns both route metric and protocol distance. +*/ +static int +zsend_ipv4_nexthop_lookup_v2 (struct zserv *client, struct in_addr addr) +{ + struct stream *s; + struct rib *rib; + unsigned long nump; + u_char num; + struct nexthop *nexthop; + + /* Lookup nexthop. */ + rib = rib_match_ipv4 (addr); + + /* Get output stream. */ + s = client->obuf; + stream_reset (s); + + /* Fill in result. */ + zserv_create_header (s, ZEBRA_IPV4_NEXTHOP_LOOKUP_V2); + stream_put_in_addr (s, &addr); + + if (rib) + { + stream_putc (s, rib->distance); + stream_putl (s, rib->metric); + num = 0; + nump = stream_get_endp(s); /* remember position for nexthop_num */ + stream_putc (s, 0); /* reserve room for nexthop_num */ + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + stream_putc (s, nexthop->type); + switch (nexthop->type) + { + case ZEBRA_NEXTHOP_IPV4: + stream_put_in_addr (s, &nexthop->gate.ipv4); + break; + case ZEBRA_NEXTHOP_IFINDEX: + case ZEBRA_NEXTHOP_IFNAME: + stream_putl (s, nexthop->ifindex); + break; + case ZEBRA_NEXTHOP_IPV4_IFINDEX: + stream_put_in_addr (s, &nexthop->gate.ipv4); + stream_putl (s, nexthop->ifindex); + break; + default: + /* do nothing */ + break; + } + num++; + } + + stream_putc_at (s, nump, num); /* store nexthop_num */ + } + else + { + stream_putc (s, 0); /* distance */ + stream_putl (s, 0); /* metric */ + stream_putc (s, 0); /* nexthop_num */ + } + + stream_putw_at (s, 0, stream_get_endp (s)); + + return zebra_server_send_message(client); +} + static int zsend_ipv4_import_lookup (struct zserv *client, struct prefix_ipv4 *p) { @@ -804,6 +877,8 @@ zread_ipv4_add (struct zserv *client, u_short length) /* Table */ rib->table=zebrad.rtm_table_default; rib_add_ipv4_multipath (&p, rib); + + rib_update_background (); return 0; } @@ -878,6 +953,8 @@ zread_ipv4_delete (struct zserv *client, u_short length) rib_delete_ipv4 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table); + + rib_update_background (); return 0; } @@ -891,6 +968,16 @@ zread_ipv4_nexthop_lookup (struct zserv *client, u_short length) return zsend_ipv4_nexthop_lookup (client, addr); } +/* Nexthop lookup v2 for IPv4. */ +static int +zread_ipv4_nexthop_lookup_v2 (struct zserv *client, u_short length) +{ + struct in_addr addr; + + addr.s_addr = stream_get_ipv4 (client->ibuf); + return zsend_ipv4_nexthop_lookup_v2 (client, addr); +} + /* Nexthop lookup for IPv4. */ static int zread_ipv4_import_lookup (struct zserv *client, u_short length) @@ -969,6 +1056,8 @@ zread_ipv6_add (struct zserv *client, u_short length) else rib_add_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, zebrad.rtm_table_default, api.metric, api.distance); + + rib_update_background (); return 0; } @@ -1033,6 +1122,8 @@ zread_ipv6_delete (struct zserv *client, u_short length) rib_delete_ipv6 (api.type, api.flags, &p, NULL, ifindex, client->rtm_table); else rib_delete_ipv6 (api.type, api.flags, &p, &nexthop, ifindex, client->rtm_table); + + rib_update_background (); return 0; } @@ -1275,6 +1366,9 @@ zebra_client_read (struct thread *thread) case ZEBRA_IPV4_NEXTHOP_LOOKUP: zread_ipv4_nexthop_lookup (client, length); break; + case ZEBRA_IPV4_NEXTHOP_LOOKUP_V2: + zread_ipv4_nexthop_lookup_v2 (client, length); + break; #ifdef HAVE_IPV6 case ZEBRA_IPV6_NEXTHOP_LOOKUP: zread_ipv6_nexthop_lookup (client, length); @@ -1738,6 +1832,6 @@ zebra_zserv_socket_init (void) #ifdef HAVE_TCP_ZEBRA zebra_serv (); #else - zebra_serv_un (ZEBRA_SERV_PATH); + zebra_serv_un (path_state (ZEBRA_SERV_NAME)); #endif /* HAVE_TCP_ZEBRA */ } diff --git a/zebra/zserv.h b/zebra/zserv.h index a7371830..340e7f5d 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -30,7 +30,9 @@ #define ZEBRA_VTY_PORT 2601 /* Default configuration filename. */ -#define DEFAULT_CONFIG_FILE "zebra.conf" +#define ZEBRA_CONFIG_NAME "zebra.conf" +#define ZEBRA_PID_NAME "zebra.pid" +#define ZEBRA_VTY_NAME "zebra.vty" /* Client structure. */ struct zserv @@ -81,6 +83,9 @@ struct zebra_t /* rib work queue */ struct work_queue *ribq; struct meta_queue *mq; + + /* rib update thread */ + struct thread *update; }; /* Count prefix size from mask length */ |