ifp->ifindex = ifi_index;
}
-/* Make socket for Linux netlink interface. */
static int
-netlink_socket (struct nlsock *nl, unsigned long groups)
+netlink_recvbuf (struct nlsock *nl, uint32_t newsize)
{
+ u_int32_t oldsize;
+ socklen_t newlen = sizeof(newsize);
+ socklen_t oldlen = sizeof(oldsize);
int ret;
- struct sockaddr_nl snl;
- int sock;
- int namelen;
- int save_errno;
- sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sock < 0)
+ ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
+ if (ret < 0)
{
- zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
- safe_strerror (errno));
+ zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
+ safe_strerror (errno));
return -1;
}
- ret = fcntl (sock, F_SETFL, O_NONBLOCK);
+ ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
+ sizeof(nl_rcvbufsize));
if (ret < 0)
{
- zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", nl->name,
- safe_strerror (errno));
- close (sock);
+ zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
+ safe_strerror (errno));
return -1;
}
- /* Set receive buffer size if it's set from command line */
- if (nl_rcvbufsize)
+ ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
+ if (ret < 0)
{
- u_int32_t oldsize, oldlen;
- u_int32_t newsize, newlen;
+ zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
+ safe_strerror (errno));
+ return -1;
+ }
- oldlen = sizeof(oldsize);
- newlen = sizeof(newsize);
+ zlog (NULL, LOG_INFO,
+ "Setting netlink socket receive buffer size: %u -> %u",
+ oldsize, newsize);
+ return 0;
+}
- ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
-
- ret = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &nl_rcvbufsize,
- sizeof(nl_rcvbufsize));
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't set %s receive buffer size: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
-
- ret = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
- if (ret < 0)
- {
- zlog (NULL, LOG_ERR, "Can't get %s receive buffer size: %s", nl->name,
- safe_strerror (errno));
- close (sock);
- return -1;
- }
+/* Make socket for Linux netlink interface. */
+static int
+netlink_socket (struct nlsock *nl, unsigned long groups)
+{
+ int ret;
+ struct sockaddr_nl snl;
+ int sock;
+ int namelen;
+ int save_errno;
- zlog (NULL, LOG_INFO,
- "Setting netlink socket receive buffer size: %u -> %u",
- oldsize, newsize);
+ sock = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (sock < 0)
+ {
+ zlog (NULL, LOG_ERR, "Can't open %s socket: %s", nl->name,
+ safe_strerror (errno));
+ return -1;
}
memset (&snl, 0, sizeof snl);
return ret;
}
-static int
-set_netlink_blocking (struct nlsock *nl, int *flags)
-{
-
- /* Change socket flags for blocking I/O. */
- if ((*flags = fcntl (nl->sock, F_GETFL, 0)) < 0)
- {
- zlog (NULL, LOG_ERR, "%s:%i F_GETFL error: %s",
- __FUNCTION__, __LINE__, safe_strerror (errno));
- return -1;
- }
- *flags &= ~O_NONBLOCK;
- if (fcntl (nl->sock, F_SETFL, *flags) < 0)
- {
- zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
- __FUNCTION__, __LINE__, safe_strerror (errno));
- return -1;
- }
- return 0;
-}
-
-static int
-set_netlink_nonblocking (struct nlsock *nl, int *flags)
-{
- /* Restore socket flags for nonblocking I/O */
- *flags |= O_NONBLOCK;
- if (fcntl (nl->sock, F_SETFL, *flags) < 0)
- {
- zlog (NULL, LOG_ERR, "%s:%i F_SETFL error: %s",
- __FUNCTION__, __LINE__, safe_strerror (errno));
- return -1;
- }
- return 0;
-}
-
/* Get type specified information from netlink. */
static int
netlink_request (int family, int type, struct nlsock *nl)
struct sockaddr_nl snl;
struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
struct nlmsghdr *h;
- int save_errno;
-
- if (zserv_privs.change (ZPRIVS_RAISE))
- zlog (NULL, LOG_ERR, "Can't raise privileges");
status = recvmsg (nl->sock, &msg, 0);
- save_errno = errno;
-
- if (zserv_privs.change (ZPRIVS_LOWER))
- zlog (NULL, LOG_ERR, "Can't lower privileges");
-
if (status < 0)
{
- if (save_errno == EINTR)
+ if (errno == EINTR)
continue;
- if (save_errno == EWOULDBLOCK || save_errno == EAGAIN)
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
break;
zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
- nl->name, safe_strerror(save_errno));
+ nl->name, safe_strerror(errno));
continue;
}
if (h->nlmsg_type == NLMSG_ERROR)
{
struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h);
+ int errnum = err->error;
+ int msg_type = err->msg.nlmsg_type;
/* If the error field is zero, then this is an ACK */
if (err->error == 0)
return -1;
}
- /* Deal with Error Noise - MAG */
- {
- int loglvl = LOG_ERR;
- int errnum = err->error;
- int msg_type = err->msg.nlmsg_type;
-
- if (nl == &netlink_cmd
- && (-errnum == ENODEV || -errnum == ESRCH)
- && (msg_type == RTM_NEWROUTE || msg_type == RTM_DELROUTE))
- loglvl = LOG_DEBUG;
-
- zlog (NULL, loglvl, "%s error: %s, type=%s(%u), "
- "seq=%u, pid=%u",
- nl->name, safe_strerror (-errnum),
- lookup (nlmsg_str, msg_type),
- msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
- }
- /*
- ret = -1;
- continue;
- */
+ /* Deal with errors that occur because of races in link handling */
+ if (nl == &netlink_cmd
+ && ((msg_type == RTM_DELROUTE &&
+ (-errnum == ENODEV || -errnum == ESRCH))
+ || (msg_type == RTM_NEWROUTE && -errnum == EEXIST)))
+ {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug ("%s: error: %s type=%s(%u), seq=%u, pid=%u",
+ nl->name, safe_strerror (-errnum),
+ lookup (nlmsg_str, msg_type),
+ msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
+ return 0;
+ }
+
+ zlog_err ("%s error: %s, type=%s(%u), seq=%u, pid=%u",
+ nl->name, safe_strerror (-errnum),
+ lookup (nlmsg_str, msg_type),
+ msg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid);
return -1;
}
ifp = if_get_by_name (name);
set_ifindex(ifp, ifi->ifi_index);
ifp->flags = ifi->ifi_flags & 0x0000fffff;
- ifp->mtu6 = ifp->mtu = *(int *) RTA_DATA (tb[IFLA_MTU]);
+ ifp->mtu6 = ifp->mtu = *(uint32_t *) RTA_DATA (tb[IFLA_MTU]);
ifp->metric = 1;
/* Hardware type and address. */
int index;
int table;
+ int metric;
+
void *dest;
void *gate;
void *src;
}
index = 0;
+ metric = 0;
dest = NULL;
gate = NULL;
src = NULL;
if (tb[RTA_PREFSRC])
src = RTA_DATA (tb[RTA_PREFSRC]);
+ if (h->nlmsg_type == RTM_NEWROUTE && tb[RTA_PRIORITY])
+ metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+
if (rtm->rtm_family == AF_INET)
{
struct prefix_ipv4 p;
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
+ rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, metric, 0);
else
rib_delete_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
}
if (h->nlmsg_type == RTM_NEWROUTE)
- rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0, 0, 0);
+ rib_add_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table, metric, 0);
else
- rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, 0);
+ rib_delete_ipv6 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, index, table);
}
#endif /* HAVE_IPV6 */
interface_lookup_netlink (void)
{
int ret;
- int flags;
- int snb_ret;
-
- /*
- * Change netlink socket flags to blocking to ensure we get
- * a reply via nelink_parse_info
- */
- snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
/* Get interface information. */
ret = netlink_request (AF_PACKET, RTM_GETLINK, &netlink_cmd);
return ret;
#endif /* HAVE_IPV6 */
- /* restore socket flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
return 0;
}
netlink_route_read (void)
{
int ret;
- int flags;
- int snb_ret;
-
- /*
- * Change netlink socket flags to blocking to ensure we get
- * a reply via nelink_parse_info
- */
- snb_ret = set_netlink_blocking (&netlink_cmd, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
/* Get IPv4 routing table. */
ret = netlink_request (AF_INET, RTM_GETROUTE, &netlink_cmd);
return ret;
#endif /* HAVE_IPV6 */
- /* restore flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
return 0;
}
struct sockaddr_nl snl;
struct iovec iov = { (void *) n, n->nlmsg_len };
struct msghdr msg = { (void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0 };
- int flags = 0;
- int snb_ret;
int save_errno;
memset (&snl, 0, sizeof snl);
return -1;
}
- /*
- * Change socket flags for blocking I/O.
- * This ensures we wait for a reply in netlink_parse_info().
- */
- snb_ret = set_netlink_blocking (nl, &flags);
- if (snb_ret < 0)
- zlog (NULL, LOG_WARNING,
- "%s:%i Warning: Could not set netlink socket to blocking.",
- __FUNCTION__, __LINE__);
/*
* Get reply from netlink socket.
* The reply should either be an acknowlegement or an error.
*/
- status = netlink_parse_info (netlink_talk_filter, nl);
-
- /* Restore socket flags for nonblocking I/O */
- if (snb_ret == 0)
- set_netlink_nonblocking (nl, &flags);
-
- return status;
+ return netlink_parse_info (netlink_talk_filter, nl);
}
/* Routing table change via netlink interface. */
/* Register kernel socket. */
if (netlink.sock > 0)
{
+ /* Only want non-blocking on the netlink event socket */
+ if (fcntl (netlink.sock, F_SETFL, O_NONBLOCK) < 0)
+ zlog (NULL, LOG_ERR, "Can't set %s socket flags: %s", netlink.name,
+ safe_strerror (errno));
+
+ /* Set receive buffer size if it's set from command line */
+ if (nl_rcvbufsize)
+ netlink_recvbuf (&netlink, nl_rcvbufsize);
+
netlink_install_filter (netlink.sock, netlink_cmd.snl.nl_pid);
thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
}