Skip to content

Commit ef20cd4

Browse files
Richard Alpedavem330
Richard Alpe
authored andcommitted
tipc: introduce UDP replicast
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 <[email protected]> Reviewed-by: Jon Maloy <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1ca73e3 commit ef20cd4

File tree

6 files changed

+201
-12
lines changed

6 files changed

+201
-12
lines changed

include/uapi/linux/tipc_netlink.h

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ enum {
6060
TIPC_NL_MON_GET,
6161
TIPC_NL_MON_PEER_GET,
6262
TIPC_NL_PEER_REMOVE,
63+
TIPC_NL_BEARER_ADD,
6364

6465
__TIPC_NL_CMD_MAX,
6566
TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1

net/tipc/bearer.c

+44
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "monitor.h"
4343
#include "bcast.h"
4444
#include "netlink.h"
45+
#include "udp_media.h"
4546

4647
#define MAX_ADDR_STR 60
4748

@@ -897,6 +898,49 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
897898
return 0;
898899
}
899900

901+
int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
902+
{
903+
int err;
904+
char *name;
905+
struct tipc_bearer *b;
906+
struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
907+
struct net *net = sock_net(skb->sk);
908+
909+
if (!info->attrs[TIPC_NLA_BEARER])
910+
return -EINVAL;
911+
912+
err = nla_parse_nested(attrs, TIPC_NLA_BEARER_MAX,
913+
info->attrs[TIPC_NLA_BEARER],
914+
tipc_nl_bearer_policy);
915+
if (err)
916+
return err;
917+
918+
if (!attrs[TIPC_NLA_BEARER_NAME])
919+
return -EINVAL;
920+
name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
921+
922+
rtnl_lock();
923+
b = tipc_bearer_find(net, name);
924+
if (!b) {
925+
rtnl_unlock();
926+
return -EINVAL;
927+
}
928+
929+
#ifdef CONFIG_TIPC_MEDIA_UDP
930+
if (attrs[TIPC_NLA_BEARER_UDP_OPTS]) {
931+
err = tipc_udp_nl_bearer_add(b,
932+
attrs[TIPC_NLA_BEARER_UDP_OPTS]);
933+
if (err) {
934+
rtnl_unlock();
935+
return err;
936+
}
937+
}
938+
#endif
939+
rtnl_unlock();
940+
941+
return 0;
942+
}
943+
900944
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
901945
{
902946
int err;

net/tipc/bearer.h

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
181181
int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
182182
int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
183183
int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
184+
int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
184185

185186
int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
186187
int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);

net/tipc/netlink.c

+5
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
160160
.dumpit = tipc_nl_bearer_dump,
161161
.policy = tipc_nl_policy,
162162
},
163+
{
164+
.cmd = TIPC_NL_BEARER_ADD,
165+
.doit = tipc_nl_bearer_add,
166+
.policy = tipc_nl_policy,
167+
},
163168
{
164169
.cmd = TIPC_NL_BEARER_SET,
165170
.doit = tipc_nl_bearer_set,

net/tipc/udp_media.c

+106-12
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "core.h"
5050
#include "bearer.h"
5151
#include "netlink.h"
52+
#include "msg.h"
5253

5354
/* IANA assigned UDP port */
5455
#define UDP_PORT_DEFAULT 6118
@@ -70,6 +71,13 @@ struct udp_media_addr {
7071
};
7172
};
7273

74+
/* struct udp_replicast - container for UDP remote addresses */
75+
struct udp_replicast {
76+
struct udp_media_addr addr;
77+
struct rcu_head rcu;
78+
struct list_head list;
79+
};
80+
7381
/**
7482
* struct udp_bearer - ip/udp bearer data structure
7583
* @bearer: associated generic tipc bearer
@@ -82,6 +90,7 @@ struct udp_bearer {
8290
struct socket *ubsock;
8391
u32 ifindex;
8492
struct work_struct work;
93+
struct udp_replicast rcast;
8594
};
8695

8796
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,
203212
{
204213
struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
205214
struct udp_media_addr *dst = (struct udp_media_addr *)&addr->value;
215+
struct udp_replicast *rcast;
206216
struct udp_bearer *ub;
207217
int err = 0;
208218

209219
if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
210220
err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
211221
if (err)
212-
goto tx_error;
222+
goto out;
213223
}
214224

215225
skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
216226
ub = rcu_dereference_rtnl(b->media_ptr);
217227
if (!ub) {
218228
err = -ENODEV;
219-
goto tx_error;
229+
goto out;
220230
}
221231

222-
return tipc_udp_xmit(net, skb, ub, src, dst);
232+
if (!addr->broadcast || list_empty(&ub->rcast.list))
233+
return tipc_udp_xmit(net, skb, ub, src, dst);
223234

224-
tx_error:
235+
/* Replicast, send an skb to each configured IP address */
236+
list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
237+
struct sk_buff *_skb;
238+
239+
_skb = pskb_copy(skb, GFP_ATOMIC);
240+
if (!_skb) {
241+
err = -ENOMEM;
242+
goto out;
243+
}
244+
245+
err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr);
246+
if (err) {
247+
kfree_skb(_skb);
248+
goto out;
249+
}
250+
}
251+
err = 0;
252+
out:
225253
kfree_skb(skb);
226254
return err;
227255
}
228256

