summaryrefslogtreecommitdiff
path: root/zebra/connected.c
diff options
context:
space:
mode:
authorpaul <paul>2002-12-13 20:15:29 +0000
committerpaul <paul>2002-12-13 20:15:29 +0000
commit718e3744195351130f4ce7dbe0613f4b3e23df93 (patch)
treebac2ad39971cd43f31241ef123bd4e470f695ac9 /zebra/connected.c
Initial revision
Diffstat (limited to 'zebra/connected.c')
-rw-r--r--zebra/connected.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/zebra/connected.c b/zebra/connected.c
new file mode 100644
index 00000000..cb43074b
--- /dev/null
+++ b/zebra/connected.c
@@ -0,0 +1,394 @@
+/*
+ * Address linked list routine.
+ * Copyright (C) 1997, 98 Kunihiro Ishiguro
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "prefix.h"
+#include "linklist.h"
+#include "if.h"
+#include "table.h"
+#include "rib.h"
+#include "table.h"
+#include "log.h"
+
+#include "zebra/zserv.h"
+#include "zebra/redistribute.h"
+
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv4 (struct interface *ifp, struct prefix *p)
+{
+ struct connected *ifc;
+ listnode node;
+
+ for (node = listhead (ifp->connected); node; node = nextnode (node))
+ {
+ ifc = getdata (node);
+
+ if (prefix_same (ifc->address, p))
+ return ifc;
+ }
+ return NULL;
+}
+
+/* Called from if_up(). */
+void
+connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+ struct prefix_ipv4 p;
+ struct prefix_ipv4 *addr;
+ struct prefix_ipv4 *dest;
+
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ return;
+
+ addr = (struct prefix_ipv4 *) ifc->address;
+ dest = (struct prefix_ipv4 *) ifc->destination;
+
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefixlen = addr->prefixlen;
+
+ /* Point-to-point check. */
+ if (if_is_pointopoint (ifp))
+ p.prefix = dest->prefix;
+ else
+ p.prefix = addr->prefix;
+
+ /* Apply mask to the network. */
+ apply_mask_ipv4 (&p);
+
+ /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+ address. */
+ if (prefix_ipv4_any (&p))
+ return;
+
+ rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
+
+ rib_update ();
+}
+
+/* Add connected IPv4 route to the interface. */
+void
+connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+ int prefixlen, struct in_addr *broad, char *label)
+{
+ struct prefix_ipv4 *p;
+ struct connected *ifc;
+ struct connected *current;
+
+ /* Make connected structure. */
+ ifc = connected_new ();
+ ifc->ifp = ifp;
+ ifc->flags = flags;
+
+ /* Allocate new connected address. */
+ p = prefix_ipv4_new ();
+ p->family = AF_INET;
+ p->prefix = *addr;
+ p->prefixlen = prefixlen;
+ ifc->address = (struct prefix *) p;
+
+ /* If there is broadcast or pointopoint address. */
+ if (broad)
+ {
+ p = prefix_ipv4_new ();
+ p->family = AF_INET;
+ p->prefix = *broad;
+ ifc->destination = (struct prefix *) p;
+ }
+
+ /* Label of this address. */
+ if (label)
+ 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))
+ {
+ SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
+
+ zebra_interface_address_add_update (ifp, ifc);
+
+ if (if_is_up(ifp))
+ connected_up_ipv4 (ifp, ifc);
+ }
+}
+
+void
+connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
+{
+ struct prefix_ipv4 p;
+ struct prefix_ipv4 *addr;
+ struct prefix_ipv4 *dest;
+
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ return;
+
+ addr = (struct prefix_ipv4 *)ifc->address;
+ dest = (struct prefix_ipv4 *)ifc->destination;
+
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefixlen = addr->prefixlen;
+
+ if (if_is_pointopoint (ifp))
+ p.prefix = dest->prefix;
+ else
+ p.prefix = addr->prefix;
+
+ /* Apply mask to the network. */
+ apply_mask_ipv4 (&p);
+
+ /* In case of connected address is 0.0.0.0/0 we treat it tunnel
+ address. */
+ if (prefix_ipv4_any (&p))
+ return;
+
+ rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+ rib_update ();
+}
+
+/* Delete connected IPv4 route to the interface. */
+void
+connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
+ int prefixlen, struct in_addr *broad, char *label)
+{
+ struct prefix_ipv4 p;
+ struct connected *ifc;
+
+ memset (&p, 0, sizeof (struct prefix_ipv4));
+ p.family = AF_INET;
+ p.prefix = *addr;
+ p.prefixlen = prefixlen;
+
+ ifc = connected_check_ipv4 (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_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);
+ }
+}
+
+#ifdef HAVE_IPV6
+/* If same interface address is already exist... */
+struct connected *
+connected_check_ipv6 (struct interface *ifp, struct prefix *p)
+{
+ struct connected *ifc;
+ listnode node;
+
+ for (node = listhead (ifp->connected); node; node = nextnode (node))
+ {
+ ifc = getdata (node);
+
+ if (prefix_same (ifc->address, p))
+ return ifc;
+ }
+ return 0;
+}
+
+void
+connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ struct prefix_ipv6 p;
+ struct prefix_ipv6 *addr;
+ struct prefix_ipv6 *dest;
+
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ return;
+
+ addr = (struct prefix_ipv6 *) ifc->address;
+ dest = (struct prefix_ipv6 *) ifc->destination;
+
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ p.prefixlen = addr->prefixlen;
+
+ if (if_is_pointopoint (ifp) && dest)
+ {
+ if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+ p.prefix = addr->prefix;
+ else
+ p.prefix = dest->prefix;
+ }
+ else
+ p.prefix = addr->prefix;
+
+ /* Apply mask to the network. */
+ apply_mask_ipv6 (&p);
+
+ if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+ return;
+
+ rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+ rib_update ();
+}
+
+/* Add connected IPv6 route to the interface. */
+void
+connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
+ int prefixlen, struct in6_addr *broad)
+{
+ struct prefix_ipv6 *p;
+ struct connected *ifc;
+ struct connected *current;
+
+ /* Make connected structure. */
+ ifc = connected_new ();
+ ifc->ifp = ifp;
+
+ /* Allocate new connected address. */
+ p = prefix_ipv6_new ();
+ p->family = AF_INET6;
+ IPV6_ADDR_COPY (&p->prefix, addr);
+ p->prefixlen = prefixlen;
+ ifc->address = (struct prefix *) p;
+
+ /* If there is broadcast or pointopoint address. */
+ if (broad)
+ {
+ p = prefix_ipv6_new ();
+ p->family = AF_INET6;
+ IPV6_ADDR_COPY (&p->prefix, broad);
+ 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);
+ }
+}
+
+void
+connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
+{
+ struct prefix_ipv6 p;
+ struct prefix_ipv6 *addr;
+ struct prefix_ipv6 *dest;
+
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
+ return;
+
+ addr = (struct prefix_ipv6 *) ifc->address;
+ dest = (struct prefix_ipv6 *) ifc->destination;
+
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ p.prefixlen = addr->prefixlen;
+
+ if (if_is_pointopoint (ifp) && dest)
+ {
+ if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
+ p.prefix = addr->prefix;
+ else
+ p.prefix = dest->prefix;
+ }
+ else
+ p.prefix = addr->prefix;
+
+ apply_mask_ipv6 (&p);
+
+ if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
+ return;
+
+ rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
+
+ rib_update ();
+}
+
+void
+connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
+ int prefixlen, struct in6_addr *broad)
+{
+ struct prefix_ipv6 p;
+ struct connected *ifc;
+
+ memset (&p, 0, sizeof (struct prefix_ipv6));
+ p.family = AF_INET6;
+ memcpy (&p.prefix, address, sizeof (struct in6_addr));
+ p.prefixlen = prefixlen;
+
+ ifc = connected_check_ipv6 (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);
+ }
+
+ if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
+ {
+ listnode_delete (ifp->connected, ifc);
+ connected_free (ifc);
+ }
+}
+#endif /* HAVE_IPV6 */