diff options
Diffstat (limited to 'zebra/connected.c')
-rw-r--r-- | zebra/connected.c | 105 |
1 files changed, 97 insertions, 8 deletions
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; |