/* Create rtnetlink socket. */
if (!status) {
- status = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
+ status = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
if (status) {
VLOG_ERR_RL(&rl, "failed to create rtnetlink socket: %s",
strerror(status));
free(nn);
}
- error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
+ error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
if (error) {
VLOG_WARN_RL(&rl, "Failed to create NETLINK_ROUTE socket");
return error;
/*
- * Copyright (c) 2008, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
};
BUILD_ASSERT_DECL(sizeof(struct nlmsgerr) == 20);
-#define NETLINK_ADD_MEMBERSHIP 1
-#define NETLINK_DROP_MEMBERSHIP 2
-#define NETLINK_PKTINFO 3
-
struct genlmsghdr {
uint8_t cmd;
uint8_t version;
#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
#endif
+/* These were introduced all together in 2.6.14. (We want our programs to
+ * support the newer kernel features even if compiled with older headers.) */
+#ifndef NETLINK_ADD_MEMBERSHIP
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#endif
+
#endif /* netlink-protocol.h */
/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
/* Creates a new netlink socket for the given netlink 'protocol'
* (NETLINK_ROUTE, NETLINK_GENERIC, ...). Returns 0 and sets '*sockp' to the
- * new socket if successful, otherwise returns a positive errno value.
- *
- * If 'multicast_group' is nonzero, the new socket subscribes to the specified
- * netlink multicast group. (A netlink socket may listen to an arbitrary
- * number of multicast groups, but so far we only need one at a time.)
- *
- * Nonzero 'so_sndbuf' or 'so_rcvbuf' override the kernel default send or
- * receive buffer size, respectively.
- */
+ * new socket if successful, otherwise returns a positive errno value. */
int
-nl_sock_create(int protocol, int multicast_group,
- size_t so_sndbuf, size_t so_rcvbuf, struct nl_sock **sockp)
+nl_sock_create(int protocol, struct nl_sock **sockp)
{
struct nl_sock *sock;
struct sockaddr_nl local, remote;
goto error;
}
- if (so_sndbuf != 0
- && setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF,
- &so_sndbuf, sizeof so_sndbuf) < 0) {
- VLOG_ERR("setsockopt(SO_SNDBUF,%zu): %s", so_sndbuf, strerror(errno));
- goto error_free_pid;
- }
-
- if (so_rcvbuf != 0
- && setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF,
- &so_rcvbuf, sizeof so_rcvbuf) < 0) {
- VLOG_ERR("setsockopt(SO_RCVBUF,%zu): %s", so_rcvbuf, strerror(errno));
- goto error_free_pid;
- }
-
/* Bind local address as our selected pid. */
memset(&local, 0, sizeof local);
local.nl_family = AF_NETLINK;
local.nl_pid = sock->pid;
- if (multicast_group > 0 && multicast_group <= 32) {
- /* This method of joining multicast groups is supported by old kernels,
- * but it only allows 32 multicast groups per protocol. */
- local.nl_groups |= 1ul << (multicast_group - 1);
- }
if (bind(sock->fd, (struct sockaddr *) &local, sizeof local) < 0) {
VLOG_ERR("bind(%"PRIu32"): %s", sock->pid, strerror(errno));
goto error_free_pid;
goto error_free_pid;
}
- /* Older kernel headers failed to define this macro. We want our programs
- * to support the newer kernel features even if compiled with older
- * headers, so define it ourselves in such a case. */
-#ifndef NETLINK_ADD_MEMBERSHIP
-#define NETLINK_ADD_MEMBERSHIP 1
-#endif
-
- /* This method of joining multicast groups is only supported by newish
- * kernels, but it allows for an arbitrary number of multicast groups. */
- if (multicast_group > 32
- && setsockopt(sock->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
- &multicast_group, sizeof multicast_group) < 0) {
- VLOG_ERR("setsockopt(NETLINK_ADD_MEMBERSHIP,%d): %s",
- multicast_group, strerror(errno));
- goto error_free_pid;
- }
-
*sockp = sock;
return 0;
}
}
+/* Tries to add 'sock' as a listener for 'multicast_group'. Returns 0 if
+ * successful, otherwise a positive errno value.
+ *
+ * Multicast group numbers are always positive.
+ *
+ * It is not an error to attempt to join a multicast group to which a socket
+ * already belongs. */
+int
+nl_sock_join_mcgroup(struct nl_sock *sock, unsigned int multicast_group)
+{
+ if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP,
+ &multicast_group, sizeof multicast_group) < 0) {
+ VLOG_WARN("could not join multicast group %u (%s)",
+ multicast_group, strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
+/* Tries to make 'sock' stop listening to 'multicast_group'. Returns 0 if
+ * successful, otherwise a positive errno value.
+ *
+ * Multicast group numbers are always positive.
+ *
+ * It is not an error to attempt to leave a multicast group to which a socket
+ * does not belong.
+ *
+ * On success, reading from 'sock' will still return any messages that were
+ * received on 'multicast_group' before the group was left. */
+int
+nl_sock_leave_mcgroup(struct nl_sock *sock, unsigned int multicast_group)
+{
+ if (setsockopt(sock->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP,
+ &multicast_group, sizeof multicast_group) < 0) {
+ VLOG_WARN("could not leave multicast group %u (%s)",
+ multicast_group, strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
/* Tries to send 'msg', which must contain a Netlink message, to the kernel on
* 'sock'. nlmsg_len in 'msg' will be finalized to match msg->size, and
* nlmsg_pid will be set to 'sock''s pid, before the message is sent.
struct nlattr *attrs[ARRAY_SIZE(family_policy)];
int retval;
- retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock);
+ retval = nl_sock_create(NETLINK_GENERIC, &sock);
if (retval) {
return -retval;
}
/*
- * Copyright (c) 2008, 2009, 2010 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#endif
/* Netlink sockets. */
-int nl_sock_create(int protocol, int multicast_group,
- size_t so_sndbuf, size_t so_rcvbuf,
- struct nl_sock **);
+int nl_sock_create(int protocol, struct nl_sock **);
void nl_sock_destroy(struct nl_sock *);
+int nl_sock_join_mcgroup(struct nl_sock *, unsigned int multicast_group);
+int nl_sock_leave_mcgroup(struct nl_sock *, unsigned int multicast_group);
+
int nl_sock_send(struct nl_sock *, const struct ofpbuf *, bool wait);
int nl_sock_sendv(struct nl_sock *sock, const struct iovec iov[], size_t n_iov,
bool wait);
route_map_clear();
route_table_valid = true;
- error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
+ error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
if (error) {
VLOG_WARN_RL(&rl, "failed to reset routing table, "
"cannot create RTNETLINK_ROUTE socket");
rtnetlink_notify_func *cb, void *aux)
{
if (!rtn->notify_sock) {
- int error = nl_sock_create(NETLINK_ROUTE, rtn->multicast_group, 0, 0,
- &rtn->notify_sock);
+ struct nl_sock *sock;
+ int error;
+
+ error = nl_sock_create(NETLINK_ROUTE, &sock);
+ if (!error) {
+ error = nl_sock_join_mcgroup(sock, rtn->multicast_group);
+ }
if (error) {
+ nl_sock_destroy(sock);
VLOG_WARN("could not create rtnetlink socket: %s",
strerror(error));
return error;
}
+ rtn->notify_sock = sock;
} else {
/* Catch up on notification work so that the new notifier won't
* receive any stale notifications. */
/*
- * Copyright (c) 2009, 2010 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
set_program_name(argv[0]);
vlog_set_levels(NULL, VLF_ANY_FACILITY, VLL_DBG);
- error = nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &sock);
+ error = nl_sock_create(NETLINK_ROUTE, &sock);
if (error) {
ovs_fatal(error, "could not create rtnetlink socket");
}
+ error = nl_sock_join_mcgroup(sock, RTNLGRP_LINK);
+ if (error) {
+ ovs_fatal(error, "could not join RTNLGRP_LINK multicast group");
+ }
+
for (;;) {
struct ofpbuf *buf;
struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)];
int retval;
- retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock);
+ retval = nl_sock_create(NETLINK_GENERIC, &sock);
if (retval) {
return retval;
}
return retval;
}
- retval = nl_sock_create(NETLINK_GENERIC, multicast_group, 0, 0, sock);
+ retval = nl_sock_create(NETLINK_GENERIC, sock);
if (retval) {
return retval;
}
- return 0;
+ retval = nl_sock_join_mcgroup(*sock, multicast_group);
+ if (retval) {
+ nl_sock_destroy(*sock);
+ *sock = NULL;
+ }
+ return retval;
}
static const struct nl_policy brc_dp_policy[] = {
}
if (prune_timeout) {
- if (nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &rtnl_sock)) {
- ovs_fatal(0, "could not create rtnetlink socket");
+ int error;
+
+ error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
+ if (error) {
+ ovs_fatal(error, "could not create rtnetlink socket");
+ }
+
+ error = nl_sock_join_mcgroup(rtnl_sock, RTNLGRP_LINK);
+ if (error) {
+ ovs_fatal(error, "could not join RTNLGRP_LINK multicast group");
}
}
-/* Copyright (c) 2009, 2010 Nicira Networks
+/* Copyright (c) 2009, 2010, 2011 Nicira Networks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
return retval;
}
- retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &brc_sock);
+ retval = nl_sock_create(NETLINK_GENERIC, &brc_sock);
if (retval) {
return retval;
}