257+
static int tipc_udp_rcast_add(struct tipc_bearer *b,
258+
struct udp_media_addr *addr)
259+
{
260+
struct udp_replicast *rcast;
261+
struct udp_bearer *ub;
262+
263+
ub = rcu_dereference_rtnl(b->media_ptr);
264+
if (!ub)
265+
return -ENODEV;
266+
267+
rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC);
268+
if (!rcast)
269+
return -ENOMEM;
270+
271+
memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
272+
273+
if (ntohs(addr->proto) == ETH_P_IP)
274+
pr_info("New replicast peer: %pI4\n", &rcast->addr.ipv4);
275+
#if IS_ENABLED(CONFIG_IPV6)
276+
else if (ntohs(addr->proto) == ETH_P_IPV6)
277+
pr_info("New replicast peer: %pI6\n", &rcast->addr.ipv6);
278+
#endif
279+
280+
list_add_rcu(&rcast->list, &ub->rcast.list);
281+
return 0;
282+
}
283+
229284
/* tipc_udp_recv - read data from bearer socket */
230285
static int tipc_udp_recv(struct sock *sk, struct sk_buff *skb)
231286
{
@@ -320,6 +375,32 @@ static int tipc_parse_udp_addr(struct nlattr *nla, struct udp_media_addr *addr,
320375
return -EADDRNOTAVAIL;
321376
}
322377

378+
int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr)
379+
{
380+
int err;
381+
struct udp_media_addr addr = {0};
382+
struct nlattr *opts[TIPC_NLA_UDP_MAX + 1];
383+
struct udp_media_addr *dst;
384+
385+
if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy))
386+
return -EINVAL;
387+
388+
if (!opts[TIPC_NLA_UDP_REMOTE])
389+
return -EINVAL;
390+
391+
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &addr, NULL);
392+
if (err)
393+
return err;
394+
395+
dst = (struct udp_media_addr *)&b->bcast_addr.value;
396+
if (tipc_udp_is_mcast_addr(dst)) {
397+
pr_err("Can't add remote ip to TIPC UDP multicast bearer\n");
398+
return -EINVAL;
399+
}
400+
401+
return tipc_udp_rcast_add(b, &addr);
402+
}
403+
323404
/**
324405
* tipc_udp_enable - callback to create a new udp bearer instance
325406
* @net: network namespace
@@ -334,7 +415,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
334415
{
335416
int err = -EINVAL;
336417
struct udp_bearer *ub;
337-
struct udp_media_addr *remote;
418+
struct udp_media_addr remote = {0};
338419
struct udp_media_addr local = {0};
339420
struct udp_port_cfg udp_conf = {0};
340421
struct udp_tunnel_sock_cfg tuncfg = {NULL};
@@ -344,6 +425,8 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
344425
if (!ub)
345426
return -ENOMEM;
346427

428+
INIT_LIST_HEAD(&ub->rcast.list);
429+
347430
if (!attrs[TIPC_NLA_BEARER_UDP_OPTS])
348431
goto err;
349432

@@ -362,9 +445,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
362445
if (err)
363446
goto err;
364447

365-
remote = (struct udp_media_addr *)&b->bcast_addr.value;
366-
memset(remote, 0, sizeof(struct udp_media_addr));
367-
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], remote, NULL);
448+
err = tipc_parse_udp_addr(opts[TIPC_NLA_UDP_REMOTE], &remote, NULL);
368449
if (err)
369450
goto err;
370451

@@ -409,10 +490,17 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
409490
tuncfg.encap_destroy = NULL;
410491
setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);
411492

412-
if (tipc_udp_is_mcast_addr(remote)) {
413-
if (enable_mcast(ub, remote))
414-
goto err;
415-
}
493+
/**
494+
* The bcast media address port is used for all peers and the ip
495+
* is used if it's a multicast address.
496+
*/
497+
memcpy(&b->bcast_addr.value, &remote, sizeof(remote));
498+
if (tipc_udp_is_mcast_addr(&remote))
499+
err = enable_mcast(ub, &remote);
500+
else
501+
err = tipc_udp_rcast_add(b, &remote);
502+
if (err)
503+
goto err;
416504

417505
return 0;
418506
err:
@@ -424,6 +512,12 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
424512
static void cleanup_bearer(struct work_struct *work)
425513
{
426514
struct udp_bearer *ub = container_of(work, struct udp_bearer, work);
515+
struct udp_replicast *rcast, *tmp;
516+
517+
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
518+
list_del_rcu(&rcast->list);
519+
kfree_rcu(rcast, rcu);
520+
}
427521

428522
if (ub->ubsock)
429523
udp_tunnel_sock_release(ub->ubsock);

net/tipc/udp_media.h

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* net/tipc/udp_media.h: Include file for UDP bearer media
3+
*
4+
* Copyright (c) 1996-2006, 2013-2016, Ericsson AB
5+
* Copyright (c) 2005, 2010-2011, Wind River Systems
6+
* All rights reserved.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions are met:
10+
*
11+
* 1. Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in the
15+
* documentation and/or other materials provided with the distribution.
16+
* 3. Neither the names of the copyright holders nor the names of its
17+
* contributors may be used to endorse or promote products derived from
18+
* this software without specific prior written permission.
19+
*
20+
* Alternatively, this software may be distributed under the terms of the
21+
* GNU General Public License ("GPL") version 2 as published by the Free
22+
* Software Foundation.
23+
*
24+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34+
* POSSIBILITY OF SUCH DAMAGE.
35+
*/
36+
37+
#ifdef CONFIG_TIPC_MEDIA_UDP
38+
#ifndef _TIPC_UDP_MEDIA_H
39+
#define _TIPC_UDP_MEDIA_H
40+
41+
int tipc_udp_nl_bearer_add(struct tipc_bearer *b, struct nlattr *attr);
42+
43+
#endif
44+
#endif

0 commit comments

Comments
 (0)