IPVlan has an hard dependency on IPv6, refactor the ipvlan code to allow
compiling it with IPv6 disabled, move duplicate code into addr_equal()
and refactor series of if-else into a switch.

Signed-off-by: Matteo Croce <mcroce@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Matteo Croce 2018-02-21 01:31:13 +01:00 коммит произвёл David S. Miller
Родитель cac56209a6
Коммит 94333fac44
3 изменённых файлов: 85 добавлений и 36 удалений

Просмотреть файл

@ -149,7 +149,6 @@ config MACVTAP
config IPVLAN config IPVLAN
tristate "IP-VLAN support" tristate "IP-VLAN support"
depends on INET depends on INET
depends on IPV6
depends on NETFILTER depends on NETFILTER
depends on NET_L3_MASTER_DEV depends on NET_L3_MASTER_DEV
---help--- ---help---

Просмотреть файл

@ -35,6 +35,7 @@ void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
} }
EXPORT_SYMBOL_GPL(ipvlan_count_rx); EXPORT_SYMBOL_GPL(ipvlan_count_rx);
#if IS_ENABLED(CONFIG_IPV6)
static u8 ipvlan_get_v6_hash(const void *iaddr) static u8 ipvlan_get_v6_hash(const void *iaddr)
{ {
const struct in6_addr *ip6_addr = iaddr; const struct in6_addr *ip6_addr = iaddr;
@ -42,6 +43,12 @@ static u8 ipvlan_get_v6_hash(const void *iaddr)
return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) & return __ipv6_addr_jhash(ip6_addr, ipvlan_jhash_secret) &
IPVLAN_HASH_MASK; IPVLAN_HASH_MASK;
} }
#else
static u8 ipvlan_get_v6_hash(const void *iaddr)
{
return 0;
}
#endif
static u8 ipvlan_get_v4_hash(const void *iaddr) static u8 ipvlan_get_v4_hash(const void *iaddr)
{ {
@ -51,6 +58,23 @@ static u8 ipvlan_get_v4_hash(const void *iaddr)
IPVLAN_HASH_MASK; IPVLAN_HASH_MASK;
} }
static bool addr_equal(bool is_v6, struct ipvl_addr *addr, const void *iaddr)
{
if (!is_v6 && addr->atype == IPVL_IPV4) {
struct in_addr *i4addr = (struct in_addr *)iaddr;
return addr->ip4addr.s_addr == i4addr->s_addr;
#if IS_ENABLED(CONFIG_IPV6)
} else if (is_v6 && addr->atype == IPVL_IPV6) {
struct in6_addr *i6addr = (struct in6_addr *)iaddr;
return ipv6_addr_equal(&addr->ip6addr, i6addr);
#endif
}
return false;
}
static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port, static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
const void *iaddr, bool is_v6) const void *iaddr, bool is_v6)
{ {
@ -59,15 +83,9 @@ static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
hash = is_v6 ? ipvlan_get_v6_hash(iaddr) : hash = is_v6 ? ipvlan_get_v6_hash(iaddr) :
ipvlan_get_v4_hash(iaddr); ipvlan_get_v4_hash(iaddr);
hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) { hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
if (is_v6 && addr->atype == IPVL_IPV6 && if (addr_equal(is_v6, addr, iaddr))
ipv6_addr_equal(&addr->ip6addr, iaddr))
return addr; return addr;
else if (!is_v6 && addr->atype == IPVL_IPV4 &&
addr->ip4addr.s_addr ==
((struct in_addr *)iaddr)->s_addr)
return addr;
}
return NULL; return NULL;
} }
@ -93,13 +111,9 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
{ {
struct ipvl_addr *addr; struct ipvl_addr *addr;
list_for_each_entry(addr, &ipvlan->addrs, anode) { list_for_each_entry(addr, &ipvlan->addrs, anode)
if ((is_v6 && addr->atype == IPVL_IPV6 && if (addr_equal(is_v6, addr, iaddr))
ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
(!is_v6 && addr->atype == IPVL_IPV4 &&
addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
return addr; return addr;
}
return NULL; return NULL;
} }
@ -150,6 +164,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int
lyr3h = ip4h; lyr3h = ip4h;
break; break;
} }
#if IS_ENABLED(CONFIG_IPV6)
case htons(ETH_P_IPV6): { case htons(ETH_P_IPV6): {
struct ipv6hdr *ip6h; struct ipv6hdr *ip6h;
@ -188,6 +203,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int
} }
break; break;
} }
#endif
default: default:
return NULL; return NULL;
} }
@ -337,14 +353,18 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
{ {
struct ipvl_addr *addr = NULL; struct ipvl_addr *addr = NULL;
if (addr_type == IPVL_IPV6) { switch (addr_type) {
#if IS_ENABLED(CONFIG_IPV6)
case IPVL_IPV6: {
struct ipv6hdr *ip6h; struct ipv6hdr *ip6h;
struct in6_addr *i6addr; struct in6_addr *i6addr;
ip6h = (struct ipv6hdr *)lyr3h; ip6h = (struct ipv6hdr *)lyr3h;
i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr; i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
addr = ipvlan_ht_addr_lookup(port, i6addr, true); addr = ipvlan_ht_addr_lookup(port, i6addr, true);
} else if (addr_type == IPVL_ICMPV6) { break;
}
case IPVL_ICMPV6: {
struct nd_msg *ndmh; struct nd_msg *ndmh;
struct in6_addr *i6addr; struct in6_addr *i6addr;
@ -356,14 +376,19 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
i6addr = &ndmh->target; i6addr = &ndmh->target;
addr = ipvlan_ht_addr_lookup(port, i6addr, true); addr = ipvlan_ht_addr_lookup(port, i6addr, true);
} }
} else if (addr_type == IPVL_IPV4) { break;
}
#endif
case IPVL_IPV4: {
struct iphdr *ip4h; struct iphdr *ip4h;
__be32 *i4addr; __be32 *i4addr;
ip4h = (struct iphdr *)lyr3h; ip4h = (struct iphdr *)lyr3h;
i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr; i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
addr = ipvlan_ht_addr_lookup(port, i4addr, false); addr = ipvlan_ht_addr_lookup(port, i4addr, false);
} else if (addr_type == IPVL_ARP) { break;
}
case IPVL_ARP: {
struct arphdr *arph; struct arphdr *arph;
unsigned char *arp_ptr; unsigned char *arp_ptr;
__be32 dip; __be32 dip;
@ -377,6 +402,8 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
memcpy(&dip, arp_ptr, 4); memcpy(&dip, arp_ptr, 4);
addr = ipvlan_ht_addr_lookup(port, &dip, false); addr = ipvlan_ht_addr_lookup(port, &dip, false);
break;
}
} }
return addr; return addr;
@ -420,6 +447,7 @@ out:
return ret; return ret;
} }
#if IS_ENABLED(CONFIG_IPV6)
static int ipvlan_process_v6_outbound(struct sk_buff *skb) static int ipvlan_process_v6_outbound(struct sk_buff *skb)
{ {
const struct ipv6hdr *ip6h = ipv6_hdr(skb); const struct ipv6hdr *ip6h = ipv6_hdr(skb);
@ -456,6 +484,12 @@ err:
out: out:
return ret; return ret;
} }
#else
static int ipvlan_process_v6_outbound(struct sk_buff *skb)
{
return NET_XMIT_DROP;
}
#endif
static int ipvlan_process_outbound(struct sk_buff *skb) static int ipvlan_process_outbound(struct sk_buff *skb)
{ {
@ -759,6 +793,7 @@ struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
goto out; goto out;
break; break;
} }
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6: case AF_INET6:
{ {
struct dst_entry *dst; struct dst_entry *dst;
@ -778,6 +813,7 @@ struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
skb_dst_set(skb, dst); skb_dst_set(skb, dst);
break; break;
} }
#endif
default: default:
break; break;
} }

