Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9c1a793 authored by Xin Long's avatar Xin Long Committed by David S. Miller
Browse files

tipc: add dst_cache support for udp media



As other udp/ip tunnels do, tipc udp media should also have a
lockless dst_cache supported on its tx path.

Here we add dst_cache into udp_replicast to support dst cache
for both rmcast and rcast, and rmcast uses ub->rcast and each
rcast uses its own node in ub->rcast.list.

Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d96ff269
Loading
Loading
Loading
Loading
+47 −25
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ struct udp_media_addr {
/* struct udp_replicast - container for UDP remote addresses */
struct udp_replicast {
	struct udp_media_addr addr;
	struct dst_cache dst_cache;
	struct rcu_head rcu;
	struct list_head list;
};
@@ -158,12 +159,15 @@ static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a)
/* tipc_send_msg - enqueue a send request */
static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
			 struct udp_bearer *ub, struct udp_media_addr *src,
			 struct udp_media_addr *dst)
			 struct udp_media_addr *dst, struct dst_cache *cache)
{
	struct dst_entry *ndst = dst_cache_get(cache);
	int ttl, err = 0;
	struct rtable *rt;

	if (dst->proto == htons(ETH_P_IP)) {
		struct rtable *rt = (struct rtable *)ndst;

		if (!rt) {
			struct flowi4 fl = {
				.daddr = dst->ipv4.s_addr,
				.saddr = src->ipv4.s_addr,
@@ -175,6 +179,8 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
				err = PTR_ERR(rt);
				goto tx_error;
			}
			dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
		}

		ttl = ip4_dst_hoplimit(&rt->dst);
		udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
@@ -182,17 +188,19 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
				    dst->port, false, true);
#if IS_ENABLED(CONFIG_IPV6)
	} else {
		struct dst_entry *ndst;
		if (!ndst) {
			struct flowi6 fl6 = {
				.flowi6_oif = ub->ifindex,
				.daddr = dst->ipv6,
				.saddr = src->ipv6,
				.flowi6_proto = IPPROTO_UDP
			};
		err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst,
						 &fl6);
			err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk,
							 &ndst, &fl6);
			if (err)
				goto tx_error;
			dst_cache_set_ip6(cache, ndst, &fl6.saddr);
		}
		ttl = ip6_dst_hoplimit(ndst);
		err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
					   &src->ipv6, &dst->ipv6, 0, ttl, 0,
@@ -230,7 +238,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
	}

	if (addr->broadcast != TIPC_REPLICAST_SUPPORT)
		return tipc_udp_xmit(net, skb, ub, src, dst);
		return tipc_udp_xmit(net, skb, ub, src, dst,
				     &ub->rcast.dst_cache);

	/* Replicast, send an skb to each configured IP address */
	list_for_each_entry_rcu(rcast, &ub->rcast.list, list) {
@@ -242,7 +251,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
			goto out;
		}

		err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr);
		err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr,
				    &rcast->dst_cache);
		if (err)
			goto out;
	}
@@ -286,6 +296,11 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b,
	if (!rcast)
		return -ENOMEM;

	if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
		kfree(rcast);
		return -ENOMEM;
	}

	memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));

	if (ntohs(addr->proto) == ETH_P_IP)
@@ -742,6 +757,10 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,
	tuncfg.encap_destroy = NULL;
	setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg);

	err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC);
	if (err)
		goto err;

	/**
	 * The bcast media address port is used for all peers and the ip
	 * is used if it's a multicast address.
@@ -756,6 +775,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b,

	return 0;
err:
	dst_cache_destroy(&ub->rcast.dst_cache);
	if (ub->ubsock)
		udp_tunnel_sock_release(ub->ubsock);
	kfree(ub);
@@ -769,10 +789,12 @@ static void cleanup_bearer(struct work_struct *work)
	struct udp_replicast *rcast, *tmp;

	list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
		dst_cache_destroy(&rcast->dst_cache);
		list_del_rcu(&rcast->list);
		kfree_rcu(rcast, rcu);
	}

	dst_cache_destroy(&ub->rcast.dst_cache);
	if (ub->ubsock)
		udp_tunnel_sock_release(ub->ubsock);
	synchronize_net();