diff options
author | Xin Long <lucien.xin@gmail.com> | 2019-06-20 07:03:41 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-28 01:36:57 -0400 |
commit | e9c1a793210f29f32ee4cf048e04d7d9bb3221cc (patch) | |
tree | c210981a6790a78bd55d46ff126d8d8db3e983ef /net/tipc | |
parent | d96ff269a04be286989ead13bf8b4be55bdee8ee (diff) |
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>
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/udp_media.c | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 1405ccc9101c..b8962df07d36 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c | |||
@@ -76,6 +76,7 @@ struct udp_media_addr { | |||
76 | /* struct udp_replicast - container for UDP remote addresses */ | 76 | /* struct udp_replicast - container for UDP remote addresses */ |
77 | struct udp_replicast { | 77 | struct udp_replicast { |
78 | struct udp_media_addr addr; | 78 | struct udp_media_addr addr; |
79 | struct dst_cache dst_cache; | ||
79 | struct rcu_head rcu; | 80 | struct rcu_head rcu; |
80 | struct list_head list; | 81 | struct list_head list; |
81 | }; | 82 | }; |
@@ -158,22 +159,27 @@ static int tipc_udp_addr2msg(char *msg, struct tipc_media_addr *a) | |||
158 | /* tipc_send_msg - enqueue a send request */ | 159 | /* tipc_send_msg - enqueue a send request */ |
159 | static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, | 160 | static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, |
160 | struct udp_bearer *ub, struct udp_media_addr *src, | 161 | struct udp_bearer *ub, struct udp_media_addr *src, |
161 | struct udp_media_addr *dst) | 162 | struct udp_media_addr *dst, struct dst_cache *cache) |
162 | { | 163 | { |
164 | struct dst_entry *ndst = dst_cache_get(cache); | ||
163 | int ttl, err = 0; | 165 | int ttl, err = 0; |
164 | struct rtable *rt; | ||
165 | 166 | ||
166 | if (dst->proto == htons(ETH_P_IP)) { | 167 | if (dst->proto == htons(ETH_P_IP)) { |
167 | struct flowi4 fl = { | 168 | struct rtable *rt = (struct rtable *)ndst; |
168 | .daddr = dst->ipv4.s_addr, | 169 | |
169 | .saddr = src->ipv4.s_addr, | 170 | if (!rt) { |
170 | .flowi4_mark = skb->mark, | 171 | struct flowi4 fl = { |
171 | .flowi4_proto = IPPROTO_UDP | 172 | .daddr = dst->ipv4.s_addr, |
172 | }; | 173 | .saddr = src->ipv4.s_addr, |
173 | rt = ip_route_output_key(net, &fl); | 174 | .flowi4_mark = skb->mark, |
174 | if (IS_ERR(rt)) { | 175 | .flowi4_proto = IPPROTO_UDP |
175 | err = PTR_ERR(rt); | 176 | }; |
176 | goto tx_error; | 177 | rt = ip_route_output_key(net, &fl); |
178 | if (IS_ERR(rt)) { | ||
179 | err = PTR_ERR(rt); | ||
180 | goto tx_error; | ||
181 | } | ||
182 | dst_cache_set_ip4(cache, &rt->dst, fl.saddr); | ||
177 | } | 183 | } |
178 | 184 | ||
179 | ttl = ip4_dst_hoplimit(&rt->dst); | 185 | ttl = ip4_dst_hoplimit(&rt->dst); |
@@ -182,17 +188,19 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, | |||
182 | dst->port, false, true); | 188 | dst->port, false, true); |
183 | #if IS_ENABLED(CONFIG_IPV6) | 189 | #if IS_ENABLED(CONFIG_IPV6) |
184 | } else { | 190 | } else { |
185 | struct dst_entry *ndst; | 191 | if (!ndst) { |
186 | struct flowi6 fl6 = { | 192 | struct flowi6 fl6 = { |
187 | .flowi6_oif = ub->ifindex, | 193 | .flowi6_oif = ub->ifindex, |
188 | .daddr = dst->ipv6, | 194 | .daddr = dst->ipv6, |
189 | .saddr = src->ipv6, | 195 | .saddr = src->ipv6, |
190 | .flowi6_proto = IPPROTO_UDP | 196 | .flowi6_proto = IPPROTO_UDP |
191 | }; | 197 | }; |
192 | err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, &ndst, | 198 | err = ipv6_stub->ipv6_dst_lookup(net, ub->ubsock->sk, |
193 | &fl6); | 199 | &ndst, &fl6); |
194 | if (err) | 200 | if (err) |
195 | goto tx_error; | 201 | goto tx_error; |
202 | dst_cache_set_ip6(cache, ndst, &fl6.saddr); | ||
203 | } | ||
196 | ttl = ip6_dst_hoplimit(ndst); | 204 | ttl = ip6_dst_hoplimit(ndst); |
197 | err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, | 205 | err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, |
198 | &src->ipv6, &dst->ipv6, 0, ttl, 0, | 206 | &src->ipv6, &dst->ipv6, 0, ttl, 0, |
@@ -230,7 +238,8 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb, | |||
230 | } | 238 | } |
231 | 239 | ||
232 | if (addr->broadcast != TIPC_REPLICAST_SUPPORT) | 240 | if (addr->broadcast != TIPC_REPLICAST_SUPPORT) |
233 | return tipc_udp_xmit(net, skb, ub, src, dst); | 241 | return tipc_udp_xmit(net, skb, ub, src, dst, |
242 | &ub->rcast.dst_cache); | ||
234 | 243 | ||
235 | /* Replicast, send an skb to each configured IP address */ | 244 | /* Replicast, send an skb to each configured IP address */ |
236 | list_for_each_entry_rcu(rcast, &ub->rcast.list, list) { | 245 | 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, | |||
242 | goto out; | 251 | goto out; |
243 | } | 252 | } |
244 | 253 | ||
245 | err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr); | 254 | err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr, |
255 | &rcast->dst_cache); | ||
246 | if (err) | 256 | if (err) |
247 | goto out; | 257 | goto out; |
248 | } | 258 | } |
@@ -286,6 +296,11 @@ static int tipc_udp_rcast_add(struct tipc_bearer *b, | |||
286 | if (!rcast) | 296 | if (!rcast) |
287 | return -ENOMEM; | 297 | return -ENOMEM; |
288 | 298 | ||
299 | if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) { | ||
300 | kfree(rcast); | ||
301 | return -ENOMEM; | ||
302 | } | ||
303 | |||
289 | memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); | 304 | memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); |
290 | 305 | ||
291 | if (ntohs(addr->proto) == ETH_P_IP) | 306 | if (ntohs(addr->proto) == ETH_P_IP) |
@@ -742,6 +757,10 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
742 | tuncfg.encap_destroy = NULL; | 757 | tuncfg.encap_destroy = NULL; |
743 | setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); | 758 | setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); |
744 | 759 | ||
760 | err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC); | ||
761 | if (err) | ||
762 | goto err; | ||
763 | |||
745 | /** | 764 | /** |
746 | * The bcast media address port is used for all peers and the ip | 765 | * The bcast media address port is used for all peers and the ip |
747 | * is used if it's a multicast address. | 766 | * is used if it's a multicast address. |
@@ -756,6 +775,7 @@ static int tipc_udp_enable(struct net *net, struct tipc_bearer *b, | |||
756 | 775 | ||
757 | return 0; | 776 | return 0; |
758 | err: | 777 | err: |
778 | dst_cache_destroy(&ub->rcast.dst_cache); | ||
759 | if (ub->ubsock) | 779 | if (ub->ubsock) |
760 | udp_tunnel_sock_release(ub->ubsock); | 780 | udp_tunnel_sock_release(ub->ubsock); |
761 | kfree(ub); | 781 | kfree(ub); |
@@ -769,10 +789,12 @@ static void cleanup_bearer(struct work_struct *work) | |||
769 | struct udp_replicast *rcast, *tmp; | 789 | struct udp_replicast *rcast, *tmp; |
770 | 790 | ||
771 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { | 791 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
792 | dst_cache_destroy(&rcast->dst_cache); | ||
772 | list_del_rcu(&rcast->list); | 793 | list_del_rcu(&rcast->list); |
773 | kfree_rcu(rcast, rcu); | 794 | kfree_rcu(rcast, rcu); |
774 | } | 795 | } |
775 | 796 | ||
797 | dst_cache_destroy(&ub->rcast.dst_cache); | ||
776 | if (ub->ubsock) | 798 | if (ub->ubsock) |
777 | udp_tunnel_sock_release(ub->ubsock); | 799 | udp_tunnel_sock_release(ub->ubsock); |
778 | synchronize_net(); | 800 | synchronize_net(); |