2005-09-12 Paul Jakma <paul.jakma@sun.com>
* (general) RTM_CHANGE and implicit withdraw on RTM_NEWADDR
support.
* connected.c: (connected_withdraw) new function. withdraw a
connected subnet address set from zebra, and pass information
along to clients.
(connected_announce) similar, but to announce a new connected
subnet address set.
(connected_check_ipv4) renamed to connected_check, as its
AFI independent.
(connected_add_ipv{4,6}) Remove the connected address announce
stuff, use connected_announce instead.
If connected_check indicates address is already present,
treat it as an implicit withdraw of the existing address, ie
remove the old address details and replace with the new
details.
(connected_delete_ipv{4,6}) Use connected_withdraw.
(connected_check_ipv6) deleted in favour of connected_check.
* connected.h: Rename connected_check_ipv4 to connected_check.
delete connected_check_ipv6.
* interface.c: Use connected_check rather than the AFI specific
symbols.
* kernel_socket.c: (rtm_read) RTM_CHANGE support. Create a
rib delete event for the existing route, before adding route
again.
(kernel_read) we can handle RTM_CHANGE now.
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 61b8b41..6225ce1 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,31 @@
+2005-09-12 Paul Jakma <paul.jakma@sun.com>
+
+ * (general) RTM_CHANGE and implicit withdraw on RTM_NEWADDR
+ support.
+ * connected.c: (connected_withdraw) new function. withdraw a
+ connected subnet address set from zebra, and pass information
+ along to clients.
+ (connected_announce) similar, but to announce a new connected
+ subnet address set.
+ (connected_check_ipv4) renamed to connected_check, as its
+ AFI independent.
+ (connected_add_ipv{4,6}) Remove the connected address announce
+ stuff, use connected_announce instead.
+ If connected_check indicates address is already present,
+ treat it as an implicit withdraw of the existing address, ie
+ remove the old address details and replace with the new
+ details.
+ (connected_delete_ipv{4,6}) Use connected_withdraw.
+ (connected_check_ipv6) deleted in favour of connected_check.
+ * connected.h: Rename connected_check_ipv4 to connected_check.
+ delete connected_check_ipv6.
+ * interface.c: Use connected_check rather than the AFI specific
+ symbols.
+ * kernel_socket.c: (rtm_read) RTM_CHANGE support. Create a
+ rib delete event for the existing route, before adding route
+ again.
+ (kernel_read) we can handle RTM_CHANGE now.
+
2005-08-27 Hasso Tepper <hasso at quagga.net>
* zebra_rib.c, rib.h: Add distance and metric arguments to the
diff --git a/zebra/connected.c b/zebra/connected.c
index 6826908..7599d24 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -35,9 +35,63 @@
#include "zebra/interface.h"
#include "zebra/connected.h"
+/* withdraw a connected address */
+static void
+connected_withdraw (struct connected *ifc)
+{
+ if (! ifc)
+ return;
+
+ /* Update interface address information to protocol daemon. */
+ if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ {
+ zebra_interface_address_delete_update (ifc->ifp, ifc);
+
+ if_subnet_delete (ifc->ifp, ifc);
+
+ if (ifc->address->family == AF_INET)
+ connected_down_ipv4 (ifc->ifp, ifc);
+ else
+ connected_down_ipv6 (ifc->ifp, ifc);
+
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+ }
+
+ listnode_delete (ifc->ifp->connected, ifc);
+ connected_free (ifc);
+}
+
+static void
+connected_announce (struct interface *ifp, struct connected *ifc)
+{
+ if (!ifc)
+ return;
+
+ listnode_add (ifp->connected, ifc);
+
+ /* Update interface address information to protocol daemon. */
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ {
+ if (ifc->address->family == AF_INET)
+ if_subnet_add (ifp, ifc);
+
+ SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+ zebra_interface_address_add_update (ifp, ifc);
+
+ if (if_is_up(ifp))
+ {
+ if (ifc->address->family == AF_INET)
+ connected_up_ipv4 (ifp, ifc);
+ else
+ connected_up_ipv6 (ifp, ifc);
+ }
+ }
+}
+
/* If same interface address is already exist... */
struct connected *
-connected_check_ipv4 (struct interface *ifp, struct prefix *p)
+connected_check (struct interface *ifp, struct prefix *p)
{
struct connected *ifc;
struct listnode *node;
@@ -106,7 +160,7 @@
p->prefix = *addr;
p->prefixlen = prefixlen;
ifc->address = (struct prefix *) p;
-
+
/* If there is broadcast or pointopoint address. */
if (broad)
{
@@ -163,29 +217,10 @@
ifc->label = strdup (label);
/* Check same connected route. */
- current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address);
- if (current)
- {
- connected_free (ifc);
- ifc = current;
- }
- else
- {
- listnode_add (ifp->connected, ifc);
- }
-
- /* Update interface address information to protocol daemon. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- {
- if_subnet_add (ifp, ifc);
-
- SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
- zebra_interface_address_add_update (ifp, ifc);
-
- if (if_is_up(ifp))
- connected_up_ipv4 (ifp, ifc);
- }
+ if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
+ connected_withdraw (current); /* implicit withdraw - freebsd does this */
+
+ connected_announce (ifp, ifc);
}
void
@@ -237,41 +272,14 @@
p.prefix = *addr;
p.prefixlen = prefixlen;
- ifc = connected_check_ipv4 (ifp, (struct prefix *) &p);
+ ifc = connected_check (ifp, (struct prefix *) &p);
if (! ifc)
return;
-
- /* Update interface address information to protocol daemon. */
- if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- {
- zebra_interface_address_delete_update (ifp, ifc);
-
- if_subnet_delete (ifp, ifc);
-
- connected_down_ipv4 (ifp, ifc);
-
- UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
- }
-
- listnode_delete (ifp->connected, ifc);
- connected_free (ifc);
+
+ connected_withdraw (ifc);
}
#ifdef HAVE_IPV6
-/* If same interface address is already exist... */
-struct connected *
-connected_check_ipv6 (struct interface *ifp, struct prefix *p)
-{
- struct connected *ifc;
- struct listnode *node;
-
- for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
- if (prefix_same (ifc->address, p))
- return ifc;
-
- return 0;
-}
-
void
connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
{
@@ -342,27 +350,10 @@
ifc->destination = (struct prefix *) p;
}
- current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address);
- if (current)
- {
- connected_free (ifc);
- ifc = current;
- }
- else
- {
- listnode_add (ifp->connected, ifc);
- }
-
- /* Update interface address information to protocol daemon. */
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- {
- SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
- zebra_interface_address_add_update (ifp, ifc);
-
- if (if_is_up(ifp))
- connected_up_ipv6 (ifp, ifc);
- }
+ if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
+ connected_withdraw (current); /* implicit update of existing address */
+
+ connected_announce (ifp, ifc);
}
void
@@ -414,21 +405,10 @@
memcpy (&p.prefix, address, sizeof (struct in6_addr));
p.prefixlen = prefixlen;
- ifc = connected_check_ipv6 (ifp, (struct prefix *) &p);
+ ifc = connected_check (ifp, (struct prefix *) &p);
if (! ifc)
return;
- /* Update interface address information to protocol daemon. */
- if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
- {
- zebra_interface_address_delete_update (ifp, ifc);
-
- connected_down_ipv6 (ifp, ifc);
-
- UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
- }
-
- listnode_delete (ifp->connected, ifc);
- connected_free (ifc);
+ connected_withdraw (ifc);
}
#endif /* HAVE_IPV6 */
diff --git a/zebra/connected.h b/zebra/connected.h
index 726092a..73166eb 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -24,7 +24,7 @@
#define _ZEBRA_CONNECTED_H
extern struct connected *
-connected_check_ipv4 (struct interface *ifp, struct prefix *p);
+connected_check (struct interface *ifp, struct prefix *p);
extern void
connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
@@ -38,9 +38,6 @@
extern void connected_down_ipv4 (struct interface *, struct connected *);
#ifdef HAVE_IPV6
-extern struct connected *
-connected_check_ipv6 (struct interface *ifp, struct prefix *p);
-
extern void
connected_add_ipv6 (struct interface *ifp, struct in6_addr *address,
u_char prefixlen, struct in6_addr *broad);
diff --git a/zebra/interface.c b/zebra/interface.c
index 92e43d9..49fffcf 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1150,7 +1150,7 @@
return CMD_WARNING;
}
- ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+ ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
ifc = connected_new ();
@@ -1236,7 +1236,7 @@
}
/* Check current interface address. */
- ifc = connected_check_ipv4 (ifp, (struct prefix *) &cp);
+ ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
@@ -1346,7 +1346,7 @@
return CMD_WARNING;
}
- ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+ ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
ifc = connected_new ();
@@ -1425,7 +1425,7 @@
}
/* Check current interface address. */
- ifc = connected_check_ipv6 (ifp, (struct prefix *) &cp);
+ ifc = connected_check (ifp, (struct prefix *) &cp);
if (! ifc)
{
vty_out (vty, "%% Can't find address%s", VTY_NEWLINE);
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index fe7411e..f391d53 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -623,8 +623,17 @@
p.prefixlen = IPV4_MAX_PREFIXLEN;
else
p.prefixlen = ip_masklen (mask.sin.sin_addr);
-
- if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+
+ /* Change, delete the old prefix, we have no further information
+ * to specify the route really
+ */
+ if (rtm->rtm_type == RTM_CHANGE)
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
+ NULL, 0, 0);
+
+ if (rtm->rtm_type == RTM_GET
+ || rtm->rtm_type == RTM_ADD
+ || rtm->rtm_type == RTM_CHANGE)
rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
&p, &gate.sin.sin_addr, 0, 0, 0, 0);
else
@@ -652,7 +661,16 @@
}
#endif /* KAME */
- if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD)
+ /* CHANGE: delete the old prefix, we have no further information
+ * to specify the route really
+ */
+ if (rtm->rtm_type == RTM_CHANGE)
+ rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &p,
+ NULL, 0, 0);
+
+ if (rtm->rtm_type == RTM_GET
+ || rtm->rtm_type == RTM_ADD
+ || rtm->rtm_type == RTM_CHANGE)
rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, zebra_flags,
&p, &gate.sin6.sin6_addr, ifindex, 0, 0, 0);
else
@@ -920,6 +938,7 @@
{
case RTM_ADD:
case RTM_DELETE:
+ case RTM_CHANGE:
rtm_read (rtm);
break;
case RTM_IFINFO: