Skip to content

Commit 981eb73

Browse files
Jethro BeekmanUlrich Hecht
authored andcommitted
macvlan: Add nodst option to macvlan type source
[ Upstream commit 427f0c8c194b22edcafef1b0a42995ddc5c2227d ] 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: Jethro Beekman <kernel@jbeekman.nl> Signed-off-by: David S. Miller <davem@davemloft.net> Stable-dep-of: 7470a7a63dc1 ("macvlan: fix possible UAF in macvlan_forward_source()") Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Ulrich Hecht <uli@kernel.org>
1 parent 612801b commit 981eb73

2 files changed

Lines changed: 15 additions & 5 deletions

File tree

drivers/net/macvlan.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,18 +424,24 @@ static void macvlan_forward_source_one(struct sk_buff *skb,
424424
macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, false);
425425
}
426426

427-
static void macvlan_forward_source(struct sk_buff *skb,
427+
static bool macvlan_forward_source(struct sk_buff *skb,
428428
struct macvlan_port *port,
429429
const unsigned char *addr)
430430
{
431431
struct macvlan_source_entry *entry;
432432
u32 idx = macvlan_eth_hash(addr);
433433
struct hlist_head *h = &port->vlan_source_hash[idx];
434+
bool consume = false;
434435

435436
hlist_for_each_entry_rcu(entry, h, hlist) {
436-
if (ether_addr_equal_64bits(entry->addr, addr))
437+
if (ether_addr_equal_64bits(entry->addr, addr)) {
438+
if (entry->vlan->flags & MACVLAN_FLAG_NODST)
439+
consume = true;
437440
macvlan_forward_source_one(skb, entry->vlan);
441+
}
438442
}
443+
444+
return consume;
439445
}
440446

441447
/* called under rcu_read_lock() from netif_receive_skb */
@@ -464,7 +470,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
464470
return RX_HANDLER_CONSUMED;
465471
*pskb = skb;
466472
eth = eth_hdr(skb);
467-
macvlan_forward_source(skb, port, eth->h_source);
473+
if (macvlan_forward_source(skb, port, eth->h_source))
474+
return RX_HANDLER_CONSUMED;
468475
src = macvlan_hash_lookup(port, eth->h_source);
469476
if (src && src->mode != MACVLAN_MODE_VEPA &&
470477
src->mode != MACVLAN_MODE_BRIDGE) {
@@ -483,7 +490,8 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
483490
return RX_HANDLER_PASS;
484491
}
485492

486-
macvlan_forward_source(skb, port, eth->h_source);
493+
if (macvlan_forward_source(skb, port, eth->h_source))
494+
return RX_HANDLER_CONSUMED;
487495
if (macvlan_passthru(port))
488496
vlan = list_first_or_null_rcu(&port->vlans,
489497
struct macvlan_dev, list);
@@ -1244,7 +1252,8 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[],
12441252
return 0;
12451253

12461254
if (data[IFLA_MACVLAN_FLAGS] &&
1247-
nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC)
1255+
nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~(MACVLAN_FLAG_NOPROMISC |
1256+
MACVLAN_FLAG_NODST))
12481257
return -EINVAL;
12491258

12501259
if (data[IFLA_MACVLAN_MODE]) {

include/uapi/linux/if_link.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,7 @@ enum macvlan_macaddr_mode {
422422
};
423423

424424
#define MACVLAN_FLAG_NOPROMISC 1
425+
#define MACVLAN_FLAG_NODST 2 /* skip dst macvlan if matching src macvlan */
425426

426427
/* VRF section */
427428
enum {

0 commit comments

Comments
 (0)