From 74ecdc9e74eb96829e342a03531ba6647ce6bb3c Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 15 Jun 2006 18:10:47 +0000 Subject: [zebra] Fix forgetfulness wrt configured address on FreeBSD 2006-06-15 Paul Jakma * (general) The key fixes are actually Andrew Schorr's. * interface.c: (ip_address_uninstall) Unset the configured flag. * connected.c: (connected_same) new helper, check whether two connected are same. (connected_implicit_withdraw) new helper, consolidation of existing code in connected_add_ipv{4,6}. Try filter out unneeded Zserv address delete/adds when address is exact same. Where old address is implicitely removed, be sure to preserve the IFC_CONFIGURED flag if set, fixes bug where configured addresses were being lost on FreeBSD. --- zebra/ChangeLog | 10 +++++++ zebra/connected.c | 83 +++++++++++++++++++++++++++++++++++++++++-------------- zebra/interface.c | 2 ++ 3 files changed, 74 insertions(+), 21 deletions(-) diff --git a/zebra/ChangeLog b/zebra/ChangeLog index c31e3504..69bb1e8e 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -2,6 +2,16 @@ * interface.c: (if_flag_dump_vty) redundant code, remove. (if_dump_vty) use libzebra if_flag_dump. + (ip_address_uninstall) Unset the configured flag. + * connected.c: (connected_same) new helper, check whether + two connected are same. + (connected_implicit_withdraw) new helper, consolidation of + existing code in connected_add_ipv{4,6}. + Try filter out unneeded Zserv address delete/adds when + address is exact same. + Where old address is implicitely removed, be sure to preserve + the IFC_CONFIGURED flag if set, fixes bug where configured + addresses were being lost on FreeBSD (Andrew Schorr). 2006-05-21 Andrew J. Schorr diff --git a/zebra/connected.c b/zebra/connected.c index 37aa456a..736b40b0 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -111,6 +111,63 @@ connected_check (struct interface *ifp, struct prefix *p) return NULL; } +/* Check if two ifc's describe the same address */ +static int +connected_same (struct connected *ifc1, struct connected *ifc2) +{ + if (ifc1->ifp != ifc2->ifp) + return 0; + + if (ifc1->destination) + if (!ifc2->destination) + return 0; + if (ifc2->destination) + if (!ifc1->destination) + return 0; + + if (ifc1->destination && ifc2->destination) + if (!prefix_same (ifc1->destination, ifc2->destination)) + return 0; + + if (ifc1->flags != ifc2->flags) + return 0; + + return 1; +} + +/* Handle implicit withdrawals of addresses, where a system ADDs an address + * to an interface which already has the same address configured. + * + * Returns the struct connected which must be announced to clients, + * or NULL if nothing to do. + */ +static struct connected * +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 (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) + SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); + + /* Avoid spurious withdraws, this might be just the kernel 'reflecting' + * back an address we have already added. + */ + if (connected_same (current, ifc)) + { + /* nothing to do */ + connected_free (ifc); + return NULL; + } + + UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); + connected_withdraw (current); /* implicit withdraw - freebsd does this */ + } + return ifc; +} + /* Called from if_up(). */ void connected_up_ipv4 (struct interface *ifp, struct connected *ifc) @@ -157,7 +214,6 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, { struct prefix_ipv4 *p; struct connected *ifc; - struct connected *current; /* Make connected structure. */ ifc = connected_new (); @@ -226,16 +282,9 @@ connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); - /* Check same connected route. */ - if ((current = connected_check (ifp, (struct prefix *) ifc->address))) - { - if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) - { - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); - } - connected_withdraw (current); /* implicit withdraw - freebsd does this */ - } + /* nothing to do? */ + if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) + return; connected_announce (ifp, ifc); } @@ -347,7 +396,6 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, { struct prefix_ipv6 *p; struct connected *ifc; - struct connected *current; /* Make connected structure. */ ifc = connected_new (); @@ -373,15 +421,8 @@ connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr, if (label) ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label); - if ((current = connected_check (ifp, (struct prefix *) ifc->address))) - { - if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED)) - { - SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED); - UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED); - } - connected_withdraw (current); /* implicit update of existing address */ - } + if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL) + return; connected_announce (ifp, ifc); } diff --git a/zebra/interface.c b/zebra/interface.c index e386047f..69124b3d 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1273,6 +1273,8 @@ ip_address_uninstall (struct vty *vty, struct interface *ifp, if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED)) return CMD_WARNING; + UNSET_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED); + /* This is not real address or interface is not active. */ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL) || ! CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_ACTIVE)) -- cgit v1.2.1