diff options
Diffstat (limited to 'drivers/net/ipvlan')
| -rw-r--r-- | drivers/net/ipvlan/ipvlan_core.c | 72 | ||||
| -rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 48 |
2 files changed, 85 insertions, 35 deletions
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index c1f008fe4e1d..1b5dc200b573 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c | |||
| @@ -35,6 +35,7 @@ void ipvlan_count_rx(const struct ipvl_dev *ipvlan, | |||
| 35 | } | 35 | } |
| 36 | EXPORT_SYMBOL_GPL(ipvlan_count_rx); | 36 | EXPORT_SYMBOL_GPL(ipvlan_count_rx); |
| 37 | 37 | ||
| 38 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 38 | static u8 ipvlan_get_v6_hash(const void *iaddr) | 39 | static u8 ipvlan_get_v6_hash(const void *iaddr) |
| 39 | { | 40 | { |
| 40 | const struct in6_addr *ip6_addr = iaddr; | 41 | const struct in6_addr *ip6_addr = iaddr; |
| @@ -42,6 +43,12 @@ static u8 ipvlan_get_v6_hash(const void *iaddr) | |||
| 42 | return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) & | 43 | return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) & |
| 43 | IPVLAN_HASH_MASK; | 44 | IPVLAN_HASH_MASK; |
| 44 | } | 45 | } |
| 46 | #else | ||
| 47 | static u8 ipvlan_get_v6_hash(const void *iaddr) | ||
| 48 | { | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | #endif | ||
| 45 | 52 | ||
| 46 | static u8 ipvlan_get_v4_hash(const void *iaddr) | 53 | static u8 ipvlan_get_v4_hash(const void *iaddr) |
| 47 | { | 54 | { |
| @@ -51,6 +58,23 @@ static u8 ipvlan_get_v4_hash(const void *iaddr) | |||
| 51 | IPVLAN_HASH_MASK; | 58 | IPVLAN_HASH_MASK; |
| 52 | } | 59 | } |
| 53 | 60 | ||
| 61 | static bool addr_equal(bool is_v6, struct ipvl_addr *addr, const void *iaddr) | ||
| 62 | { | ||
| 63 | if (!is_v6 && addr->atype == IPVL_IPV4) { | ||
| 64 | struct in_addr *i4addr = (struct in_addr *)iaddr; | ||
| 65 | |||
| 66 | return addr->ip4addr.s_addr == i4addr->s_addr; | ||
| 67 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 68 | } else if (is_v6 && addr->atype == IPVL_IPV6) { | ||
| 69 | struct in6_addr *i6addr = (struct in6_addr *)iaddr; | ||
| 70 | |||
| 71 | return ipv6_addr_equal(&addr->ip6addr, i6addr); | ||
| 72 | #endif | ||
| 73 | } | ||
| 74 | |||
| 75 | return false; | ||
| 76 | } | ||
| 77 | |||
| 54 | static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, | 78 | static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, |
| 55 | const void *iaddr, bool is_v6) | 79 | const void *iaddr, bool is_v6) |
| 56 | { | 80 | { |
| @@ -59,15 +83,9 @@ static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, | |||
| 59 | 83 | ||
| 60 | hash = is_v6 ? ipvlan_get_v6_hash(iaddr) : | 84 | hash = is_v6 ? ipvlan_get_v6_hash(iaddr) : |
| 61 | ipvlan_get_v4_hash(iaddr); | 85 | ipvlan_get_v4_hash(iaddr); |
| 62 | hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) { | 86 | hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) |
| 63 | if (is_v6 && addr->atype == IPVL_IPV6 && | 87 | if (addr_equal(is_v6, addr, iaddr)) |
| 64 | ipv6_addr_equal(&addr->ip6addr, iaddr)) | ||
| 65 | return addr; | ||
| 66 | else if (!is_v6 && addr->atype == IPVL_IPV4 && | ||
| 67 | addr->ip4addr.s_addr == | ||
| 68 | ((struct in_addr *)iaddr)->s_addr) | ||
| 69 | return addr; | 88 | return addr; |
| 70 | } | ||
| 71 | return NULL; | 89 | return NULL; |
| 72 | } | 90 | } |
| 73 | 91 | ||
| @@ -93,13 +111,9 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan, | |||
| 93 | { | 111 | { |
| 94 | struct ipvl_addr *addr; | 112 | struct ipvl_addr *addr; |
| 95 | 113 | ||
| 96 | list_for_each_entry(addr, &ipvlan->addrs, anode) { | 114 | list_for_each_entry(addr, &ipvlan->addrs, anode) |
| 97 | if ((is_v6 && addr->atype == IPVL_IPV6 && | 115 | if (addr_equal(is_v6, addr, iaddr)) |
| 98 | ipv6_addr_equal(&addr->ip6addr, iaddr)) || | ||
| 99 | (!is_v6 && addr->atype == IPVL_IPV4 && | ||
| 100 | addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr)) | ||
| 101 | return addr; | 116 | return addr; |
| 102 | } | ||
| 103 | return NULL; | 117 | return NULL; |
| 104 | } | 118 | } |
| 105 | 119 | ||
| @@ -150,6 +164,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int | |||
| 150 | lyr3h = ip4h; | 164 | lyr3h = ip4h; |
| 151 | break; | 165 | break; |
| 152 | } | 166 | } |
| 167 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 153 | case htons(ETH_P_IPV6): { | 168 | case htons(ETH_P_IPV6): { |
| 154 | struct ipv6hdr *ip6h; | 169 | struct ipv6hdr *ip6h; |
| 155 | 170 | ||
| @@ -188,6 +203,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int | |||
| 188 | } | 203 | } |
| 189 | break; | 204 | break; |
| 190 | } | 205 | } |
| 206 | #endif | ||
| 191 | default: | 207 | default: |
| 192 | return NULL; | 208 | return NULL; |
| 193 | } | 209 | } |
| @@ -337,14 +353,18 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, | |||
| 337 | { | 353 | { |
| 338 | struct ipvl_addr *addr = NULL; | 354 | struct ipvl_addr *addr = NULL; |
| 339 | 355 | ||
| 340 | if (addr_type == IPVL_IPV6) { | 356 | switch (addr_type) { |
| 357 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 358 | case IPVL_IPV6: { | ||
| 341 | struct ipv6hdr *ip6h; | 359 | struct ipv6hdr *ip6h; |
| 342 | struct in6_addr *i6addr; | 360 | struct in6_addr *i6addr; |
| 343 | 361 | ||
| 344 | ip6h = (struct ipv6hdr *)lyr3h; | 362 | ip6h = (struct ipv6hdr *)lyr3h; |
| 345 | i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr; | 363 | i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr; |
| 346 | addr = ipvlan_ht_addr_lookup(port, i6addr, true); | 364 | addr = ipvlan_ht_addr_lookup(port, i6addr, true); |
| 347 | } else if (addr_type == IPVL_ICMPV6) { | 365 | break; |
| 366 | } | ||
| 367 | case IPVL_ICMPV6: { | ||
| 348 | struct nd_msg *ndmh; | 368 | struct nd_msg *ndmh; |
| 349 | struct in6_addr *i6addr; | 369 | struct in6_addr *i6addr; |
| 350 | 370 | ||
| @@ -356,14 +376,19 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, | |||
| 356 | i6addr = &ndmh->target; | 376 | i6addr = &ndmh->target; |
| 357 | addr = ipvlan_ht_addr_lookup(port, i6addr, true); | 377 | addr = ipvlan_ht_addr_lookup(port, i6addr, true); |
| 358 | } | 378 | } |
| 359 | } else if (addr_type == IPVL_IPV4) { | 379 | break; |
| 380 | } | ||
| 381 | #endif | ||
| 382 | case IPVL_IPV4: { | ||
| 360 | struct iphdr *ip4h; | 383 | struct iphdr *ip4h; |
| 361 | __be32 *i4addr; | 384 | __be32 *i4addr; |
| 362 | 385 | ||
| 363 | ip4h = (struct iphdr *)lyr3h; | 386 | ip4h = (struct iphdr *)lyr3h; |
| 364 | i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr; | 387 | i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr; |
| 365 | addr = ipvlan_ht_addr_lookup(port, i4addr, false); | 388 | addr = ipvlan_ht_addr_lookup(port, i4addr, false); |
| 366 | } else if (addr_type == IPVL_ARP) { | 389 | break; |
| 390 | } | ||
| 391 | case IPVL_ARP: { | ||
| 367 | struct arphdr *arph; | 392 | struct arphdr *arph; |
| 368 | unsigned char *arp_ptr; | 393 | unsigned char *arp_ptr; |
| 369 | __be32 dip; | 394 | __be32 dip; |
| @@ -377,6 +402,8 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, | |||
| 377 | 402 | ||
| 378 | memcpy(&dip, arp_ptr, 4); | 403 | memcpy(&dip, arp_ptr, 4); |
| 379 | addr = ipvlan_ht_addr_lookup(port, &dip, false); | 404 | addr = ipvlan_ht_addr_lookup(port, &dip, false); |
| 405 | break; | ||
| 406 | } | ||
| 380 | } | 407 | } |
| 381 | 408 | ||
| 382 | return addr; | 409 | return addr; |
| @@ -420,6 +447,7 @@ out: | |||
| 420 | return ret; | 447 | return ret; |
| 421 | } | 448 | } |
| 422 | 449 | ||
| 450 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 423 | static int ipvlan_process_v6_outbound(struct sk_buff *skb) | 451 | static int ipvlan_process_v6_outbound(struct sk_buff *skb) |
| 424 | { | 452 | { |
| 425 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | 453 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); |
| @@ -456,6 +484,12 @@ err: | |||
| 456 | out: | 484 | out: |
| 457 | return ret; | 485 | return ret; |
| 458 | } | 486 | } |
| 487 | #else | ||
| 488 | static int ipvlan_process_v6_outbound(struct sk_buff *skb) | ||
| 489 | { | ||
| 490 | return NET_XMIT_DROP; | ||
| 491 | } | ||
| 492 | #endif | ||
| 459 | 493 | ||
| 460 | static int ipvlan_process_outbound(struct sk_buff *skb) | 494 | static int ipvlan_process_outbound(struct sk_buff *skb) |
| 461 | { | 495 | { |
| @@ -759,6 +793,7 @@ struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb, | |||
| 759 | goto out; | 793 | goto out; |
| 760 | break; | 794 | break; |
| 761 | } | 795 | } |
| 796 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 762 | case AF_INET6: | 797 | case AF_INET6: |
| 763 | { | 798 | { |
| 764 | struct dst_entry *dst; | 799 | struct dst_entry *dst; |
| @@ -778,6 +813,7 @@ struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb, | |||
| 778 | skb_dst_set(skb, dst); | 813 | skb_dst_set(skb, dst); |
| 779 | break; | 814 | break; |
| 780 | } | 815 | } |
| 816 | #endif | ||
| 781 | default: | 817 | default: |
| 782 | break; | 818 | break; |
| 783 | } | 819 | } |
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 2469df118fbf..67c91ceda979 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c | |||
| @@ -22,12 +22,14 @@ static const struct nf_hook_ops ipvl_nfops[] = { | |||
| 22 | .hooknum = NF_INET_LOCAL_IN, | 22 | .hooknum = NF_INET_LOCAL_IN, |
| 23 | .priority = INT_MAX, | 23 | .priority = INT_MAX, |
| 24 | }, | 24 | }, |
| 25 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 25 | { | 26 | { |
| 26 | .hook = ipvlan_nf_input, | 27 | .hook = ipvlan_nf_input, |
| 27 | .pf = NFPROTO_IPV6, | 28 | .pf = NFPROTO_IPV6, |
| 28 | .hooknum = NF_INET_LOCAL_IN, | 29 | .hooknum = NF_INET_LOCAL_IN, |
| 29 | .priority = INT_MAX, | 30 | .priority = INT_MAX, |
| 30 | }, | 31 | }, |
| 32 | #endif | ||
| 31 | }; | 33 | }; |
| 32 | 34 | ||
| 33 | static const struct l3mdev_ops ipvl_l3mdev_ops = { | 35 | static const struct l3mdev_ops ipvl_l3mdev_ops = { |
| @@ -800,12 +802,14 @@ static int ipvlan_add_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) | |||
| 800 | return -ENOMEM; | 802 | return -ENOMEM; |
| 801 | 803 | ||
| 802 | addr->master = ipvlan; | 804 | addr->master = ipvlan; |
| 803 | if (is_v6) { | 805 | if (!is_v6) { |
| 804 | memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr)); | ||
| 805 | addr->atype = IPVL_IPV6; | ||
| 806 | } else { | ||
| 807 | memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr)); | 806 | memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr)); |
| 808 | addr->atype = IPVL_IPV4; | 807 | addr->atype = IPVL_IPV4; |
| 808 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 809 | } else { | ||
| 810 | memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr)); | ||
| 811 | addr->atype = IPVL_IPV6; | ||
| 812 | #endif | ||
| 809 | } | 813 | } |
| 810 | list_add_tail(&addr->anode, &ipvlan->addrs); | 814 | list_add_tail(&addr->anode, &ipvlan->addrs); |
| 811 | 815 | ||
| @@ -833,6 +837,20 @@ static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6) | |||
| 833 | return; | 837 | return; |
| 834 | } | 838 | } |
| 835 | 839 | ||
| 840 | static bool ipvlan_is_valid_dev(const struct net_device *dev) | ||
| 841 | { | ||
| 842 | struct ipvl_dev *ipvlan = netdev_priv(dev); | ||
| 843 | |||
| 844 | if (!netif_is_ipvlan(dev)) | ||
| 845 | return false; | ||
| 846 | |||
| 847 | if (!ipvlan || !ipvlan->port) | ||
| 848 | return false; | ||
| 849 | |||
| 850 | return true; | ||
| 851 | } | ||
| 852 | |||
| 853 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 836 | static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) | 854 | static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) |
| 837 | { | 855 | { |
| 838 | if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) { | 856 | if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) { |
| @@ -850,19 +868,6 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) | |||
| 850 | return ipvlan_del_addr(ipvlan, ip6_addr, true); | 868 | return ipvlan_del_addr(ipvlan, ip6_addr, true); |
| 851 | } | 869 | } |
| 852 | 870 | ||
| 853 | static bool ipvlan_is_valid_dev(const struct net_device *dev) | ||
| 854 | { | ||
| 855 | struct ipvl_dev *ipvlan = netdev_priv(dev); | ||
| 856 | |||
| 857 | if (!netif_is_ipvlan(dev)) | ||
| 858 | return false; | ||
| 859 | |||
| 860 | if (!ipvlan || !ipvlan->port) | ||
| 861 | return false; | ||
| 862 | |||
| 863 | return true; | ||
| 864 | } | ||
| 865 | |||
| 866 | static int ipvlan_addr6_event(struct notifier_block *unused, | 871 | static int ipvlan_addr6_event(struct notifier_block *unused, |
| 867 | unsigned long event, void *ptr) | 872 | unsigned long event, void *ptr) |
| 868 | { | 873 | { |
| @@ -913,6 +918,7 @@ static int ipvlan_addr6_validator_event(struct notifier_block *unused, | |||
| 913 | 918 | ||
| 914 | return NOTIFY_OK; | 919 | return NOTIFY_OK; |
| 915 | } | 920 | } |
| 921 | #endif | ||
| 916 | 922 | ||
| 917 | static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) | 923 | static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) |
| 918 | { | 924 | { |
| @@ -993,6 +999,7 @@ static struct notifier_block ipvlan_notifier_block __read_mostly = { | |||
| 993 | .notifier_call = ipvlan_device_event, | 999 | .notifier_call = ipvlan_device_event, |
| 994 | }; | 1000 | }; |
| 995 | 1001 | ||
| 1002 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 996 | static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { | 1003 | static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { |
| 997 | .notifier_call = ipvlan_addr6_event, | 1004 | .notifier_call = ipvlan_addr6_event, |
| 998 | }; | 1005 | }; |
| @@ -1000,6 +1007,7 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { | |||
| 1000 | static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { | 1007 | static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { |
| 1001 | .notifier_call = ipvlan_addr6_validator_event, | 1008 | .notifier_call = ipvlan_addr6_validator_event, |
| 1002 | }; | 1009 | }; |
| 1010 | #endif | ||
| 1003 | 1011 | ||
| 1004 | static void ipvlan_ns_exit(struct net *net) | 1012 | static void ipvlan_ns_exit(struct net *net) |
| 1005 | { | 1013 | { |
| @@ -1024,9 +1032,11 @@ static int __init ipvlan_init_module(void) | |||
| 1024 | 1032 | ||
| 1025 | ipvlan_init_secret(); | 1033 | ipvlan_init_secret(); |
| 1026 | register_netdevice_notifier(&ipvlan_notifier_block); | 1034 | register_netdevice_notifier(&ipvlan_notifier_block); |
| 1035 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 1027 | register_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 1036 | register_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
| 1028 | register_inet6addr_validator_notifier( | 1037 | register_inet6addr_validator_notifier( |
| 1029 | &ipvlan_addr6_vtor_notifier_block); | 1038 | &ipvlan_addr6_vtor_notifier_block); |
| 1039 | #endif | ||
| 1030 | register_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 1040 | register_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
| 1031 | register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); | 1041 | register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); |
| 1032 | 1042 | ||
| @@ -1045,9 +1055,11 @@ error: | |||
| 1045 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 1055 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
| 1046 | unregister_inetaddr_validator_notifier( | 1056 | unregister_inetaddr_validator_notifier( |
| 1047 | &ipvlan_addr4_vtor_notifier_block); | 1057 | &ipvlan_addr4_vtor_notifier_block); |
| 1058 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 1048 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 1059 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
| 1049 | unregister_inet6addr_validator_notifier( | 1060 | unregister_inet6addr_validator_notifier( |
| 1050 | &ipvlan_addr6_vtor_notifier_block); | 1061 | &ipvlan_addr6_vtor_notifier_block); |
| 1062 | #endif | ||
| 1051 | unregister_netdevice_notifier(&ipvlan_notifier_block); | 1063 | unregister_netdevice_notifier(&ipvlan_notifier_block); |
| 1052 | return err; | 1064 | return err; |
| 1053 | } | 1065 | } |
| @@ -1060,9 +1072,11 @@ static void __exit ipvlan_cleanup_module(void) | |||
| 1060 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); | 1072 | unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); |
| 1061 | unregister_inetaddr_validator_notifier( | 1073 | unregister_inetaddr_validator_notifier( |
| 1062 | &ipvlan_addr4_vtor_notifier_block); | 1074 | &ipvlan_addr4_vtor_notifier_block); |
| 1075 | #if IS_ENABLED(CONFIG_IPV6) | ||
| 1063 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); | 1076 | unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); |
| 1064 | unregister_inet6addr_validator_notifier( | 1077 | unregister_inet6addr_validator_notifier( |
| 1065 | &ipvlan_addr6_vtor_notifier_block); | 1078 | &ipvlan_addr6_vtor_notifier_block); |
| 1079 | #endif | ||
| 1066 | } | 1080 | } |
| 1067 | 1081 | ||
| 1068 | module_init(ipvlan_init_module); | 1082 | module_init(ipvlan_init_module); |
