summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2008-05-19 13:34:23 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2008-05-19 13:34:23 -0700
commit61514d88f16d567902b34281cb40379aa099bf8c (patch)
treeb4e54acc43c516e160591500ad2080579e879c78
parent685a4b330aff3edff8e1c72638cf8a65bf655da1 (diff)
downloadquagga-61514d88f16d567902b34281cb40379aa099bf8c.tar.bz2
quagga-61514d88f16d567902b34281cb40379aa099bf8c.tar.xz
only set non-blocking on netlink socket
There is no need to increase buffer size or set non-blocking on the netlink command socket. This reduces the number of system calls per transaction.
-rw-r--r--zebra/rt_netlink.c183
1 files changed, 50 insertions, 133 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 954e0791..71d26a76 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -114,75 +114,64 @@ set_ifindex(struct interface *ifp, unsigned int ifi_index)
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);
snl.nl_family = AF_NETLINK;
snl.nl_groups = groups;
@@ -223,41 +212,6 @@ netlink_socket (struct nlsock *nl, unsigned long groups)
return ret;
}
-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;
-}
-
-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)
@@ -343,6 +297,7 @@ netlink_parse_info (int (*filter) (struct sockaddr_nl *, struct nlmsghdr *),
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
break;
+
zlog (NULL, LOG_ERR, "%s recvmsg overrun: %s",
nl->name, safe_strerror(errno));
continue;
@@ -1110,18 +1065,6 @@ int
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);
@@ -1149,9 +1092,6 @@ interface_lookup_netlink (void)
return ret;
#endif /* HAVE_IPV6 */
- /* restore socket flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
return 0;
}
@@ -1161,18 +1101,6 @@ int
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);
@@ -1192,9 +1120,6 @@ netlink_route_read (void)
return ret;
#endif /* HAVE_IPV6 */
- /* restore flags */
- if (snb_ret == 0)
- set_netlink_nonblocking (&netlink_cmd, &flags);
return 0;
}
@@ -1277,8 +1202,6 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
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);
@@ -1309,27 +1232,12 @@ netlink_talk (struct nlmsghdr *n, struct nlsock *nl)
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. */
@@ -1997,6 +1905,15 @@ kernel_init (void)
/* 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);
}