Now it looks good to me.

For the whole series:

Reviewed-by: jon

///jon


On 08/25/2016 04:15 AM, Richard Alpe wrote:
> This patch introduces UDP replicast. A concept where we emulate
> multicast by sending multiple unicast messages to configured peers.
>
> The purpose of replicast is mainly to be able to use TIPC in cloud
> environments where IP multicast is disabled. Using replicas to unicast
> multicast messages is costly as we have to copy each skb and send the
> copies individually.
>
> Signed-off-by: Richard Alpe <richard.a...@ericsson.com>
> ---
>   include/uapi/linux/tipc_netlink.h |   1 +
>   net/tipc/bearer.c                 |  44 ++++++++++++++
>   net/tipc/bearer.h                 |   1 +
>   net/tipc/netlink.c                |   5 ++
>   net/tipc/udp_media.c              | 118 
> ++++++++++++++++++++++++++++++++++----
>   net/tipc/udp_media.h              |  44 ++++++++++++++
>   6 files changed, 201 insertions(+), 12 deletions(-)
>   create mode 100644 net/tipc/udp_media.h
>
> diff --git a/include/uapi/linux/tipc_netlink.h 
> b/include/uapi/linux/tipc_netlink.h
> index bcb65ef..b15664c 100644
> --- a/include/uapi/linux/tipc_netlink.h
> +++ b/include/uapi/linux/tipc_netlink.h
> @@ -60,6 +60,7 @@ enum {
>       TIPC_NL_MON_GET,
>       TIPC_NL_MON_PEER_GET,
>       TIPC_NL_PEER_REMOVE,
> +     TIPC_NL_BEARER_ADD,
>   
>       __TIPC_NL_CMD_MAX,
>       TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
> diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
> index 28056fa..d7b442d 100644
> --- a/net/tipc/bearer.c
> +++ b/net/tipc/bearer.c
> @@ -42,6 +42,7 @@
>   #include "monitor.h"
>   #include "bcast.h"
>   #include "netlink.h"
> +#include "udp_media.h"
>   
>   #define MAX_ADDR_STR 60
>   
> @@ -897,6 +898,49 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct 
> genl_info *info)
>       return 0;
>   }
>   
> +int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
> +{
> +     int err;
> +     char *name;
> +     struct tipc_bearer *b;
> +     struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
> +     struct net *net = sock_net(skb->sk);
> +
> +     if (!info->attrs[TIPC_NLA_BEARER])
> +             return -EINVAL;
> +
> +     err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
> +                            info->attrs[TIPC_NLA_BEARER],
> +                            tipc_nl_bearer_policy);
> +     if (err)
> +             return err;
> +
> +     if (!attrs[TIPC_NLA_BEARER_NAME])
> +             return -EINVAL;
> +     name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
> +
> +     rtnl_lock();
> +     b = tipc_bearer_find(net, name);
> +     if (!b) {
> +             rtnl_unlock();
> +             return -EINVAL;
> +     }
> +
> +#ifdef CONFIG_TIPC_MEDIA_UDP
> +     if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) {
> +             err = tipc_udp_nl_bearer_add(b,
> +                                          attrs[TIPC_NLA_BEARER_UDP_OPTS]);
> +             if (err) {
> +                     rtnl_unlock();
> +                     return err;
> +             }
> +     }
> +#endif
> +     rtnl_unlock();
> +
> +     return 0;
> +}
> +
>   int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
>   {
>       int err;
> diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
> index 83a9abb..78892e2f 100644
> --- a/net/tipc/bearer.h
> +++ b/net/tipc/bearer.h
> @@ -181,6 +181,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct 
> genl_info *info);
>   int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
>   int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
>   int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
> +int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
>   
>   int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
>   int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
> diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
> index 2718de6..3122f21 100644
> --- a/net/tipc/netlink.c
> +++ b/net/tipc/netlink.c
> @@ -161,6 +161,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
>               .policy = tipc_nl_policy,
>       },
>       {
> +             .cmd    = TIPC_NL_BEARER_ADD,
> +             .doit   = tipc_nl_bearer_add,
> +             .policy = tipc_nl_policy,
> +     },
> +     {
>               .cmd    = TIPC_NL_BEARER_SET,
>               .doit   = tipc_nl_bearer_set,
>               .policy = tipc_nl_policy,
> diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
> index b8ec1a1..6b938cc 100644
> --- a/net/tipc/udp_media.c
> +++ b/net/tipc/udp_media.c
> @@ -49,6 +49,7 @@
>   #include "core.h"
>   #include "bearer.h"
>   #include "netlink.h"
> +#include "msg.h"
>   
>   /* IANA assigned UDP port */
>   #define UDP_PORT_DEFAULT    6118
> @@ -70,6 +71,13 @@ struct udp_media_addr {
>       };
>   };
>   
> +/* struct udp_replicast - container for UDP remote addresses */
> +struct udp_replicast {
> +     struct udp_media_addr addr;
> +     struct rcu_head rcu;
> +     struct list_head list;
> +};
> +
>   /**
>    * struct udp_bearer - ip/udp bearer data structure
>    * @bearer: associated generic tipc bearer
> @@ -82,6 +90,7 @@ struct udp_bearer {
>       struct socket *ubsock;
>       u32 ifindex;
>       struct work_struct work;
> +     struct udp_replicast rcast;
>   };
>   
>   static int tipc_udp_is_mcast_addr(struct udp_media_addr *addr)
> @@ -203,29 +212,75 @@ static int tipc_udp_send_msg(struct net *net, struct 
> sk_buff *skb,
>   {
>       struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
>       struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value;
> +     struct udp_replicast *rcast;
>       struct udp_bearer *ub;
>       int err = 0;
>   
>       if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
>               err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
>               if (err)
> -                     goto tx_error;
> +                     goto out;
>       }
>   
>       skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
>       ub = rcu_dereference_rtnl(b->media_ptr);
>       if (!ub) {
>               err = -ENODEV;
> -             goto tx_error;
> +             goto out;
>       }
>   
> -     return tipc_udp_xmit(net, skb, ub, src, dst);
> +     if (!addr->broadcast || list_empty(&ub->rcast.list))
> +             return tipc_udp_xmit(net, skb, ub, src, dst);
>   
> -tx_error:
> +     /* Replicast, send an skb to each configured IP address */
> +     list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
> +             struct sk_buff *_skb;
> +
> +             _skb = pskb_copy(skb, GFP_ATOMIC);
> +             if (!_skb) {
> +                     err = -ENOMEM;
> +                     goto out;
> +             }
> +
> +             err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr);
> +             if (err) {
> +                     kfree_skb(_skb);
> +                     goto out;
> +             }
> +     }
> +     err = 0;
> +out:
>       kfree_skb(skb);
>       return err;
>   }
>   
> +static int tipc_udp_rcast_add(struct tipc_bearer *b,
> +                           struct udp_media_addr *addr)
> +{
> +     struct udp_replicast *rcast;
> +     struct udp_bearer *ub;
> +
> +     ub = rcu_dereference_rtnl(b->media_ptr);
> +     if (!ub)
> +             return -ENODEV;
> +
> +     rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC);
> +     if (!rcast)
> +             return -ENOMEM;
> +
> +     memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
> +
> +     if (ntohs(addr->proto) == ETH_P_IP)
> +             pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4);
> +#if IS_ENABLED(CONFIG_IPV6)
> +     else if (ntohs(addr->proto) == ETH_P_IPV6)
> +             pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);
> +#endif
> +
> +     list_add_rcu(&rcast->list, &ub->rcast.list);
> +     return 0;
> +}
> +
>   /* tipc_udp_recv - read data from bearer socket */
>   static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
>   {
> @@ -320,6 +375,32 @@ static int tipc_parse_udp_addr(struct nlattr *nla, 
> struct udp_media_addr *addr,
>       return -EADDRNOTAVAIL;
>   }
>   
> +int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
> +{
> +     int err;
> +     struct udp_media_addr addr = {0};
> +     struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
> +     struct udp_media_addr *dst;
> +
> +     if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy))
> +             return -EINVAL;
> +
> +     if (!opts[TIPC_NLA_UDP_REMOTE])
> +             return -EINVAL;
> +
> +     err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL);
> +     if (err)
> +             return err;
> +
> +     dst = (struct udp_media_addr *)&b->bcast_addr.value;
> +     if (tipc_udp_is_mcast_addr(dst)) {
> +             pr_err("Can't add remote ip to TIPC UDP multicast bearer\n");
> +             return -EINVAL;
> +     }
> +
> +     return tipc_udp_rcast_add(b, &addr);
> +}
> +
>   /**
>    * tipc_udp_enable - callback to create a new udp bearer instance
>    * @net:    network namespace
> @@ -334,7 +415,7 @@ static int tipc_udp_enable(struct net *net, struct 
> tipc_bearer *b,
>   {
>       int err = -EINVAL;
>       struct udp_bearer *ub;
> -     struct udp_media_addr *remote;
> +     struct udp_media_addr remote = {0};
>       struct udp_media_addr local = {0};
>       struct udp_port_cfg udp_conf = {0};
>       struct udp_tunnel_sock_cfg tuncfg = {NULL};
> @@ -344,6 +425,8 @@ static int tipc_udp_enable(struct net *net, struct 
> tipc_bearer *b,
>       if (!ub)
>               return -ENOMEM;
>   
> +     INIT_LIST_HEAD(&ub->rcast.list);
> +
>       if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
>               goto err;
>   
> @@ -362,9 +445,7 @@ static int tipc_udp_enable(struct net *net, struct 
> tipc_bearer *b,
>       if (err)
>               goto err;
>   
> -     remote = (struct udp_media_addr *)&b->bcast_addr.value;
> -     memset(remote, 0, sizeof(struct udp_media_addr));
> -     err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], remote, NULL);
> +     err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL);
>       if (err)
>               goto err;
>   
> @@ -409,10 +490,17 @@ static int tipc_udp_enable(struct net *net, struct 
> tipc_bearer *b,
>       tuncfg.encap_destroy = NULL;
>       setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
>   
> -     if (tipc_udp_is_mcast_addr(remote)) {
> -             if (enable_mcast(ub, remote))
> -                     goto err;
> -     }
> +     /**
> +      * The bcast media address port is used for all peers and the ip
> +      * is used if it's a multicast address.
> +      */
> +     memcpy(&b->bcast_addr.value, &remote, sizeof(remote));
> +     if (tipc_udp_is_mcast_addr(&remote))
> +             err = enable_mcast(ub, &remote);
> +     else
> +             err = tipc_udp_rcast_add(b, &remote);
> +     if (err)
> +             goto err;
>   
>       return 0;
>   err:
> @@ -424,6 +512,12 @@ err:
>   static void cleanup_bearer(struct work_struct *work)
>   {
>       struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
> +     struct udp_replicast *rcast, *tmp;
> +
> +     list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
> +             list_del_rcu(&rcast->list);
> +             kfree_rcu(rcast, rcu);
> +     }
>   
>       if (ub->ubsock)
>               udp_tunnel_sock_release(ub->ubsock);
> diff --git a/net/tipc/udp_media.h b/net/tipc/udp_media.h
> new file mode 100644
> index 0000000..4dcb548
> --- /dev/null
> +++ b/net/tipc/udp_media.h
> @@ -0,0 +1,44 @@
> +/*
> + * net/tipc/udp_media.h: Include file for UDP bearer media
> + *
> + * Copyright (c) 1996-2006, 2013-2016, Ericsson AB
> + * Copyright (c) 2005, 2010-2011, Wind River Systems
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions are 
> met:
> + *
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above copyright
> + *    notice, this list of conditions and the following disclaimer in the
> + *    documentation and/or other materials provided with the distribution.
> + * 3. Neither the names of the copyright holders nor the names of its
> + *    contributors may be used to endorse or promote products derived from
> + *    this software without specific prior written permission.
> + *
> + * Alternatively, this software may be distributed under the terms of the
> + * GNU General Public License ("GPL") version 2 as published by the Free
> + * Software Foundation.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
> IS"
> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> + * POSSIBILITY OF SUCH DAMAGE.
> + */
> +
> +#ifdef CONFIG_TIPC_MEDIA_UDP
> +#ifndef _TIPC_UDP_MEDIA_H
> +#define _TIPC_UDP_MEDIA_H
> +
> +int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr);
> +
> +#endif
> +#endif


------------------------------------------------------------------------------
_______________________________________________
tipc-discussion mailing list
tipc-discussion@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tipc-discussion

Reply via email to