Skip to content

Commit

Permalink
tipc: introduce UDP replicast
Browse files Browse the repository at this point in the history
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.alpe@ericsson.com>
Reviewed-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Richard Alpe authored and davem330 committed Aug 27, 2016
1 parent 1ca73e3 commit ef20cd4
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 12 deletions.
1 change: 1 addition & 0 deletions include/uapi/linux/tipc_netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
44 changes: 44 additions & 0 deletions net/tipc/bearer.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "monitor.h"
#include "bcast.h"
#include "netlink.h"
#include "udp_media.h"

#define MAX_ADDR_STR 60

Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions net/tipc/bearer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions net/tipc/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
.dumpit = tipc_nl_bearer_dump,
.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,
Expand Down
118 changes: 106 additions & 12 deletions net/tipc/udp_media.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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
Expand All @@ -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};
Expand All @@ -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;

Expand All @@ -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;

Expand Down Expand Up @@ -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:
Expand All @@ -424,6 +512,12 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
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);
Expand Down
44 changes: 44 additions & 0 deletions net/tipc/udp_media.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ef20cd4

Please sign in to comment.