Commit 427f0c8c authored by Jethro Beekman's avatar Jethro Beekman Committed by David S. Miller

macvlan: Add nodst option to macvlan type source

The default behavior for source MACVLAN is to duplicate packets to
appropriate type source devices, and then do the normal destination MACVLAN
flow. This patch adds an option to skip destination MACVLAN processing if
any matching source MACVLAN device has the option set.

This allows setting up a "catch all" device for source MACVLAN: create one
or more devices with type source nodst, and one device with e.g. type vepa,
and incoming traffic will be received on exactly one device.

v2: netdev wants non-standard line length
Signed-off-by: default avatarJethro Beekman <kernel@jbeekman.nl>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1e5e4acb
......@@ -423,18 +423,24 @@ static void macvlan_forward_source_one(struct sk_buff *skb,
macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
}
static void macvlan_forward_source(struct sk_buff *skb,
static bool macvlan_forward_source(struct sk_buff *skb,
struct macvlan_port *port,
const unsigned char *addr)
{
struct macvlan_source_entry *entry;
u32 idx = macvlan_eth_hash(addr);
struct hlist_head *h = &port->vlan_source_hash[idx];
bool consume = false;
hlist_for_each_entry_rcu(entry, h, hlist) {
if (ether_addr_equal_64bits(entry->addr, addr))
if (ether_addr_equal_64bits(entry->addr, addr)) {
if (entry->vlan->flags & MACVLAN_FLAG_NODST)
consume = true;
macvlan_forward_source_one(skb, entry->vlan);
}
}
return consume;
}
/* called under rcu_read_lock() from netif_receive_skb */
......@@ -463,7 +469,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
return RX_HANDLER_CONSUMED;
*pskb = skb;
eth = eth_hdr(skb);
macvlan_forward_source(skb, port, eth->h_source);
if (macvlan_forward_source(skb, port, eth->h_source))
return RX_HANDLER_CONSUMED;
src = macvlan_hash_lookup(port, eth->h_source);
if (src && src->mode != MACVLAN_MODE_VEPA &&
src->mode != MACVLAN_MODE_BRIDGE) {
......@@ -482,7 +489,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
return RX_HANDLER_PASS;
}
macvlan_forward_source(skb, port, eth->h_source);
if (macvlan_forward_source(skb, port, eth->h_source))
return RX_HANDLER_CONSUMED;
if (macvlan_passthru(port))
vlan = list_first_or_null_rcu(&port->vlans,
struct macvlan_dev, list);
......@@ -1286,7 +1294,8 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],
return 0;
if (data[IFLA_MACVLAN_FLAGS] &&
nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC)
nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~(MACVLAN_FLAG_NOPROMISC |
MACVLAN_FLAG_NODST))
return -EINVAL;
if (data[IFLA_MACVLAN_MODE]) {
......
......@@ -614,6 +614,7 @@ enum macvlan_macaddr_mode {
};
#define MACVLAN_FLAG_NOPROMISC 1
#define MACVLAN_FLAG_NODST 2 /* skip dst macvlan if matching src macvlan */
/* VRF section */
enum {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment