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: Xin Long <lucien.xin@gmail.com>
Acked-by: Jon Maloy <jon.maloy@ericsson.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Xin Long 2019-06-20 19:03:41 +08:00 committed by David S. Miller
parent d96ff269a0
commit e9c1a79321

View File

@ -76,6 +76,7 @@ struct udp_media_addr {
/* struct udp_replicast - container for UDP remote addresses */ /* struct udp_replicast - container for UDP remote addresses */
struct udp_replicast { struct udp_replicast {
struct udp_media_addr addr; struct udp_media_addr addr;
struct dst_cache dst_cache;
struct rcu_head rcu; struct rcu_head rcu;
struct list_head list; 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 */ /* tipc_send_msg - enqueue a send request */
static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
struct udp_bearer *ub, struct udp_media_addr *src, 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; int ttl, err = 0;
struct rtable *rt;
if (dst->proto == htons(ETH_P_IP)) { if (dst->proto == htons(ETH_P_IP)) {
struct rtable *rt = (struct rtable *)ndst;
if (!rt) {
struct flowi4 fl = { struct flowi4 fl = {
.daddr = dst->ipv4.s_addr, .daddr = dst->ipv4.s_addr,
.saddr = src->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); err = PTR_ERR(rt);
goto tx_error; goto tx_error;
} }
dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
}
ttl = ip4_dst_hoplimit(&rt->dst); ttl = ip4_dst_hoplimit(&rt->dst);
udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr, 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); dst->port, false, true);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
} else { } else {
struct dst_entry *ndst; if (!ndst) {
struct flowi6 fl6 = { struct flowi6 fl6 = {
.flowi6_oif = ub->ifindex, .flowi6_oif = ub->ifindex,
.daddr = dst->ipv6, .daddr = dst->ipv6,
.saddr = src->ipv6, .saddr = src->ipv6,
.flowi6_proto = IPPROTO_UDP .flowi6_proto = IPPROTO_UDP
}; };
err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst, err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk,
&fl6); &ndst, &fl6);
if (err) if (err)
goto tx_error; goto tx_error;
dst_cache_set_ip6(cache, ndst, &fl6.saddr);
}
ttl = ip6_dst_hoplimit(ndst); ttl = ip6_dst_hoplimit(ndst);
err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
&src->ipv6, &dst->ipv6, 0, ttl, 0, &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) 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 */ /* Replicast, send an skb to each configured IP address */
list_for_each_entry_rcu(rcast, &ub->rcast.list, list) { 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; 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) if (err)
goto out; goto out;
} }
@ -286,6 +296,11 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b,
if (!rcast) if (!rcast)
return -ENOMEM; return -ENOMEM;
if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) {
kfree(rcast);
return -ENOMEM;
}
memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr));
if (ntohs(addr->proto) == ETH_P_IP) 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; tuncfg.encap_destroy = NULL;
setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); 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 * The bcast media address port is used for all peers and the ip
* is used if it's a multicast address. * 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; return 0;
err: err:
dst_cache_destroy(&ub->rcast.dst_cache);
if (ub->ubsock) if (ub->ubsock)
udp_tunnel_sock_release(ub->ubsock); udp_tunnel_sock_release(ub->ubsock);
kfree(ub); kfree(ub);
@ -769,10 +789,12 @@ static void cleanup_bearer(struct work_struct *work)
struct udp_replicast *rcast, *tmp; struct udp_replicast *rcast, *tmp;
list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) {
dst_cache_destroy(&rcast->dst_cache);
list_del_rcu(&rcast->list); list_del_rcu(&rcast->list);
kfree_rcu(rcast, rcu); kfree_rcu(rcast, rcu);
} }
dst_cache_destroy(&ub->rcast.dst_cache);
if (ub->ubsock) if (ub->ubsock)
udp_tunnel_sock_release(ub->ubsock); udp_tunnel_sock_release(ub->ubsock);
synchronize_net(); synchronize_net();