* Given a pointer (sockaddr or void *), return the number of bytes
* taken up by the sockaddr and any padding needed for alignment.
*/
-#if defined(HAVE_SA_LEN)
+#if defined(HAVE_STRUCT_SOCKADDR_SA_LEN)
#define SAROUNDUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
#elif defined(HAVE_IPV6)
/*
ROUNDUP(sizeof(struct sockaddr_in)):\
(((struct sockaddr *)(X))->sa_family == AF_LINK ? \
ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr)))
-#endif /* HAVE_SA_LEN */
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
/* We use an additional pointer in following, pdest, rather than (DEST)
* directly, because gcc will warn if the macro is expanded and DEST is NULL,
(LEN) = 0; \
}
/* Routing socket message types. */
-struct message rtm_type_str[] =
+const struct message rtm_type_str[] =
{
{RTM_ADD, "RTM_ADD"},
{RTM_DELETE, "RTM_DELETE"},
}
#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
* 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);
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);
if_delete_update (ifp);
}
#endif /* RTM_IFANNOUNCE */
+ if (if_is_up (ifp))
+ {
+#if defined(__bsdi__)
+ if_kvm_get_mtu (ifp);
+#else
+ if_get_mtu (ifp);
+#endif /* __bsdi__ */
+ if_get_metric (ifp);
+ }
}
#ifdef HAVE_NET_RT_IFLIST
short *ifnlen)
{
caddr_t pnt, end;
+ union sockunion dst;
+ union sockunion gateway;
pnt = (caddr_t)(ifm + 1);
end = ((caddr_t)ifm) + ifm->ifam_msglen;
memset (mask, 0, sizeof (union sockunion));
memset (addr, 0, sizeof (union sockunion));
memset (brd, 0, sizeof (union sockunion));
+ memset (&dst, 0, sizeof (union sockunion));
+ memset (&gateway, 0, sizeof (union sockunion));
/* We fetch each socket variable into sockunion. */
- RTA_ADDR_GET (NULL, RTA_DST, ifm->ifam_addrs, pnt);
- RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifam_addrs, pnt);
+ RTA_ADDR_GET (&dst, RTA_DST, ifm->ifam_addrs, pnt);
+ RTA_ADDR_GET (&gateway, RTA_GATEWAY, ifm->ifam_addrs, pnt);
RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
{
case AF_INET:
{
- char buf[2][INET_ADDRSTRLEN];
+ char buf[4][INET_ADDRSTRLEN];
zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
- "addr %s/%d broad %s",
- __func__, ifm->ifam_index,
+ "ifam_flags 0x%x, addr %s/%d broad %s dst %s "
+ "gateway %s",
+ __func__, ifm->ifam_index,
(ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
+ ifm->ifam_flags,
inet_ntop(AF_INET,&addr->sin.sin_addr,
buf[0],sizeof(buf[0])),
ip_masklen(mask->sin.sin_addr),
inet_ntop(AF_INET,&brd->sin.sin_addr,
- buf[1],sizeof(buf[1])));
+ buf[1],sizeof(buf[1])),
+ inet_ntop(AF_INET,&dst.sin.sin_addr,
+ buf[2],sizeof(buf[2])),
+ inet_ntop(AF_INET,&gateway.sin.sin_addr,
+ buf[3],sizeof(buf[3])));
}
break;
#ifdef HAVE_IPV6
case AF_INET6:
{
- char buf[2][INET6_ADDRSTRLEN];
+ char buf[4][INET6_ADDRSTRLEN];
zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x, "
- "addr %s/%d broad %s",
+ "ifam_flags 0x%x, addr %s/%d broad %s dst %s "
+ "gateway %s",
__func__, ifm->ifam_index,
(ifnlen ? ifname : "(nil)"), ifm->ifam_addrs,
+ ifm->ifam_flags,
inet_ntop(AF_INET6,&addr->sin6.sin6_addr,
buf[0],sizeof(buf[0])),
ip6_masklen(mask->sin6.sin6_addr),
inet_ntop(AF_INET6,&brd->sin6.sin6_addr,
- buf[1],sizeof(buf[1])));
+ buf[1],sizeof(buf[1])),
+ inet_ntop(AF_INET6,&dst.sin6.sin6_addr,
+ buf[2],sizeof(buf[2])),
+ inet_ntop(AF_INET6,&gateway.sin6.sin6_addr,
+ buf[3],sizeof(buf[3])));
}
break;
#endif /* HAVE_IPV6 */
break;
}
}
-
+
/* Assert read up end point matches to end point */
if (pnt != end)
zlog_warn ("ifam_read() does't read all socket data");
char ifname[INTERFACE_NAMSIZ];
short ifnlen = 0;
char isalias = 0;
+ int flags = 0;
ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0';
if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ))
isalias = 1;
+ /* N.B. The info in ifa_msghdr does not tell us whether the RTA_BRD
+ field contains a broadcast address or a peer address, so we are forced to
+ rely upon the interface type. */
+ if (if_is_pointopoint(ifp))
+ SET_FLAG(flags, ZEBRA_IFA_PEER);
+
+#if 0
+ /* it might seem cute to grab the interface metric here, however
+ * we're processing an address update message, and so some systems
+ * (e.g. FBSD) dont bother to fill in ifam_metric. Disabled, but left
+ * in deliberately, as comment.
+ */
ifp->metric = ifam->ifam_metric;
-
+#endif
+
/* Add connected address. */
switch (sockunion_family (&addr))
{
case AF_INET:
if (ifam->ifam_type == RTM_NEWADDR)
- connected_add_ipv4 (ifp, 0, &addr.sin.sin_addr,
+ connected_add_ipv4 (ifp, flags, &addr.sin.sin_addr,
ip_masklen (mask.sin.sin_addr),
&brd.sin.sin_addr,
(isalias ? ifname : NULL));
else
- connected_delete_ipv4 (ifp, 0, &addr.sin.sin_addr,
+ connected_delete_ipv4 (ifp, flags, &addr.sin.sin_addr,
ip_masklen (mask.sin.sin_addr),
&brd.sin.sin_addr);
break;
SET_IN6_LINKLOCAL_IFINDEX (addr.sin6.sin6_addr, 0);
if (ifam->ifam_type == RTM_NEWADDR)
- connected_add_ipv6 (ifp,
- &addr.sin6.sin6_addr,
+ connected_add_ipv6 (ifp, flags, &addr.sin6.sin6_addr,
ip6_masklen (mask.sin6.sin6_addr),
&brd.sin6.sin6_addr,
(isalias ? ifname : NULL));
zebra_flags = 0;
- /* Discard self send message. */
- if (rtm->rtm_type != RTM_GET
- && (rtm->rtm_pid == pid || rtm->rtm_pid == old_pid))
- return;
-
/* Read destination and netmask and gateway from rtm message
structure. */
flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
+ if (!(flags & RTF_DONE))
+ return;
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: got rtm of type %d (%s)", __func__, rtm->rtm_type,
+ lookup (rtm_type_str, rtm->rtm_type));
#ifdef RTF_CLONED /*bsdi, netbsd 1.6*/
if (flags & RTF_CLONED)
else
p.prefixlen = ip_masklen (mask.sin.sin_addr);
+ /* Catch self originated messages and match them against our current RIB.
+ * At the same time, ignore unconfirmed messages, they should be tracked
+ * by rtm_write() and kernel_rtm_ipv4().
+ */
+ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
+ {
+ char buf[INET_ADDRSTRLEN], gate_buf[INET_ADDRSTRLEN];
+ int ret;
+ if (! IS_ZEBRA_DEBUG_RIB)
+ return;
+ ret = rib_lookup_ipv4_route (&p, &gate);
+ inet_ntop (AF_INET, &p.prefix, buf, INET_ADDRSTRLEN);
+ switch (rtm->rtm_type)
+ {
+ case RTM_ADD:
+ case RTM_GET:
+ case RTM_CHANGE:
+ /* The kernel notifies us about a new route in FIB created by us.
+ Do we have a correspondent entry in our RIB? */
+ switch (ret)
+ {
+ case ZEBRA_RIB_NOTFOUND:
+ zlog_debug ("%s: %s %s/%d: desync: RR isn't yet in RIB, while already in FIB",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
+ break;
+ case ZEBRA_RIB_FOUND_CONNECTED:
+ case ZEBRA_RIB_FOUND_NOGATE:
+ inet_ntop (AF_INET, &gate.sin.sin_addr, gate_buf, INET_ADDRSTRLEN);
+ zlog_debug ("%s: %s %s/%d: desync: RR is in RIB, but gate differs (ours is %s)",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen, gate_buf);
+ break;
+ case ZEBRA_RIB_FOUND_EXACT: /* RIB RR == FIB RR */
+ zlog_debug ("%s: %s %s/%d: done Ok",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
+ rib_lookup_and_dump (&p);
+ return;
+ break;
+ }
+ break;
+ case RTM_DELETE:
+ /* The kernel notifies us about a route deleted by us. Do we still
+ have it in the RIB? Do we have anything instead? */
+ switch (ret)
+ {
+ case ZEBRA_RIB_FOUND_EXACT:
+ zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, while already not in FIB",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
+ rib_lookup_and_dump (&p);
+ break;
+ case ZEBRA_RIB_FOUND_CONNECTED:
+ case ZEBRA_RIB_FOUND_NOGATE:
+ zlog_debug ("%s: %s %s/%d: desync: RR is still in RIB, plus gate differs",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
+ rib_lookup_and_dump (&p);
+ break;
+ case ZEBRA_RIB_NOTFOUND: /* RIB RR == FIB RR */
+ zlog_debug ("%s: %s %s/%d: done Ok",
+ __func__, lookup (rtm_type_str, rtm->rtm_type), buf, p.prefixlen);
+ rib_lookup_and_dump (&p);
+ return;
+ break;
+ }
+ break;
+ default:
+ zlog_debug ("%s: %s/%d: warning: loopback RTM of type %s received",
+ __func__, buf, p.prefixlen, lookup (rtm_type_str, rtm->rtm_type));
+ }
+ return;
+ }
+
/* Change, delete the old prefix, we have no further information
* to specify the route really
*/
|| 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);
+ &p, &gate.sin.sin_addr, NULL, 0, 0, 0, 0);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags,
&p, &gate.sin.sin_addr, 0, 0);
#ifdef HAVE_IPV6
if (dest.sa.sa_family == AF_INET6)
{
+ /* One day we might have a debug section here like one in the
+ * IPv4 case above. Just ignore own messages at the moment.
+ */
+ if (rtm->rtm_type != RTM_GET && rtm->rtm_pid == pid)
+ return;
struct prefix_ipv6 p;
unsigned int ifindex = 0;
{
if (!ifp)
{
- zlog_warn ("no gateway found for interface index %d", index);
+ char dest_buf[INET_ADDRSTRLEN] = "NULL", mask_buf[INET_ADDRSTRLEN] = "255.255.255.255";
+ if (dest)
+ inet_ntop (AF_INET, &dest->sin.sin_addr, dest_buf, INET_ADDRSTRLEN);
+ if (mask)
+ inet_ntop (AF_INET, &mask->sin.sin_addr, mask_buf, INET_ADDRSTRLEN);
+ zlog_warn ("%s: %s/%s: gate == NULL and no gateway found for ifindex %d",
+ __func__, dest_buf, mask_buf, index);
return -1;
}
gate = (union sockunion *) & ifp->sdl;
msg.rtm.rtm_flags |= RTF_REJECT;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
#define SOCKADDRSET(X,R) \
if (msg.rtm.rtm_addrs & (R)) \
{ \
memcpy (pnt, (caddr_t)(X), len); \
pnt += len; \
}
-#endif /* HAVE_SIN_LEN */
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
pnt = (caddr_t) msg.buf;
return ZEBRA_ERR_RTEXIST;
if (errno == ENETUNREACH)
return ZEBRA_ERR_RTUNREACH;
+ if (errno == ESRCH)
+ return ZEBRA_ERR_RTNOEXIST;
- zlog_warn ("write : %s (%d)", safe_strerror (errno), errno);
- return -1;
+ zlog_warn ("%s: write : %s (%d)", __func__, safe_strerror (errno), errno);
+ return ZEBRA_ERR_KERNEL;
}
- return 0;
+ return ZEBRA_ERR_NOERROR;
}
\f
static void
rtmsg_debug (struct rt_msghdr *rtm)
{
- const char *type = "Unknown";
- struct message *mes;
-
- for (mes = rtm_type_str; mes->str; mes++)
- if (mes->key == rtm->rtm_type)
- {
- type = mes->str;
- break;
- }
-
- zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
+ zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, lookup (rtm_type_str, rtm->rtm_type));
rtm_flag_dump (rtm->rtm_flags);
zlog_debug ("Kernel: message seq %d", rtm->rtm_seq);
zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs);