forked from Minki/linux
ipvlan: drop ipv6 dependency
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:
parent
cac56209a6
commit
94333fac44
@ -149,7 +149,6 @@ config MACVTAP
|
||||
config IPVLAN
|
||||
tristate "IP-VLAN support"
|
||||
depends on INET
|
||||
depends on IPV6
|
||||
depends on NETFILTER
|
||||
depends on NET_L3_MASTER_DEV
|
||||
---help---
|
||||
|
@ -35,6 +35,7 @@ void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ipvlan_count_rx);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static u8 ipvlan_get_v6_hash(const void *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) &
|
||||
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)
|
||||
{
|
||||
@ -51,6 +58,23 @@ static u8 ipvlan_get_v4_hash(const void *iaddr)
|
||||
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,
|
||||
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) :
|
||||
ipvlan_get_v4_hash(iaddr);
|
||||
hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode) {
|
||||
if (is_v6 && addr->atype == IPVL_IPV6 &&
|
||||
ipv6_addr_equal(&addr->ip6addr, iaddr))
|
||||
hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
|
||||
if (addr_equal(is_v6, addr, iaddr))
|
||||
return addr;
|
||||
else if (!is_v6 && addr->atype == IPVL_IPV4 &&
|
||||
addr->ip4addr.s_addr ==
|
||||
((struct in_addr *)iaddr)->s_addr)
|
||||
return addr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -93,13 +111,9 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
|
||||
{
|
||||
struct ipvl_addr *addr;
|
||||
|
||||
list_for_each_entry(addr, &ipvlan->addrs, anode) {
|
||||
if ((is_v6 && addr->atype == IPVL_IPV6 &&
|
||||
ipv6_addr_equal(&addr->ip6addr, iaddr)) ||
|
||||
(!is_v6 && addr->atype == IPVL_IPV4 &&
|
||||
addr->ip4addr.s_addr == ((struct in_addr *)iaddr)->s_addr))
|
||||
list_for_each_entry(addr, &ipvlan->addrs, anode)
|
||||
if (addr_equal(is_v6, addr, iaddr))
|
||||
return addr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -150,6 +164,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int
|
||||
lyr3h = ip4h;
|
||||
break;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case htons(ETH_P_IPV6): {
|
||||
struct ipv6hdr *ip6h;
|
||||
|
||||
@ -188,6 +203,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@ -337,14 +353,18 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
|
||||
{
|
||||
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 in6_addr *i6addr;
|
||||
|
||||
ip6h = (struct ipv6hdr *)lyr3h;
|
||||
i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
|
||||
addr = ipvlan_ht_addr_lookup(port, i6addr, true);
|
||||
} else if (addr_type == IPVL_ICMPV6) {
|
||||
break;
|
||||
}
|
||||
case IPVL_ICMPV6: {
|
||||
struct nd_msg *ndmh;
|
||||
struct in6_addr *i6addr;
|
||||
|
||||
@ -356,14 +376,19 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
|
||||
i6addr = &ndmh->target;
|
||||
addr = ipvlan_ht_addr_lookup(port, i6addr, true);
|
||||
}
|
||||
} else if (addr_type == IPVL_IPV4) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case IPVL_IPV4: {
|
||||
struct iphdr *ip4h;
|
||||
__be32 *i4addr;
|
||||
|
||||
ip4h = (struct iphdr *)lyr3h;
|
||||
i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
|
||||
addr = ipvlan_ht_addr_lookup(port, i4addr, false);
|
||||
} else if (addr_type == IPVL_ARP) {
|
||||
break;
|
||||
}
|
||||
case IPVL_ARP: {
|
||||
struct arphdr *arph;
|
||||
unsigned char *arp_ptr;
|
||||
__be32 dip;
|
||||
@ -377,6 +402,8 @@ static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
|
||||
|
||||
memcpy(&dip, arp_ptr, 4);
|
||||
addr = ipvlan_ht_addr_lookup(port, &dip, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return addr;
|
||||
@ -420,6 +447,7 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static int ipvlan_process_v6_outbound(struct sk_buff *skb)
|
||||
{
|
||||
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
|
||||
@ -456,6 +484,12 @@ err:
|
||||
out:
|
||||
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)
|
||||
{
|
||||
@ -759,6 +793,7 @@ struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
{
|
||||
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);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -22,12 +22,14 @@ static const struct nf_hook_ops ipvl_nfops[] = {
|
||||
.hooknum = NF_INET_LOCAL_IN,
|
||||
.priority = INT_MAX,
|
||||
},
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
{
|
||||
.hook = ipvlan_nf_input,
|
||||
.pf = NFPROTO_IPV6,
|
||||
.hooknum = NF_INET_LOCAL_IN,
|
||||
.priority = INT_MAX,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
addr->master = ipvlan;
|
||||
if (is_v6) {
|
||||
memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr));
|
||||
addr->atype = IPVL_IPV6;
|
||||
} else {
|
||||
if (!is_v6) {
|
||||
memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr));
|
||||
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);
|
||||
|
||||
@ -833,6 +837,20 @@ static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
@ -913,6 +918,7 @@ static int ipvlan_addr6_validator_event(struct notifier_block *unused,
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
static struct notifier_block ipvlan_addr6_notifier_block __read_mostly = {
|
||||
.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 = {
|
||||
.notifier_call = ipvlan_addr6_validator_event,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void ipvlan_ns_exit(struct net *net)
|
||||
{
|
||||
@ -1024,9 +1032,11 @@ static int __init ipvlan_init_module(void)
|
||||
|
||||
ipvlan_init_secret();
|
||||
register_netdevice_notifier(&ipvlan_notifier_block);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
register_inet6addr_notifier(&ipvlan_addr6_notifier_block);
|
||||
register_inet6addr_validator_notifier(
|
||||
&ipvlan_addr6_vtor_notifier_block);
|
||||
#endif
|
||||
register_inetaddr_notifier(&ipvlan_addr4_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_validator_notifier(
|
||||
&ipvlan_addr4_vtor_notifier_block);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
|
||||
unregister_inet6addr_validator_notifier(
|
||||
&ipvlan_addr6_vtor_notifier_block);
|
||||
#endif
|
||||
unregister_netdevice_notifier(&ipvlan_notifier_block);
|
||||
return err;
|
||||
}
|
||||
@ -1060,9 +1072,11 @@ static void __exit ipvlan_cleanup_module(void)
|
||||
unregister_inetaddr_notifier(&ipvlan_addr4_notifier_block);
|
||||
unregister_inetaddr_validator_notifier(
|
||||
&ipvlan_addr4_vtor_notifier_block);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
unregister_inet6addr_notifier(&ipvlan_addr6_notifier_block);
|
||||
unregister_inet6addr_validator_notifier(
|
||||
&ipvlan_addr6_vtor_notifier_block);
|
||||
#endif
|
||||
}
|
||||
|
||||
module_init(ipvlan_init_module);
|
||||
|
Loading…
Reference in New Issue
Block a user