[ovs-dev] [netlink v4 07/52] netlink-socket: Add functions for joining and leaving multicast groups.
Justin Pettit
jpettit at nicira.com
Tue Jan 18 08:42:50 UTC 2011
Looks good.
--Justin
On Jan 11, 2011, at 9:49 PM, Ben Pfaff wrote:
> When this library was originally implemented, support for Linux 2.4 was
> important. The Netlink implementation in Linux only added support for
> joining and leaving multicast groups after a socket is bound as of Linux
> 2.6.14, so the library did not support it either. But the current version
> of Open vSwitch targets Linux 2.6.18 and over, so it's fine to add this
> support now, and this commit does so.
>
> This will be used more extensively in upcoming commits.
> ---
> lib/netdev-linux.c | 4 +-
> lib/netdev-vport.c | 2 +-
> lib/netlink-protocol.h | 13 ++++--
> lib/netlink-socket.c | 94 +++++++++++++++++++++-----------------------
> lib/netlink-socket.h | 9 ++--
> lib/rtnetlink.c | 13 +++++-
> utilities/nlmon.c | 9 +++-
> vswitchd/ovs-brcompatd.c | 25 +++++++++---
> vswitchd/proc-net-compat.c | 4 +-
> 9 files changed, 99 insertions(+), 74 deletions(-)
>
> diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c
> index 5654dd4..65b22b7 100644
> --- a/lib/netdev-linux.c
> +++ b/lib/netdev-linux.c
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -445,7 +445,7 @@ netdev_linux_init(void)
>
> /* 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));
> diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
> index f3985e9..fb2b619 100644
> --- a/lib/netdev-vport.c
> +++ b/lib/netdev-vport.c
> @@ -508,7 +508,7 @@ netdev_vport_reset_name_else_route(bool is_name)
> }
> }
>
> - 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;
> diff --git a/lib/netlink-protocol.h b/lib/netlink-protocol.h
> index 6281fb2..1b5fa71 100644
> --- a/lib/netlink-protocol.h
> +++ b/lib/netlink-protocol.h
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -86,10 +86,6 @@ struct nlmsgerr
> };
> 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;
> @@ -157,4 +153,11 @@ enum {
> #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 */
> diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c
> index c9402fd..8e81da9 100644
> --- a/lib/netlink-socket.c
> +++ b/lib/netlink-socket.c
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -65,18 +65,9 @@ static void free_pid(uint32_t);
>
> /* 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;
> @@ -99,29 +90,10 @@ nl_sock_create(int protocol, int multicast_group,
> 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;
> @@ -136,23 +108,6 @@ nl_sock_create(int protocol, int multicast_group,
> 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;
>
> @@ -183,6 +138,47 @@ nl_sock_destroy(struct nl_sock *sock)
> }
> }
>
> +/* 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.
> @@ -608,7 +604,7 @@ static int do_lookup_genl_family(const char *name)
> 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;
> }
> diff --git a/lib/netlink-socket.h b/lib/netlink-socket.h
> index dc21ce8..ad06d81 100644
> --- a/lib/netlink-socket.h
> +++ b/lib/netlink-socket.h
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -45,11 +45,12 @@ struct nl_sock;
> #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);
> diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c
> index 5d80d72..b92dcd6 100644
> --- a/lib/rtnetlink.c
> +++ b/lib/rtnetlink.c
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -77,13 +77,20 @@ rtnetlink_notifier_register(struct rtnetlink *rtn,
> 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. */
> diff --git a/utilities/nlmon.c b/utilities/nlmon.c
> index 1fb3808..b6396d5 100644
> --- a/utilities/nlmon.c
> +++ b/utilities/nlmon.c
> @@ -1,5 +1,5 @@
> /*
> - * 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.
> @@ -45,11 +45,16 @@ main(int argc OVS_UNUSED, char *argv[])
> 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;
>
> diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c
> index bed2747..19e09e7 100644
> --- a/vswitchd/ovs-brcompatd.c
> +++ b/vswitchd/ovs-brcompatd.c
> @@ -1,4 +1,4 @@
> -/* 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.
> @@ -111,7 +111,7 @@ lookup_brc_multicast_group(int *multicast_group)
> 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;
> }
> @@ -156,12 +156,17 @@ brc_open(struct nl_sock **sock)
> 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[] = {
> @@ -1318,8 +1323,16 @@ main(int argc, char *argv[])
> }
>
> 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");
> }
> }
>
> diff --git a/vswitchd/proc-net-compat.c b/vswitchd/proc-net-compat.c
> index e3b7ee4..3b7596a 100644
> --- a/vswitchd/proc-net-compat.c
> +++ b/vswitchd/proc-net-compat.c
> @@ -1,4 +1,4 @@
> -/* 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.
> @@ -59,7 +59,7 @@ proc_net_compat_init(void)
> 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;
> }
> --
> 1.7.1
>
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev_openvswitch.org
More information about the dev
mailing list