forked from luck/tmp_suning_uos_patched
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:
parent
d96ff269a0
commit
e9c1a79321
|
@ -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,22 +159,27 @@ 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 flowi4 fl = {
|
struct rtable *rt = (struct rtable *)ndst;
|
||||||
.daddr = dst->ipv4.s_addr,
|
|
||||||
.saddr = src->ipv4.s_addr,
|
if (!rt) {
|
||||||
.flowi4_mark = skb->mark,
|
struct flowi4 fl = {
|
||||||
.flowi4_proto = IPPROTO_UDP
|
.daddr = dst->ipv4.s_addr,
|
||||||
};
|
.saddr = src->ipv4.s_addr,
|
||||||
rt = ip_route_output_key(net, &fl);
|
.flowi4_mark = skb->mark,
|
||||||
if (IS_ERR(rt)) {
|
.flowi4_proto = IPPROTO_UDP
|
||||||
err = PTR_ERR(rt);
|
};
|
||||||
goto tx_error;
|
rt = ip_route_output_key(net, &fl);
|
||||||
|
if (IS_ERR(rt)) {
|
||||||
|
err = PTR_ERR(rt);
|
||||||
|
goto tx_error;
|
||||||
|
}
|
||||||
|
dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ttl = ip4_dst_hoplimit(&rt->dst);
|
ttl = ip4_dst_hoplimit(&rt->dst);
|
||||||
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user