New way to handle secondary addresses from Gilad Arnold.
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 19d5431..fb8d0ab 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,12 @@
+2004-10-03 Gilad Arnold <gilad.arnold at terayon.com>
+
+ * interface.c, interface.h: A new prefix tree of connected subnets is
+ associated with each interface structure in zebra, in which each
+ live (ie, non-synthetic) node holds a list of installed addresses
+ that belong to that prefix. Remove secondary address logic from cli.
+ See [quagga-dev 872] for detailed explanation.
+ * connected.c: Use if_subnet_add() and if_subnet_delete().
+
2004-10-03 James R. Leu <jleu at mindspring.com>
* router-id.c, router-id.h: New files. Router id selection process. If
diff --git a/zebra/connected.c b/zebra/connected.c
index 21af3e9..df0b56a 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -32,6 +32,7 @@
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
+#include "zebra/interface.h"
/* If same interface address is already exist... */
struct connected *
@@ -136,6 +137,8 @@
/* 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);
@@ -203,16 +206,15 @@
{
zebra_interface_address_delete_update (ifp, ifc);
+ if_subnet_delete (ifp, ifc);
+
connected_down_ipv4 (ifp, ifc);
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
}
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
- {
- listnode_delete (ifp->connected, ifc);
- connected_free (ifc);
- }
+ listnode_delete (ifp->connected, ifc);
+ connected_free (ifc);
}
#ifdef HAVE_IPV6
@@ -389,10 +391,7 @@
UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
}
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
- {
- listnode_delete (ifp->connected, ifc);
- connected_free (ifc);
- }
+ listnode_delete (ifp->connected, ifc);
+ connected_free (ifc);
}
#endif /* HAVE_IPV6 */
diff --git a/zebra/interface.c b/zebra/interface.c
index 5c26e26..f95efa4 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -97,6 +97,9 @@
}
#endif /* RTADV */
+ /* Initialize installed address chains tree. */
+ zebra_if->ipv4_subnets = route_table_init ();
+
ifp->info = zebra_if;
return 0;
}
@@ -105,8 +108,98 @@
int
if_zebra_delete_hook (struct interface *ifp)
{
+ struct zebra_if *zebra_if;
+
if (ifp->info)
- XFREE (MTYPE_TMP, ifp->info);
+ {
+ zebra_if = ifp->info;
+
+ /* Free installed address chains tree. */
+ if (zebra_if->ipv4_subnets)
+ route_table_finish (zebra_if->ipv4_subnets);
+
+ XFREE (MTYPE_TMP, zebra_if);
+ }
+
+ return 0;
+}
+
+/* Tie an interface address to its derived subnet list of addresses. */
+int
+if_subnet_add (struct interface *ifp, struct connected *ifc)
+{
+ struct route_node *rn;
+ struct zebra_if *zebra_if;
+ struct prefix cp;
+ struct list *addr_list;
+
+ assert (ifp && ifp->info && ifc);
+ zebra_if = ifp->info;
+
+ /* Get address derived subnet node and associated address list, while marking
+ address secondary attribute appropriately. */
+ cp = *ifc->address;
+ apply_mask (&cp);
+ rn = route_node_get (zebra_if->ipv4_subnets, &cp);
+
+ if ((addr_list = rn->info))
+ SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+ else
+ {
+ UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+ rn->info = addr_list = list_new ();
+ route_lock_node (rn);
+ }
+
+ /* Tie address at the tail of address list. */
+ listnode_add (addr_list, ifc);
+
+ /* Return list element count. */
+ return (addr_list->count);
+}
+
+/* Untie an interface address from its derived subnet list of addresses. */
+int
+if_subnet_delete (struct interface *ifp, struct connected *ifc)
+{
+ struct route_node *rn;
+ struct zebra_if *zebra_if;
+ struct list *addr_list;
+
+ assert (ifp && ifp->info && ifc);
+ zebra_if = ifp->info;
+
+ /* Get address derived subnet node. */
+ rn = route_node_lookup (zebra_if->ipv4_subnets, ifc->address);
+ if (! (rn && rn->info))
+ return -1;
+ route_unlock_node (rn);
+
+ /* Untie address from subnet's address list. */
+ addr_list = rn->info;
+ listnode_delete (addr_list, ifc);
+ route_unlock_node (rn);
+
+ /* Return list element count, if not empty. */
+ if (addr_list->count)
+ {
+ /* If deleted address is primary, mark subsequent one as such and distribute. */
+ if (! CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+ {
+ ifc = (struct connected *) addr_list->head->data;
+ zebra_interface_address_delete_update (ifp, ifc);
+ UNSET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
+ zebra_interface_address_add_update (ifp, ifc);
+ }
+
+ return addr_list->count;
+ }
+
+ /* Otherwise, free list and route node. */
+ list_free (addr_list);
+ rn->info = NULL;
+ route_unlock_node (rn);
+
return 0;
}
@@ -144,6 +237,10 @@
strerror(errno));
continue;
}
+
+ /* Add to subnet chain list. */
+ if_subnet_add (ifp, ifc);
+
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
zebra_interface_address_add_update (ifp, ifc);
@@ -223,8 +320,15 @@
{
struct listnode *node;
struct listnode *next;
+ struct listnode *first;
+ struct listnode *last;
struct connected *ifc;
struct prefix *p;
+ struct route_node *rn;
+ struct zebra_if *zebra_if;
+ struct list *addr_list;
+
+ zebra_if = ifp->info;
if (if_is_up(ifp))
{
@@ -243,28 +347,70 @@
/* Delete connected routes from the kernel. */
if (ifp->connected)
{
- for (node = listhead (ifp->connected); node; node = next)
+ last = NULL;
+ while ((node = (last ? last->next : listhead (ifp->connected))))
{
- next = node->next;
ifc = getdata (node);
p = ifc->address;
-
+
if (p->family == AF_INET)
- connected_down_ipv4 (ifp, ifc);
+ {
+ rn = route_node_lookup (zebra_if->ipv4_subnets, p);
+ route_unlock_node (rn);
+ addr_list = (struct list *) rn->info;
+
+ /* Remove addresses, secondaries first. */
+ first = listhead (addr_list);
+ for (node = first->next; node || first; node = next)
+ {
+ if (! node)
+ {
+ node = first;
+ first = NULL;
+ }
+ next = node->next;
+
+ ifc = getdata (node);
+ p = ifc->address;
+
+ connected_down_ipv4 (ifp, ifc);
+
+ zebra_interface_address_delete_update (ifp, ifc);
+
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+ /* Remove from subnet chain. */
+ list_delete_node (addr_list, node);
+ route_unlock_node (rn);
+
+ /* Remove from interface address list (unconditionally). */
+ listnode_delete (ifp->connected, ifc);
+ connected_free (ifc);
+ }
+
+ /* Free chain list and respective route node. */
+ list_delete (addr_list);
+ rn->info = NULL;
+ route_unlock_node (rn);
+ }
#ifdef HAVE_IPV6
else if (p->family == AF_INET6)
- connected_down_ipv6 (ifp, ifc);
-#endif /* HAVE_IPV6 */
+ {
+ connected_down_ipv6 (ifp, ifc);
- zebra_interface_address_delete_update (ifp, ifc);
+ zebra_interface_address_delete_update (ifp, ifc);
- UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
-
- if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
- {
- listnode_delete (ifp->connected, ifc);
- connected_free (ifc);
+ UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+ if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+ last = node;
+ else
+ {
+ listnode_delete (ifp->connected, ifc);
+ connected_free (ifc);
+ }
}
+#endif /* HAVE_IPV6 */
}
}
zebra_interface_delete_update (ifp);
@@ -491,6 +637,10 @@
#endif /* HAVE_SOCKADDR_DL */
struct connected *connected;
struct listnode *node;
+ struct route_node *rn;
+ struct zebra_if *zebra_if;
+
+ zebra_if = ifp->info;
vty_out (vty, "Interface %s is ", ifp->name);
if (if_is_up(ifp)) {
@@ -566,11 +716,16 @@
vty_out(vty, "%s", VTY_NEWLINE);
}
- for (node = listhead (ifp->connected); node; nextnode (node))
+ for (rn = route_top (zebra_if->ipv4_subnets); rn; rn = route_next (rn))
{
- connected = getdata (node);
- if (CHECK_FLAG (connected->conf, ZEBRA_IFC_REAL))
- connected_dump_vty (vty, connected);
+ if (! rn->info)
+ continue;
+
+ for (node = listhead ((struct list *) rn->info); node; nextnode (node))
+ {
+ connected = getdata (node);
+ connected_dump_vty (vty, connected);
+ }
}
#ifdef RTADV
@@ -938,7 +1093,7 @@
int
ip_address_install (struct vty *vty, struct interface *ifp, char *addr_str,
- char *peer_str, char *label, int secondary)
+ char *peer_str, char *label)
{
struct prefix_ipv4 cp;
struct connected *ifc;
@@ -974,10 +1129,6 @@
ifc->destination = (struct prefix *) p;
}
- /* Secondary. */
- if (secondary)
- SET_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY);
-
/* Label. */
if (label)
ifc->label = strdup (label);
@@ -1009,6 +1160,9 @@
return CMD_WARNING;
}
+ /* Add to subnet chain list (while marking secondary attribute). */
+ if_subnet_add (ifp, ifc);
+
/* IP address propery set. */
SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
@@ -1025,7 +1179,7 @@
int
ip_address_uninstall (struct vty *vty, struct interface *ifp, char *addr_str,
- char *peer_str, char *label, int secondry)
+ char *peer_str, char *label)
{
struct prefix_ipv4 cp;
struct connected *ifc;
@@ -1069,6 +1223,7 @@
return CMD_WARNING;
}
+#if 0
/* Redistribute this information. */
zebra_interface_address_delete_update (ifp, ifc);
@@ -1078,6 +1233,7 @@
/* Free address information. */
listnode_delete (ifp->connected, ifc);
connected_free (ifc);
+#endif
return CMD_SUCCESS;
}
@@ -1089,7 +1245,7 @@
"Set the IP address of an interface\n"
"IP address (e.g. 10.0.0.1/8)\n")
{
- return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 0);
+ return ip_address_install (vty, vty->index, argv[0], NULL, NULL);
}
DEFUN (no_ip_address,
@@ -1100,21 +1256,10 @@
"Set the IP address of an interface\n"
"IP Address (e.g. 10.0.0.1/8)")
{
- return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 0);
+ return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL);
}
#ifdef HAVE_NETLINK
-DEFUN (ip_address_secondary,
- ip_address_secondary_cmd,
- "ip address A.B.C.D/M secondary",
- "Interface Internet Protocol config commands\n"
- "Set the IP address of an interface\n"
- "IP address (e.g. 10.0.0.1/8)\n"
- "Secondary IP address\n")
-{
- return ip_address_install (vty, vty->index, argv[0], NULL, NULL, 1);
-}
-
DEFUN (ip_address_label,
ip_address_label_cmd,
"ip address A.B.C.D/M label LINE",
@@ -1124,29 +1269,7 @@
"Label of this address\n"
"Label\n")
{
- return ip_address_install (vty, vty->index, argv[0], NULL, argv[1], 1);
-}
-
-ALIAS (ip_address_label,
- ip_address_secondary_label_cmd,
- "ip address A.B.C.D/M secondary label LINE",
- "Interface Internet Protocol config commands\n"
- "Set the IP address of an interface\n"
- "IP address (e.g. 10.0.0.1/8)\n"
- "Secondary IP address\n"
- "Label of this address\n"
- "Label\n")
-
-DEFUN (no_ip_address_secondary,
- no_ip_address_secondary_cmd,
- "no ip address A.B.C.D/M secondary",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Set the IP address of an interface\n"
- "IP address (e.g. 10.0.0.1/8)\n"
- "Secondary IP address\n")
-{
- return ip_address_uninstall (vty, vty->index, argv[0], NULL, NULL, 1);
+ return ip_address_install (vty, vty->index, argv[0], NULL, argv[1]);
}
DEFUN (no_ip_address_label,
@@ -1159,19 +1282,8 @@
"Label of this address\n"
"Label\n")
{
- return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1], 1);
+ return ip_address_uninstall (vty, vty->index, argv[0], NULL, argv[1]);
}
-
-ALIAS (no_ip_address_label,
- no_ip_address_secondary_label_cmd,
- "no ip address A.B.C.D/M secondary label LINE",
- NO_STR
- "Interface Internet Protocol config commands\n"
- "Set the IP address of an interface\n"
- "IP address (e.g. 10.0.0.1/8)\n"
- "Secondary IP address\n"
- "Label of this address\n"
- "Label\n")
#endif /* HAVE_NETLINK */
#ifdef HAVE_IPV6
@@ -1395,9 +1507,6 @@
inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen);
- if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
- vty_out (vty, " secondary");
-
if (ifc->label)
vty_out (vty, " label %s", ifc->label);
@@ -1468,11 +1577,7 @@
install_element (INTERFACE_NODE, &no_ip_tunnel_cmd);
#endif /* KAME */
#ifdef HAVE_NETLINK
- install_element (INTERFACE_NODE, &ip_address_secondary_cmd);
install_element (INTERFACE_NODE, &ip_address_label_cmd);
- install_element (INTERFACE_NODE, &ip_address_secondary_label_cmd);
- install_element (INTERFACE_NODE, &no_ip_address_secondary_cmd);
install_element (INTERFACE_NODE, &no_ip_address_label_cmd);
- install_element (INTERFACE_NODE, &no_ip_address_secondary_label_cmd);
#endif /* HAVE_NETLINK */
}
diff --git a/zebra/interface.h b/zebra/interface.h
index b38a922..91578ff 100644
--- a/zebra/interface.h
+++ b/zebra/interface.h
@@ -159,6 +159,9 @@
/* Interface's address. */
struct list *address;
+ /* Installed addresses chains tree. */
+ struct route_table *ipv4_subnets;
+
#ifdef RTADV
struct rtadvconf rtadv;
#endif /* RTADV */
@@ -174,6 +177,8 @@
void if_up (struct interface *);
void if_down (struct interface *);
void if_refresh (struct interface *);
+int if_subnet_add (struct interface *, struct connected *);
+int if_subnet_delete (struct interface *, struct connected *);
#ifdef HAVE_PROC_NET_DEV
int ifstat_update_proc ();