diff --git a/zebra/connected.c b/zebra/connected.c index 701314f246..1368a12289 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -100,8 +100,10 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) } /* If same interface address is already exist... */ -struct connected *connected_check(struct interface *ifp, struct prefix *p) +struct connected *connected_check(struct interface *ifp, + union prefixconstptr pu) { + const struct prefix *p = pu.p; struct connected *ifc; struct listnode *node; @@ -112,6 +114,33 @@ struct connected *connected_check(struct interface *ifp, struct prefix *p) return NULL; } +/* same, but with peer address */ +struct connected *connected_check_ptp(struct interface *ifp, + union prefixconstptr pu, + union prefixconstptr du) +{ + const struct prefix *p = pu.p; + const struct prefix *d = du.p; + 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 in the same state */ static int connected_same(struct connected *ifc1, struct connected *ifc2) { @@ -145,7 +174,8 @@ static void connected_update(struct interface *ifp, struct connected *ifc) struct connected *current; /* Check same connected route. */ - if ((current = connected_check(ifp, (struct prefix *)ifc->address))) { + current = connected_check_ptp(ifp, ifc->address, ifc->destination); + if (current) { if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); @@ -238,7 +268,8 @@ void 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. */ @@ -350,15 +381,25 @@ 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; diff --git a/zebra/connected.h b/zebra/connected.h index eaf79fe9aa..b67442fa3b 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -23,7 +23,10 @@ #define _ZEBRA_CONNECTED_H extern struct connected *connected_check(struct interface *ifp, - struct prefix *p); + union prefixconstptr p); +extern struct connected *connected_check_ptp(struct interface *ifp, + union prefixconstptr p, + union prefixconstptr d); extern void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, u_char prefixlen, diff --git a/zebra/interface.c b/zebra/interface.c index c17e408ea0..9b4af1786e 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -242,7 +242,7 @@ int 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); @@ -267,12 +267,16 @@ int 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)) { zlog_warn( "Trying to remove an address from an unknown subnet." @@ -966,6 +970,8 @@ static void connected_dump_vty(struct vty *vty, struct connected *connected) vty_out(vty, (CONNECTED_PEER(connected) ? " peer " : " broadcast ")); prefix_vty_out(vty, connected->destination); + if (CONNECTED_PEER(connected)) + vty_out(vty, "/%d", connected->destination->prefixlen); } if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY))