/* * 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 #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" #include "zebra/interface.h" /* If same interface address is already exist... */ struct connected * connected_check_ipv4 (struct interface *ifp, struct prefix *p) { struct connected *ifc; struct 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) && dest) 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)) { 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); } } 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; /* Point-to-point check. */ if (dest && 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); 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); } #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 (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 ! defined (MUSICA) && ! defined (LINUX) /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */ if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; #endif 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); } listnode_delete (ifp->connected, ifc); connected_free (ifc); } #endif /* HAVE_IPV6 */