summaryrefslogtreecommitdiffstats
path: root/zebra/connected.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/connected.c')
-rw-r--r--zebra/connected.c105
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;