Просмотреть файл

@ -22,12 +22,14 @@ static const struct nf_hook_ops ipvl_nfops[] = {
.hooknum = NF_INET_LOCAL_IN, .hooknum = NF_INET_LOCAL_IN,
.priority = INT_MAX, .priority = INT_MAX,
}, },
#if IS_ENABLED(CONFIG_IPV6)
{ {
.hook = ipvlan_nf_input, .hook = ipvlan_nf_input,
.pf = NFPROTO_IPV6, .pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_IN, .hooknum = NF_INET_LOCAL_IN,
.priority = INT_MAX, .priority = INT_MAX,
}, },
#endif
}; };
static const struct l3mdev_ops ipvl_l3mdev_ops = { 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)
return -ENOMEM; return -ENOMEM;
addr->master = ipvlan; addr->master = ipvlan;
if (is_v6) { if (!is_v6) {
memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr));
addr->atype = IPVL_IPV6;
} else {
memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr)); memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr));
addr->atype = IPVL_IPV4; addr->atype = IPVL_IPV4;
#if IS_ENABLED(CONFIG_IPV6)
} else {
memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr));
addr->atype = IPVL_IPV6;
#endif
} }
list_add_tail(&addr->anode, &ipvlan->addrs); list_add_tail(&addr->anode, &ipvlan->addrs);
@ -833,6 +837,20 @@ static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
return; return;
} }
static bool ipvlan_is_valid_dev(const struct net_device *dev)
{
struct ipvl_dev *ipvlan = netdev_priv(dev);
if (!netif_is_ipvlan(dev))
return false;
if (!ipvlan || !ipvlan->port)
return false;
return true;
}
#if IS_ENABLED(CONFIG_IPV6)
static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr) static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
{ {
if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) { 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)
return ipvlan_del_addr(ipvlan, ip6_addr, true); return ipvlan_del_addr(ipvlan, ip6_addr, true);
} }
static bool ipvlan_is_valid_dev(const struct net_device *dev)
{
struct ipvl_dev *ipvlan = netdev_priv(dev);
if (!netif_is_ipvlan(dev))
return false;
if (!ipvlan || !ipvlan->port)
return false;
return true;
}
static int ipvlan_addr6_event(struct notifier_block *unused, static int ipvlan_addr6_event(struct notifier_block *unused,
unsigned long event, void *ptr) unsigned long event, void *ptr)
{ {
@ -913,6 +918,7 @@ static int ipvlan_addr6_validator_event(struct notifier_block *unused,
return NOTIFY_OK; return NOTIFY_OK;
} }
#endif
static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr) static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
{ {
@ -993,6 +999,7 @@ static struct notifier_block ipvlan_notifier_block __read_mostly = {
.notifier_call = ipvlan_device_event, .notifier_call = ipvlan_device_event,
}; };
#if IS_ENABLED(CONFIG_IPV6)
static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = { static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
.notifier_call = ipvlan_addr6_event, .notifier_call = ipvlan_addr6_event,
}; };
@ -1000,6 +1007,7 @@ static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = { static struct notifier_block ipvlan_addr6_vtor_notifier_block __read_mostly = {
.notifier_call = ipvlan_addr6_validator_event, .notifier_call = ipvlan_addr6_validator_event,
}; };
#endif
static void ipvlan_ns_exit(struct net *net) static void ipvlan_ns_exit(struct net *net)
{ {
@ -1024,9 +1032,11 @@ static int __init ipvlan_init_module(void)
ipvlan_init_secret(); ipvlan_init_secret();
register_netdevice_notifier(&ipvlan_notifier_block); register_netdevice_notifier(&ipvlan_notifier_block);
#if IS_ENABLED(CONFIG_IPV6)
register_inet6addr_notifier(&ipvlan_addr6_notifier_block); register_inet6addr_notifier(&ipvlan_addr6_notifier_block);
register_inet6addr_validator_notifier( register_inet6addr_validator_notifier(
&ipvlan_addr6_vtor_notifier_block); &ipvlan_addr6_vtor_notifier_block);
#endif
register_inetaddr_notifier(&ipvlan_addr4_notifier_block); register_inetaddr_notifier(&ipvlan_addr4_notifier_block);
register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block); register_inetaddr_validator_notifier(&ipvlan_addr4_vtor_notifier_block);
@ -1045,9 +1055,11 @@ error:
unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
unregister_inetaddr_validator_notifier( unregister_inetaddr_validator_notifier(
&ipvlan_addr4_vtor_notifier_block); &ipvlan_addr4_vtor_notifier_block);
#if IS_ENABLED(CONFIG_IPV6)
unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
unregister_inet6addr_validator_notifier( unregister_inet6addr_validator_notifier(
&ipvlan_addr6_vtor_notifier_block); &ipvlan_addr6_vtor_notifier_block);
#endif
unregister_netdevice_notifier(&ipvlan_notifier_block); unregister_netdevice_notifier(&ipvlan_notifier_block);
return err; return err;
} }
@ -1060,9 +1072,11 @@ static void __exit ipvlan_cleanup_module(void)
unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block); unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
unregister_inetaddr_validator_notifier( unregister_inetaddr_validator_notifier(
&ipvlan_addr4_vtor_notifier_block); &ipvlan_addr4_vtor_notifier_block);
#if IS_ENABLED(CONFIG_IPV6)
unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block); unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
unregister_inet6addr_validator_notifier( unregister_inet6addr_validator_notifier(
&ipvlan_addr6_vtor_notifier_block); &ipvlan_addr6_vtor_notifier_block);
#endif
} }
module_init(ipvlan_init_module); module_init(ipvlan_init_module);