.. | .. |
---|
44 | 44 | #include <net/sock.h> |
---|
45 | 45 | #include <net/ip.h> |
---|
46 | 46 | #include <net/udp_tunnel.h> |
---|
47 | | -#include <net/addrconf.h> |
---|
| 47 | +#include <net/ipv6_stubs.h> |
---|
48 | 48 | #include <linux/tipc_netlink.h> |
---|
49 | 49 | #include "core.h" |
---|
50 | 50 | #include "addr.h" |
---|
.. | .. |
---|
52 | 52 | #include "bearer.h" |
---|
53 | 53 | #include "netlink.h" |
---|
54 | 54 | #include "msg.h" |
---|
| 55 | +#include "udp_media.h" |
---|
55 | 56 | |
---|
56 | 57 | /* IANA assigned UDP port */ |
---|
57 | 58 | #define UDP_PORT_DEFAULT 6118 |
---|
.. | .. |
---|
76 | 77 | /* struct udp_replicast - container for UDP remote addresses */ |
---|
77 | 78 | struct udp_replicast { |
---|
78 | 79 | struct udp_media_addr addr; |
---|
| 80 | + struct dst_cache dst_cache; |
---|
79 | 81 | struct rcu_head rcu; |
---|
80 | 82 | struct list_head list; |
---|
81 | 83 | }; |
---|
.. | .. |
---|
158 | 160 | /* tipc_send_msg - enqueue a send request */ |
---|
159 | 161 | static int tipc_udp_xmit(struct net *net, struct sk_buff *skb, |
---|
160 | 162 | struct udp_bearer *ub, struct udp_media_addr *src, |
---|
161 | | - struct udp_media_addr *dst) |
---|
| 163 | + struct udp_media_addr *dst, struct dst_cache *cache) |
---|
162 | 164 | { |
---|
| 165 | + struct dst_entry *ndst; |
---|
163 | 166 | int ttl, err = 0; |
---|
164 | | - struct rtable *rt; |
---|
165 | 167 | |
---|
| 168 | + local_bh_disable(); |
---|
| 169 | + ndst = dst_cache_get(cache); |
---|
166 | 170 | if (dst->proto == htons(ETH_P_IP)) { |
---|
167 | | - struct flowi4 fl = { |
---|
168 | | - .daddr = dst->ipv4.s_addr, |
---|
169 | | - .saddr = src->ipv4.s_addr, |
---|
170 | | - .flowi4_mark = skb->mark, |
---|
171 | | - .flowi4_proto = IPPROTO_UDP |
---|
172 | | - }; |
---|
173 | | - rt = ip_route_output_key(net, &fl); |
---|
174 | | - if (IS_ERR(rt)) { |
---|
175 | | - err = PTR_ERR(rt); |
---|
176 | | - goto tx_error; |
---|
| 171 | + struct rtable *rt = (struct rtable *)ndst; |
---|
| 172 | + |
---|
| 173 | + if (!rt) { |
---|
| 174 | + struct flowi4 fl = { |
---|
| 175 | + .daddr = dst->ipv4.s_addr, |
---|
| 176 | + .saddr = src->ipv4.s_addr, |
---|
| 177 | + .flowi4_mark = skb->mark, |
---|
| 178 | + .flowi4_proto = IPPROTO_UDP |
---|
| 179 | + }; |
---|
| 180 | + rt = ip_route_output_key(net, &fl); |
---|
| 181 | + if (IS_ERR(rt)) { |
---|
| 182 | + err = PTR_ERR(rt); |
---|
| 183 | + goto tx_error; |
---|
| 184 | + } |
---|
| 185 | + dst_cache_set_ip4(cache, &rt->dst, fl.saddr); |
---|
177 | 186 | } |
---|
178 | 187 | |
---|
179 | 188 | ttl = ip4_dst_hoplimit(&rt->dst); |
---|
.. | .. |
---|
182 | 191 | dst->port, false, true); |
---|
183 | 192 | #if IS_ENABLED(CONFIG_IPV6) |
---|
184 | 193 | } else { |
---|
185 | | - struct dst_entry *ndst; |
---|
186 | | - struct flowi6 fl6 = { |
---|
187 | | - .flowi6_oif = ub->ifindex, |
---|
188 | | - .daddr = dst->ipv6, |
---|
189 | | - .saddr = src->ipv6, |
---|
190 | | - .flowi6_proto = IPPROTO_UDP |
---|
191 | | - }; |
---|
192 | | - ndst = ipv6_stub->ipv6_dst_lookup_flow(net, |
---|
193 | | - ub->ubsock->sk, |
---|
194 | | - &fl6, NULL); |
---|
195 | | - if (IS_ERR(ndst)) { |
---|
196 | | - err = PTR_ERR(ndst); |
---|
197 | | - goto tx_error; |
---|
| 194 | + if (!ndst) { |
---|
| 195 | + struct flowi6 fl6 = { |
---|
| 196 | + .flowi6_oif = ub->ifindex, |
---|
| 197 | + .daddr = dst->ipv6, |
---|
| 198 | + .saddr = src->ipv6, |
---|
| 199 | + .flowi6_proto = IPPROTO_UDP |
---|
| 200 | + }; |
---|
| 201 | + ndst = ipv6_stub->ipv6_dst_lookup_flow(net, |
---|
| 202 | + ub->ubsock->sk, |
---|
| 203 | + &fl6, NULL); |
---|
| 204 | + if (IS_ERR(ndst)) { |
---|
| 205 | + err = PTR_ERR(ndst); |
---|
| 206 | + goto tx_error; |
---|
| 207 | + } |
---|
| 208 | + dst_cache_set_ip6(cache, ndst, &fl6.saddr); |
---|
198 | 209 | } |
---|
199 | 210 | ttl = ip6_dst_hoplimit(ndst); |
---|
200 | 211 | err = udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL, |
---|
.. | .. |
---|
202 | 213 | src->port, dst->port, false); |
---|
203 | 214 | #endif |
---|
204 | 215 | } |
---|
| 216 | + local_bh_enable(); |
---|
205 | 217 | return err; |
---|
206 | 218 | |
---|
207 | 219 | tx_error: |
---|
| 220 | + local_bh_enable(); |
---|
208 | 221 | kfree_skb(skb); |
---|
209 | 222 | return err; |
---|
210 | 223 | } |
---|
.. | .. |
---|
226 | 239 | } |
---|
227 | 240 | |
---|
228 | 241 | skb_set_inner_protocol(skb, htons(ETH_P_TIPC)); |
---|
229 | | - ub = rcu_dereference_rtnl(b->media_ptr); |
---|
| 242 | + ub = rcu_dereference(b->media_ptr); |
---|
230 | 243 | if (!ub) { |
---|
231 | 244 | err = -ENODEV; |
---|
232 | 245 | goto out; |
---|
233 | 246 | } |
---|
234 | 247 | |
---|
235 | 248 | if (addr->broadcast != TIPC_REPLICAST_SUPPORT) |
---|
236 | | - return tipc_udp_xmit(net, skb, ub, src, dst); |
---|
| 249 | + return tipc_udp_xmit(net, skb, ub, src, dst, |
---|
| 250 | + &ub->rcast.dst_cache); |
---|
237 | 251 | |
---|
238 | 252 | /* Replicast, send an skb to each configured IP address */ |
---|
239 | 253 | list_for_each_entry_rcu(rcast, &ub->rcast.list, list) { |
---|
.. | .. |
---|
245 | 259 | goto out; |
---|
246 | 260 | } |
---|
247 | 261 | |
---|
248 | | - err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr); |
---|
| 262 | + err = tipc_udp_xmit(net, _skb, ub, src, &rcast->addr, |
---|
| 263 | + &rcast->dst_cache); |
---|
249 | 264 | if (err) |
---|
250 | 265 | goto out; |
---|
251 | 266 | } |
---|
.. | .. |
---|
288 | 303 | rcast = kmalloc(sizeof(*rcast), GFP_ATOMIC); |
---|
289 | 304 | if (!rcast) |
---|
290 | 305 | return -ENOMEM; |
---|
| 306 | + |
---|
| 307 | + if (dst_cache_init(&rcast->dst_cache, GFP_ATOMIC)) { |
---|
| 308 | + kfree(rcast); |
---|
| 309 | + return -ENOMEM; |
---|
| 310 | + } |
---|
291 | 311 | |
---|
292 | 312 | memcpy(&rcast->addr, addr, sizeof(struct udp_media_addr)); |
---|
293 | 313 | |
---|
.. | .. |
---|
355 | 375 | skb_pull(skb, sizeof(struct udphdr)); |
---|
356 | 376 | hdr = buf_msg(skb); |
---|
357 | 377 | |
---|
358 | | - rcu_read_lock(); |
---|
359 | | - b = rcu_dereference_rtnl(ub->bearer); |
---|
| 378 | + b = rcu_dereference(ub->bearer); |
---|
360 | 379 | if (!b) |
---|
361 | | - goto rcu_out; |
---|
| 380 | + goto out; |
---|
362 | 381 | |
---|
363 | 382 | if (b && test_bit(0, &b->up)) { |
---|
| 383 | + TIPC_SKB_CB(skb)->flags = 0; |
---|
364 | 384 | tipc_rcv(sock_net(sk), skb, b); |
---|
365 | | - rcu_read_unlock(); |
---|
366 | 385 | return 0; |
---|
367 | 386 | } |
---|
368 | 387 | |
---|
369 | 388 | if (unlikely(msg_user(hdr) == LINK_CONFIG)) { |
---|
370 | 389 | err = tipc_udp_rcast_disc(b, skb); |
---|
371 | 390 | if (err) |
---|
372 | | - goto rcu_out; |
---|
| 391 | + goto out; |
---|
373 | 392 | } |
---|
374 | 393 | |
---|
375 | | -rcu_out: |
---|
376 | | - rcu_read_unlock(); |
---|
377 | 394 | out: |
---|
378 | 395 | kfree_skb(skb); |
---|
379 | 396 | return 0; |
---|
.. | .. |
---|
440 | 457 | int i; |
---|
441 | 458 | |
---|
442 | 459 | if (!bid && !skip_cnt) { |
---|
| 460 | + struct nlattr **attrs = genl_dumpit_info(cb)->attrs; |
---|
443 | 461 | struct net *net = sock_net(skb->sk); |
---|
444 | 462 | struct nlattr *battrs[TIPC_NLA_BEARER_MAX + 1]; |
---|
445 | | - struct nlattr **attrs; |
---|
446 | 463 | char *bname; |
---|
447 | | - |
---|
448 | | - err = tipc_nlmsg_parse(cb->nlh, &attrs); |
---|
449 | | - if (err) |
---|
450 | | - return err; |
---|
451 | 464 | |
---|
452 | 465 | if (!attrs[TIPC_NLA_BEARER]) |
---|
453 | 466 | return -EINVAL; |
---|
454 | 467 | |
---|
455 | | - err = nla_parse_nested(battrs, TIPC_NLA_BEARER_MAX, |
---|
456 | | - attrs[TIPC_NLA_BEARER], |
---|
457 | | - tipc_nl_bearer_policy, NULL); |
---|
| 468 | + err = nla_parse_nested_deprecated(battrs, TIPC_NLA_BEARER_MAX, |
---|
| 469 | + attrs[TIPC_NLA_BEARER], |
---|
| 470 | + tipc_nl_bearer_policy, NULL); |
---|
458 | 471 | if (err) |
---|
459 | 472 | return err; |
---|
460 | 473 | |
---|
.. | .. |
---|
482 | 495 | } |
---|
483 | 496 | } |
---|
484 | 497 | |
---|
485 | | - ub = rcu_dereference_rtnl(b->media_ptr); |
---|
| 498 | + ub = rtnl_dereference(b->media_ptr); |
---|
486 | 499 | if (!ub) { |
---|
487 | 500 | rtnl_unlock(); |
---|
488 | 501 | return -EINVAL; |
---|
.. | .. |
---|
524 | 537 | struct udp_bearer *ub; |
---|
525 | 538 | struct nlattr *nest; |
---|
526 | 539 | |
---|
527 | | - ub = rcu_dereference_rtnl(b->media_ptr); |
---|
| 540 | + ub = rtnl_dereference(b->media_ptr); |
---|
528 | 541 | if (!ub) |
---|
529 | 542 | return -ENODEV; |
---|
530 | 543 | |
---|
531 | | - nest = nla_nest_start(msg->skb, TIPC_NLA_BEARER_UDP_OPTS); |
---|
| 544 | + nest = nla_nest_start_noflag(msg->skb, TIPC_NLA_BEARER_UDP_OPTS); |
---|
532 | 545 | if (!nest) |
---|
533 | 546 | goto msg_full; |
---|
534 | 547 | |
---|
.. | .. |
---|
553 | 566 | |
---|
554 | 567 | /** |
---|
555 | 568 | * tipc_parse_udp_addr - build udp media address from netlink data |
---|
556 | | - * @nlattr: netlink attribute containing sockaddr storage aligned address |
---|
| 569 | + * @nla: netlink attribute containing sockaddr storage aligned address |
---|
557 | 570 | * @addr: tipc media address to fill with address, port and protocol type |
---|
558 | 571 | * @scope_id: IPv6 scope id pointer, not NULL indicates it's required |
---|
559 | 572 | */ |
---|
.. | .. |
---|
606 | 619 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; |
---|
607 | 620 | struct udp_media_addr *dst; |
---|
608 | 621 | |
---|
609 | | - if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, attr, |
---|
610 | | - tipc_nl_udp_policy, NULL)) |
---|
| 622 | + if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attr, tipc_nl_udp_policy, NULL)) |
---|
611 | 623 | return -EINVAL; |
---|
612 | 624 | |
---|
613 | 625 | if (!opts[TIPC_NLA_UDP_REMOTE]) |
---|
.. | .. |
---|
649 | 661 | struct udp_tunnel_sock_cfg tuncfg = {NULL}; |
---|
650 | 662 | struct nlattr *opts[TIPC_NLA_UDP_MAX + 1]; |
---|
651 | 663 | u8 node_id[NODE_ID_LEN] = {0,}; |
---|
| 664 | + struct net_device *dev; |
---|
| 665 | + int rmcast = 0; |
---|
652 | 666 | |
---|
653 | 667 | ub = kzalloc(sizeof(*ub), GFP_ATOMIC); |
---|
654 | 668 | if (!ub) |
---|
.. | .. |
---|
659 | 673 | if (!attrs[TIPC_NLA_BEARER_UDP_OPTS]) |
---|
660 | 674 | goto err; |
---|
661 | 675 | |
---|
662 | | - if (nla_parse_nested(opts, TIPC_NLA_UDP_MAX, |
---|
663 | | - attrs[TIPC_NLA_BEARER_UDP_OPTS], |
---|
664 | | - tipc_nl_udp_policy, NULL)) |
---|
| 676 | + if (nla_parse_nested_deprecated(opts, TIPC_NLA_UDP_MAX, attrs[TIPC_NLA_BEARER_UDP_OPTS], tipc_nl_udp_policy, NULL)) |
---|
665 | 677 | goto err; |
---|
666 | 678 | |
---|
667 | 679 | if (!opts[TIPC_NLA_UDP_LOCAL] || !opts[TIPC_NLA_UDP_REMOTE]) { |
---|
.. | .. |
---|
684 | 696 | goto err; |
---|
685 | 697 | } |
---|
686 | 698 | |
---|
| 699 | + /* Checking remote ip address */ |
---|
| 700 | + rmcast = tipc_udp_is_mcast_addr(&remote); |
---|
| 701 | + |
---|
687 | 702 | /* Autoconfigure own node identity if needed */ |
---|
688 | 703 | if (!tipc_own_id(net)) { |
---|
689 | 704 | memcpy(node_id, local.ipv6.in6_u.u6_addr8, 16); |
---|
.. | .. |
---|
701 | 716 | rcu_assign_pointer(ub->bearer, b); |
---|
702 | 717 | tipc_udp_media_addr_set(&b->addr, &local); |
---|
703 | 718 | if (local.proto == htons(ETH_P_IP)) { |
---|
704 | | - struct net_device *dev; |
---|
705 | | - |
---|
706 | 719 | dev = __ip_dev_find(net, local.ipv4.s_addr, false); |
---|
707 | 720 | if (!dev) { |
---|
708 | 721 | err = -ENODEV; |
---|
709 | 722 | goto err; |
---|
710 | 723 | } |
---|
711 | 724 | udp_conf.family = AF_INET; |
---|
712 | | - udp_conf.local_ip.s_addr = htonl(INADDR_ANY); |
---|
| 725 | + |
---|
| 726 | + /* Switch to use ANY to receive packets from group */ |
---|
| 727 | + if (rmcast) |
---|
| 728 | + udp_conf.local_ip.s_addr = htonl(INADDR_ANY); |
---|
| 729 | + else |
---|
| 730 | + udp_conf.local_ip.s_addr = local.ipv4.s_addr; |
---|
713 | 731 | udp_conf.use_udp_checksums = false; |
---|
714 | 732 | ub->ifindex = dev->ifindex; |
---|
715 | 733 | if (tipc_mtu_bad(dev, sizeof(struct iphdr) + |
---|
.. | .. |
---|
720 | 738 | b->mtu = b->media->mtu; |
---|
721 | 739 | #if IS_ENABLED(CONFIG_IPV6) |
---|
722 | 740 | } else if (local.proto == htons(ETH_P_IPV6)) { |
---|
| 741 | + dev = ub->ifindex ? __dev_get_by_index(net, ub->ifindex) : NULL; |
---|
| 742 | + dev = ipv6_dev_find(net, &local.ipv6, dev); |
---|
| 743 | + if (!dev) { |
---|
| 744 | + err = -ENODEV; |
---|
| 745 | + goto err; |
---|
| 746 | + } |
---|
723 | 747 | udp_conf.family = AF_INET6; |
---|
724 | 748 | udp_conf.use_udp6_tx_checksums = true; |
---|
725 | 749 | udp_conf.use_udp6_rx_checksums = true; |
---|
726 | | - udp_conf.local_ip6 = in6addr_any; |
---|
| 750 | + if (rmcast) |
---|
| 751 | + udp_conf.local_ip6 = in6addr_any; |
---|
| 752 | + else |
---|
| 753 | + udp_conf.local_ip6 = local.ipv6; |
---|
| 754 | + ub->ifindex = dev->ifindex; |
---|
727 | 755 | b->mtu = 1280; |
---|
728 | 756 | #endif |
---|
729 | 757 | } else { |
---|
.. | .. |
---|
740 | 768 | tuncfg.encap_destroy = NULL; |
---|
741 | 769 | setup_udp_tunnel_sock(net, ub->ubsock, &tuncfg); |
---|
742 | 770 | |
---|
| 771 | + err = dst_cache_init(&ub->rcast.dst_cache, GFP_ATOMIC); |
---|
| 772 | + if (err) |
---|
| 773 | + goto free; |
---|
| 774 | + |
---|
743 | 775 | /** |
---|
744 | 776 | * The bcast media address port is used for all peers and the ip |
---|
745 | 777 | * is used if it's a multicast address. |
---|
746 | 778 | */ |
---|
747 | 779 | memcpy(&b->bcast_addr.value, &remote, sizeof(remote)); |
---|
748 | | - if (tipc_udp_is_mcast_addr(&remote)) |
---|
| 780 | + if (rmcast) |
---|
749 | 781 | err = enable_mcast(ub, &remote); |
---|
750 | 782 | else |
---|
751 | 783 | err = tipc_udp_rcast_add(b, &remote); |
---|
752 | 784 | if (err) |
---|
753 | | - goto err; |
---|
| 785 | + goto free; |
---|
754 | 786 | |
---|
755 | 787 | return 0; |
---|
| 788 | + |
---|
| 789 | +free: |
---|
| 790 | + dst_cache_destroy(&ub->rcast.dst_cache); |
---|
| 791 | + udp_tunnel_sock_release(ub->ubsock); |
---|
756 | 792 | err: |
---|
757 | | - if (ub->ubsock) |
---|
758 | | - udp_tunnel_sock_release(ub->ubsock); |
---|
759 | 793 | kfree(ub); |
---|
760 | 794 | return err; |
---|
761 | 795 | } |
---|
.. | .. |
---|
767 | 801 | struct udp_replicast *rcast, *tmp; |
---|
768 | 802 | |
---|
769 | 803 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
---|
| 804 | + dst_cache_destroy(&rcast->dst_cache); |
---|
770 | 805 | list_del_rcu(&rcast->list); |
---|
771 | 806 | kfree_rcu(rcast, rcu); |
---|
772 | 807 | } |
---|
773 | 808 | |
---|
774 | | - if (ub->ubsock) |
---|
775 | | - udp_tunnel_sock_release(ub->ubsock); |
---|
| 809 | + atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); |
---|
| 810 | + dst_cache_destroy(&ub->rcast.dst_cache); |
---|
| 811 | + udp_tunnel_sock_release(ub->ubsock); |
---|
776 | 812 | synchronize_net(); |
---|
777 | 813 | kfree(ub); |
---|
778 | 814 | } |
---|
.. | .. |
---|
782 | 818 | { |
---|
783 | 819 | struct udp_bearer *ub; |
---|
784 | 820 | |
---|
785 | | - ub = rcu_dereference_rtnl(b->media_ptr); |
---|
| 821 | + ub = rtnl_dereference(b->media_ptr); |
---|
786 | 822 | if (!ub) { |
---|
787 | 823 | pr_err("UDP bearer instance not found\n"); |
---|
788 | 824 | return; |
---|
789 | 825 | } |
---|
790 | | - if (ub->ubsock) |
---|
791 | | - sock_set_flag(ub->ubsock->sk, SOCK_DEAD); |
---|
| 826 | + sock_set_flag(ub->ubsock->sk, SOCK_DEAD); |
---|
792 | 827 | RCU_INIT_POINTER(ub->bearer, NULL); |
---|
793 | 828 | |
---|
794 | 829 | /* sock_release need to be done outside of rtnl lock */ |
---|
| 830 | + atomic_inc(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); |
---|
795 | 831 | INIT_WORK(&ub->work, cleanup_bearer); |
---|
796 | 832 | schedule_work(&ub->work); |
---|
797 | 833 | } |
---|
.. | .. |
---|
805 | 841 | .msg2addr = tipc_udp_msg2addr, |
---|
806 | 842 | .priority = TIPC_DEF_LINK_PRI, |
---|
807 | 843 | .tolerance = TIPC_DEF_LINK_TOL, |
---|
808 | | - .window = TIPC_DEF_LINK_WIN, |
---|
| 844 | + .min_win = TIPC_DEF_LINK_WIN, |
---|
| 845 | + .max_win = TIPC_DEF_LINK_WIN, |
---|
809 | 846 | .mtu = TIPC_DEF_LINK_UDP_MTU, |
---|
810 | 847 | .type_id = TIPC_MEDIA_TYPE_UDP, |
---|
811 | 848 | .hwaddr_len = 0, |
---|