Skip to content

Commit

Permalink
ipvlan: drop ipv6 dependency
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matteo Croce authored and David S. Miller committed Feb 21, 2018
1 parent cac5620 commit 94333fa
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 36 deletions.
1 change: 0 additions & 1 deletion drivers/net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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---
Expand Down
72 changes: 54 additions & 18 deletions drivers/net/ipvlan/ipvlan_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,20 @@ 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;

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)
{
Expand All @@ -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)
{
Expand All @@ -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))
return addr;
else if (!is_v6 && addr->atype == IPVL_IPV4 &&
addr->ip4addr.s_addr ==
((struct in_addr *)iaddr)->s_addr)
hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
if (addr_equal(is_v6, addr, iaddr))
return addr;
}
return NULL;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -188,6 +203,7 @@ static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int
}
break;
}
#endif
default:
return NULL;
}
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -420,6 +447,7 @@ static int ipvlan_process_v4_outbound(struct sk_buff *skb)
return ret;
}

#if IS_ENABLED(CONFIG_IPV6)
static int ipvlan_process_v6_outbound(struct sk_buff *skb)
{
const struct ipv6hdr *ip6h = ipv6_hdr(skb);
Expand Down Expand Up @@ -456,6 +484,12 @@ static int ipvlan_process_v6_outbound(struct sk_buff *skb)
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)
{
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down
48 changes: 31 additions & 17 deletions drivers/net/ipvlan/ipvlan_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)) {
Expand All @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -993,13 +999,15 @@ 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,
};

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)
{
Expand All @@ -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);

Expand All @@ -1045,9 +1055,11 @@ static int __init ipvlan_init_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
unregister_netdevice_notifier(&ipvlan_notifier_block);
return err;
}
Expand All @@ -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);
Expand Down

0 comments on commit 94333fa

Please sign in to comment.