diff options
| -rw-r--r-- | drivers/net/geneve.c | 45 |
1 files changed, 34 insertions, 11 deletions
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 16af1ce99233..42edd7b7902f 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c | |||
| @@ -58,9 +58,9 @@ struct geneve_dev { | |||
| 58 | struct hlist_node hlist; /* vni hash table */ | 58 | struct hlist_node hlist; /* vni hash table */ |
| 59 | struct net *net; /* netns for packet i/o */ | 59 | struct net *net; /* netns for packet i/o */ |
| 60 | struct net_device *dev; /* netdev for geneve tunnel */ | 60 | struct net_device *dev; /* netdev for geneve tunnel */ |
| 61 | struct geneve_sock *sock4; /* IPv4 socket used for geneve tunnel */ | 61 | struct geneve_sock __rcu *sock4; /* IPv4 socket used for geneve tunnel */ |
| 62 | #if IS_ENABLED(CONFIG_IPV6) | 62 | #if IS_ENABLED(CONFIG_IPV6) |
| 63 | struct geneve_sock *sock6; /* IPv6 socket used for geneve tunnel */ | 63 | struct geneve_sock __rcu *sock6; /* IPv6 socket used for geneve tunnel */ |
| 64 | #endif | 64 | #endif |
| 65 | u8 vni[3]; /* virtual network ID for tunnel */ | 65 | u8 vni[3]; /* virtual network ID for tunnel */ |
| 66 | u8 ttl; /* TTL override */ | 66 | u8 ttl; /* TTL override */ |
| @@ -543,9 +543,19 @@ static void __geneve_sock_release(struct geneve_sock *gs) | |||
| 543 | 543 | ||
| 544 | static void geneve_sock_release(struct geneve_dev *geneve) | 544 | static void geneve_sock_release(struct geneve_dev *geneve) |
| 545 | { | 545 | { |
| 546 | __geneve_sock_release(geneve->sock4); | 546 | struct geneve_sock *gs4 = rtnl_dereference(geneve->sock4); |
| 547 | #if IS_ENABLED(CONFIG_IPV6) | 547 | #if IS_ENABLED(CONFIG_IPV6) |
| 548 | __geneve_sock_release(geneve->sock6); | 548 | struct geneve_sock *gs6 = rtnl_dereference(geneve->sock6); |
| 549 | |||
| 550 | rcu_assign_pointer(geneve->sock6, NULL); | ||
| 551 | #endif | ||
| 552 | |||
| 553 | rcu_assign_pointer(geneve->sock4, NULL); | ||
| 554 | synchronize_net(); | ||
| 555 | |||
| 556 | __geneve_sock_release(gs4); | ||
| 557 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 558 | __geneve_sock_release(gs6); | ||
| 549 | #endif | 559 | #endif |
| 550 | } | 560 | } |
| 551 | 561 | ||
| @@ -586,10 +596,10 @@ out: | |||
| 586 | gs->flags = geneve->flags; | 596 | gs->flags = geneve->flags; |
| 587 | #if IS_ENABLED(CONFIG_IPV6) | 597 | #if IS_ENABLED(CONFIG_IPV6) |
| 588 | if (ipv6) | 598 | if (ipv6) |
| 589 | geneve->sock6 = gs; | 599 | rcu_assign_pointer(geneve->sock6, gs); |
| 590 | else | 600 | else |
| 591 | #endif | 601 | #endif |
| 592 | geneve->sock4 = gs; | 602 | rcu_assign_pointer(geneve->sock4, gs); |
| 593 | 603 | ||
| 594 | hash = geneve_net_vni_hash(geneve->vni); | 604 | hash = geneve_net_vni_hash(geneve->vni); |
| 595 | hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]); | 605 | hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]); |
| @@ -603,9 +613,7 @@ static int geneve_open(struct net_device *dev) | |||
| 603 | bool metadata = geneve->collect_md; | 613 | bool metadata = geneve->collect_md; |
| 604 | int ret = 0; | 614 | int ret = 0; |
| 605 | 615 | ||
| 606 | geneve->sock4 = NULL; | ||
| 607 | #if IS_ENABLED(CONFIG_IPV6) | 616 | #if IS_ENABLED(CONFIG_IPV6) |
| 608 | geneve->sock6 = NULL; | ||
| 609 | if (ipv6 || metadata) | 617 | if (ipv6 || metadata) |
| 610 | ret = geneve_sock_add(geneve, true); | 618 | ret = geneve_sock_add(geneve, true); |
| 611 | #endif | 619 | #endif |
| @@ -720,6 +728,9 @@ static struct rtable *geneve_get_v4_rt(struct sk_buff *skb, | |||
| 720 | struct rtable *rt = NULL; | 728 | struct rtable *rt = NULL; |
| 721 | __u8 tos; | 729 | __u8 tos; |
| 722 | 730 | ||
| 731 | if (!rcu_dereference(geneve->sock4)) | ||
| 732 | return ERR_PTR(-EIO); | ||
| 733 | |||
| 723 | memset(fl4, 0, sizeof(*fl4)); | 734 | memset(fl4, 0, sizeof(*fl4)); |
| 724 | fl4->flowi4_mark = skb->mark; | 735 | fl4->flowi4_mark = skb->mark; |
| 725 | fl4->flowi4_proto = IPPROTO_UDP; | 736 | fl4->flowi4_proto = IPPROTO_UDP; |
| @@ -772,11 +783,15 @@ static struct dst_entry *geneve_get_v6_dst(struct sk_buff *skb, | |||
| 772 | { | 783 | { |
| 773 | bool use_cache = ip_tunnel_dst_cache_usable(skb, info); | 784 | bool use_cache = ip_tunnel_dst_cache_usable(skb, info); |
| 774 | struct geneve_dev *geneve = netdev_priv(dev); | 785 | struct geneve_dev *geneve = netdev_priv(dev); |
| 775 | struct geneve_sock *gs6 = geneve->sock6; | ||
| 776 | struct dst_entry *dst = NULL; | 786 | struct dst_entry *dst = NULL; |
| 777 | struct dst_cache *dst_cache; | 787 | struct dst_cache *dst_cache; |
| 788 | struct geneve_sock *gs6; | ||
| 778 | __u8 prio; | 789 | __u8 prio; |
| 779 | 790 | ||
| 791 | gs6 = rcu_dereference(geneve->sock6); | ||
| 792 | if (!gs6) | ||
| 793 | return ERR_PTR(-EIO); | ||
| 794 | |||
| 780 | memset(fl6, 0, sizeof(*fl6)); | 795 | memset(fl6, 0, sizeof(*fl6)); |
| 781 | fl6->flowi6_mark = skb->mark; | 796 | fl6->flowi6_mark = skb->mark; |
| 782 | fl6->flowi6_proto = IPPROTO_UDP; | 797 | fl6->flowi6_proto = IPPROTO_UDP; |
| @@ -842,7 +857,7 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
| 842 | struct ip_tunnel_info *info) | 857 | struct ip_tunnel_info *info) |
| 843 | { | 858 | { |
| 844 | struct geneve_dev *geneve = netdev_priv(dev); | 859 | struct geneve_dev *geneve = netdev_priv(dev); |
| 845 | struct geneve_sock *gs4 = geneve->sock4; | 860 | struct geneve_sock *gs4; |
| 846 | struct rtable *rt = NULL; | 861 | struct rtable *rt = NULL; |
| 847 | const struct iphdr *iip; /* interior IP header */ | 862 | const struct iphdr *iip; /* interior IP header */ |
| 848 | int err = -EINVAL; | 863 | int err = -EINVAL; |
| @@ -853,6 +868,10 @@ static netdev_tx_t geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
| 853 | bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); | 868 | bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); |
| 854 | u32 flags = geneve->flags; | 869 | u32 flags = geneve->flags; |
| 855 | 870 | ||
| 871 | gs4 = rcu_dereference(geneve->sock4); | ||
| 872 | if (!gs4) | ||
| 873 | goto tx_error; | ||
| 874 | |||
| 856 | if (geneve->collect_md) { | 875 | if (geneve->collect_md) { |
| 857 | if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { | 876 | if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { |
| 858 | netdev_dbg(dev, "no tunnel metadata\n"); | 877 | netdev_dbg(dev, "no tunnel metadata\n"); |
| @@ -932,9 +951,9 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
| 932 | struct ip_tunnel_info *info) | 951 | struct ip_tunnel_info *info) |
| 933 | { | 952 | { |
| 934 | struct geneve_dev *geneve = netdev_priv(dev); | 953 | struct geneve_dev *geneve = netdev_priv(dev); |
| 935 | struct geneve_sock *gs6 = geneve->sock6; | ||
| 936 | struct dst_entry *dst = NULL; | 954 | struct dst_entry *dst = NULL; |
| 937 | const struct iphdr *iip; /* interior IP header */ | 955 | const struct iphdr *iip; /* interior IP header */ |
| 956 | struct geneve_sock *gs6; | ||
| 938 | int err = -EINVAL; | 957 | int err = -EINVAL; |
| 939 | struct flowi6 fl6; | 958 | struct flowi6 fl6; |
| 940 | __u8 prio, ttl; | 959 | __u8 prio, ttl; |
| @@ -943,6 +962,10 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev, | |||
| 943 | bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); | 962 | bool xnet = !net_eq(geneve->net, dev_net(geneve->dev)); |
| 944 | u32 flags = geneve->flags; | 963 | u32 flags = geneve->flags; |
| 945 | 964 | ||
| 965 | gs6 = rcu_dereference(geneve->sock6); | ||
| 966 | if (!gs6) | ||
| 967 | goto tx_error; | ||
| 968 | |||
| 946 | if (geneve->collect_md) { | 969 | if (geneve->collect_md) { |
| 947 | if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { | 970 | if (unlikely(!info || !(info->mode & IP_TUNNEL_INFO_TX))) { |
| 948 | netdev_dbg(dev, "no tunnel metadata\n"); | 971 | netdev_dbg(dev, "no tunnel metadata\n"); |
