diff options
author | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2008-05-19 13:34:23 -0700 |
---|---|---|
committer | Stephen Hemminger <stephen.hemminger@vyatta.com> | 2008-05-19 13:34:23 -0700 |
commit | 61514d88f16d567902b34281cb40379aa099bf8c (patch) | |
tree | b4e54acc43c516e160591500ad2080579e879c78 | |
parent | 685a4b330aff3edff8e1c72638cf8a65bf655da1 (diff) | |
download | quagga-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.c | 183 |
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); } |