Skip to content

Commit

Permalink
ipvlan: decouple l3s mode dependencies from other modes
Browse files Browse the repository at this point in the history
Right now ipvlan has a hard dependency on CONFIG_NETFILTER and
otherwise it cannot be built. However, the only ipvlan operation
mode that actually depends on netfilter is l3s, everything else
is independent of it. Break this hard dependency such that users
are able to use ipvlan l3 mode on systems where netfilter is not
compiled in.

Therefore, this adds a hidden CONFIG_IPVLAN_L3S bool which is
defaulting to y when CONFIG_NETFILTER is set in order to retain
existing behavior for l3s. All l3s related code is refactored
into ipvlan_l3s.c that is compiled in when enabled.

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Cc: Mahesh Bandewar <maheshb@google.com>
Cc: Florian Westphal <fw@strlen.de>
Cc: Martynas Pumputis <m@lambda.lt>
Acked-by: Florian Westphal <fw@strlen.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
borkmann authored and davem330 committed Feb 8, 2019
1 parent 998a8a8 commit c675e06
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 208 deletions.
6 changes: 4 additions & 2 deletions drivers/net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,15 @@ config MACVTAP
To compile this driver as a module, choose M here: the module
will be called macvtap.

config IPVLAN_L3S
depends on NETFILTER
def_bool y
select NET_L3_MASTER_DEV

config IPVLAN
tristate "IP-VLAN support"
depends on INET
depends on IPV6 || !IPV6
depends on NETFILTER
select NET_L3_MASTER_DEV
---help---
This allows one to create virtual devices off of a main interface
and packets will be delivered based on the dest L3 (IPv6/IPv4 addr)
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/ipvlan/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
obj-$(CONFIG_IPVLAN) += ipvlan.o
obj-$(CONFIG_IPVTAP) += ipvtap.o

ipvlan-objs := ipvlan_core.o ipvlan_main.o
ipvlan-objs-$(CONFIG_IPVLAN_L3S) += ipvlan_l3s.o
ipvlan-objs := ipvlan_core.o ipvlan_main.o $(ipvlan-objs-y)
37 changes: 33 additions & 4 deletions drivers/net/ipvlan/ipvlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,9 @@ struct ipvl_addr *ipvlan_find_addr(const struct ipvl_dev *ipvlan,
const void *iaddr, bool is_v6);
bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6);
void ipvlan_ht_addr_del(struct ipvl_addr *addr);
struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
u16 proto);
unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state);
struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
int addr_type, bool use_dest);
void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type);
void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
unsigned int len, bool success, bool mcast);
int ipvlan_link_new(struct net *src_net, struct net_device *dev,
Expand All @@ -177,6 +176,36 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev,
void ipvlan_link_delete(struct net_device *dev, struct list_head *head);
void ipvlan_link_setup(struct net_device *dev);
int ipvlan_link_register(struct rtnl_link_ops *ops);
#ifdef CONFIG_IPVLAN_L3S
int ipvlan_l3s_register(struct ipvl_port *port);
void ipvlan_l3s_unregister(struct ipvl_port *port);
void ipvlan_migrate_l3s_hook(struct net *oldnet, struct net *newnet);
int ipvlan_l3s_init(void);
void ipvlan_l3s_cleanup(void);
#else
static inline int ipvlan_l3s_register(struct ipvl_port *port)
{
return -ENOTSUPP;
}

static inline void ipvlan_l3s_unregister(struct ipvl_port *port)
{
}

static inline void ipvlan_migrate_l3s_hook(struct net *oldnet,
struct net *newnet)
{
}

static inline int ipvlan_l3s_init(void)
{
return 0;
}

static inline void ipvlan_l3s_cleanup(void)
{
}
#endif /* CONFIG_IPVLAN_L3S */

static inline bool netif_is_ipvlan_port(const struct net_device *dev)
{
Expand Down
105 changes: 7 additions & 98 deletions drivers/net/ipvlan/ipvlan_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ bool ipvlan_addr_busy(struct ipvl_port *port, void *iaddr, bool is_v6)
return ret;
}

static void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type)
void *ipvlan_get_L3_hdr(struct ipvl_port *port, struct sk_buff *skb, int *type)
{
void *lyr3h = NULL;

Expand Down Expand Up @@ -355,9 +355,8 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
return ret;
}

static struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port,
void *lyr3h, int addr_type,
bool use_dest)
struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
int addr_type, bool use_dest)
{
struct ipvl_addr *addr = NULL;

Expand Down Expand Up @@ -647,7 +646,9 @@ int ipvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev)
case IPVLAN_MODE_L2:
return ipvlan_xmit_mode_l2(skb, dev);
case IPVLAN_MODE_L3:
#ifdef CONFIG_IPVLAN_L3S
case IPVLAN_MODE_L3S:
#endif
return ipvlan_xmit_mode_l3(skb, dev);
}

Expand Down Expand Up @@ -743,8 +744,10 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
return ipvlan_handle_mode_l2(pskb, port);
case IPVLAN_MODE_L3:
return ipvlan_handle_mode_l3(pskb, port);
#ifdef CONFIG_IPVLAN_L3S
case IPVLAN_MODE_L3S:
return RX_HANDLER_PASS;
#endif
}

/* Should not reach here */
Expand All @@ -753,97 +756,3 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}

static struct ipvl_addr *ipvlan_skb_to_addr(struct sk_buff *skb,
struct net_device *dev)
{
struct ipvl_addr *addr = NULL;
struct ipvl_port *port;
void *lyr3h;
int addr_type;

if (!dev || !netif_is_ipvlan_port(dev))
goto out;

port = ipvlan_port_get_rcu(dev);
if (!port || port->mode != IPVLAN_MODE_L3S)
goto out;

lyr3h = ipvlan_get_L3_hdr(port, skb, &addr_type);
if (!lyr3h)
goto out;

addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
out:
return addr;
}

struct sk_buff *ipvlan_l3_rcv(struct net_device *dev, struct sk_buff *skb,
u16 proto)
{
struct ipvl_addr *addr;
struct net_device *sdev;

addr = ipvlan_skb_to_addr(skb, dev);
if (!addr)
goto out;

sdev = addr->master->dev;
switch (proto) {
case AF_INET:
{
int err;
struct iphdr *ip4h = ip_hdr(skb);

err = ip_route_input_noref(skb, ip4h->daddr, ip4h->saddr,
ip4h->tos, sdev);
if (unlikely(err))
goto out;
break;
}
#if IS_ENABLED(CONFIG_IPV6)
case AF_INET6:
{
struct dst_entry *dst;
struct ipv6hdr *ip6h = ipv6_hdr(skb);
int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi6 fl6 = {
.flowi6_iif = sdev->ifindex,
.daddr = ip6h->daddr,
.saddr = ip6h->saddr,
.flowlabel = ip6_flowinfo(ip6h),
.flowi6_mark = skb->mark,
.flowi6_proto = ip6h->nexthdr,
};

skb_dst_drop(skb);
dst = ip6_route_input_lookup(dev_net(sdev), sdev, &fl6,
skb, flags);
skb_dst_set(skb, dst);
break;
}
#endif
default:
break;
}

out:
return skb;
}

unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct ipvl_addr *addr;
unsigned int len;

addr = ipvlan_skb_to_addr(skb, skb->dev);
if (!addr)
goto out;

skb->dev = addr->master->dev;
len = skb->len + ETH_HLEN;
ipvlan_count_rx(addr->master, len, true, false);
out:
return NF_ACCEPT;
}

0 comments on commit c675e06

Please sign in to comment.