diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/ChangeLog | 28 | ||||
-rw-r--r-- | zebra/ioctl.c | 26 | ||||
-rw-r--r-- | zebra/kernel_socket.c | 22 | ||||
-rw-r--r-- | zebra/rib.h | 1 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 56 |
5 files changed, 133 insertions, 0 deletions
diff --git a/zebra/ChangeLog b/zebra/ChangeLog index 3ce7b9ea..d9cae283 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,31 @@ +2008-02-26 Denis Ovsienko + * zebra_rib.[ch]: (rib_lookup_and_pushup) New function, which makes sure, + that if_set_prefix() has nothing in its way of assigning an address. + * ioctl.c: (if_set_prefix) Use rib_lookup_and_pushup() to resolve + bug #326. + +2008-01-11 Andrew J. Schorr <ajschorr@alumni.princeton.edu> + + * ioctl.c: If HAVE_BSD_LINK_DETECT is defined, include <net/if_media.h> + (if_get_flags) Remove debug messages about BSD link state. + * kernel_socket.c: (bsd_linkdetect_translate) If link state + is unknown, we should set the IFF_RUNNING flag. + +2008-01-10 Ingo Flaschberger <if@xip.at> + + * ioctl.c: (if_get_flags) If HAVE_BSD_LINK_DETECT, use the SIOCGIFMEDIA + ioctl to ascertain link state. + * kernel_socket.c: (bsd_linkdetect_translate) New function to + map the ifm_data.ifi_link_state value into the IFF_RUNNING flag. + (ifm_read) Call bsd_linkdetect_translate to fix the IFF_RUNNING + flag before calling if_flags_update. + +2008-01-08 Michael Larson <mike@vyatta.com> + + * zebra_rib.c: (nexthop_active_check) Replace if_is_up with + if_is_operative to solve problems with static interface + routes not behaving properly with link-detect. + 2007-11-12 Denis Ovsienko * connected.c: (connected_up_ipv4, connected_down_ipv4, diff --git a/zebra/ioctl.c b/zebra/ioctl.c index c9ec8d57..d536771a 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -33,6 +33,10 @@ #include "zebra/rt.h" #include "zebra/interface.h" +#ifdef HAVE_BSD_LINK_DETECT +#include <net/if_media.h> +#endif /* HAVE_BSD_LINK_DETECT*/ + extern struct zebra_privs_t zserv_privs; /* clear and set interface name string */ @@ -192,6 +196,7 @@ if_set_prefix (struct interface *ifp, struct connected *ifc) struct prefix_ipv4 *p; p = (struct prefix_ipv4 *) ifc->address; + rib_lookup_and_pushup (p); memset (&addreq, 0, sizeof addreq); strncpy ((char *)&addreq.ifra_name, ifp->name, sizeof addreq.ifra_name); @@ -344,6 +349,9 @@ if_get_flags (struct interface *ifp) { int ret; struct ifreq ifreq; +#ifdef HAVE_BSD_LINK_DETECT + struct ifmediareq ifmr; +#endif /* HAVE_BSD_LINK_DETECT */ ifreq_set_name (&ifreq, ifp); @@ -353,6 +361,24 @@ if_get_flags (struct interface *ifp) zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } +#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */ + (void) memset(&ifmr, 0, sizeof(ifmr)); + strncpy (&ifmr.ifm_name, ifp->name, IFNAMSIZ); + if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) + { + zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno)); + return; + } + if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */ + { + if (ifmr.ifm_status & IFM_ACTIVE) + SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + else + UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING); + } + else /* Force always up */ + SET_FLAG(ifreq.ifr_flags, IFF_RUNNING); +#endif /* HAVE_BSD_LINK_DETECT */ if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff)); } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index a91d76f5..2e04b031 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -295,6 +295,19 @@ ifan_read (struct if_announcemsghdr *ifan) } #endif /* RTM_IFANNOUNCE */ +#ifdef HAVE_BSD_LINK_DETECT +/* BSD link detect translation */ +static void +bsd_linkdetect_translate (struct if_msghdr *ifm) +{ + if ((ifm->ifm_data.ifi_link_state >= LINK_STATE_UP) || + (ifm->ifm_data.ifi_link_state == LINK_STATE_UNKNOWN)) + SET_FLAG(ifm->ifm_flags, IFF_RUNNING); + else + UNSET_FLAG(ifm->ifm_flags, IFF_RUNNING); +} +#endif /* HAVE_BSD_LINK_DETECT */ + /* * Handle struct if_msghdr obtained from reading routing socket or * sysctl (from interface_list). There may or may not be sockaddrs @@ -426,6 +439,11 @@ ifm_read (struct if_msghdr *ifm) * structure with ifindex IFINDEX_INTERNAL. */ ifp->ifindex = ifm->ifm_index; + +#ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ + bsd_linkdetect_translate(ifm); +#endif /* HAVE_BSD_LINK_DETECT */ + if_flags_update (ifp, ifm->ifm_flags); #if defined(__bsdi__) if_kvm_get_mtu (ifp); @@ -453,6 +471,10 @@ ifm_read (struct if_msghdr *ifm) return -1; } +#ifdef HAVE_BSD_LINK_DETECT /* translate BSD kernel msg for link-state */ + bsd_linkdetect_translate(ifm); +#endif /* HAVE_BSD_LINK_DETECT */ + /* update flags and handle operative->inoperative transition, if any */ if_flags_update (ifp, ifm->ifm_flags); diff --git a/zebra/rib.h b/zebra/rib.h index 796a30eb..9621f2c8 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -212,6 +212,7 @@ extern struct nexthop *nexthop_blackhole_add (struct rib *); extern struct nexthop *nexthop_ipv4_add (struct rib *, struct in_addr *, struct in_addr *); extern void rib_lookup_and_dump (struct prefix_ipv4 *); +extern void rib_lookup_and_pushup (struct prefix_ipv4 *); extern void rib_dump (const char *, const struct prefix_ipv4 *, const struct rib *); extern int rib_lookup_ipv4_route (struct prefix_ipv4 *, union sockunion *); #define ZEBRA_RIB_LOOKUP_ERROR -1 diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 27cd4fa9..24975f71 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1657,6 +1657,62 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) } } +/* Check if requested address assignment will fail due to another + * route being installed by zebra in FIB already. Take necessary + * actions, if needed: remove such a route from FIB and deSELECT + * corresponding RIB entry. Then put affected RN into RIBQ head. + */ +void rib_lookup_and_pushup (struct prefix_ipv4 * p) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + unsigned changed = 0; + + if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0))) + { + zlog_err ("%s: vrf_table() returned NULL", __func__); + return; + } + + /* No matches would be the simplest case. */ + if (NULL == (rn = route_node_lookup (table, (struct prefix *) p))) + return; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Check all RIB entries. In case any changes have to be done, requeue + * the RN into RIBQ head. If the routing message about the new connected + * route (generated by the IP address we are going to assign very soon) + * comes before the RIBQ is processed, the new RIB entry will join + * RIBQ record already on head. This is necessary for proper revalidation + * of the rest of the RIB. + */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && + ! RIB_SYSTEM_ROUTE (rib)) + { + changed = 1; + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[INET_ADDRSTRLEN]; + inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); + rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); + } + rib_uninstall (rn, rib); + } + } + if (changed) + { + work_queue_aim_head (zebrad.ribq, 1); + rib_queue_add (&zebrad, rn); + work_queue_aim_head (zebrad.ribq, 0); + } +} + int rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) { |