* [PATCH v2 0/1] macvlan: allow source mode devices along with passthru @ 2026-07-09 10:05 Thomas Martitz 2026-07-09 10:05 ` [PATCH v2 1/1] " Thomas Martitz 2026-07-10 9:56 ` [syzbot ci] " syzbot ci 0 siblings, 2 replies; 4+ messages in thread From: Thomas Martitz @ 2026-07-09 10:05 UTC (permalink / raw) To: Simon Horman, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, open list:NETWORKING DRIVERS, open list Cc: Thomas Martitz, open list:NETWORKING DRIVERS, open list Hello, we're trying to solve a use case on our devices where two SoC are connected on the same board, using the only available high-speed interface. One SoC runs the main Linux system including the full routing stack (FRITZ!OS) and the other SoC implements most of the GPON ONT side. The high-speed interface is of course also used for the user traffic. Therefore we must tell the inter-SoC traffic apart from the user traffic. We achieve this by matching the well-known MAC address of the ONT SoC. The user traffic passes through the ONT SoC without modifying MAC headers. Now we would like to use macvlan (with source mode devices) on the main SoC side for this but our routing stack requires the rx_handler to be available. Therefore macvlan is currently not an option. With this patch macvlan becomes an option because the current limitation of either "one passthru device" or "any other configuration" is relaxed for the combination of passthru and any number of source mode devices. This allows us to configure a source mode device for the other SoC and register an rx_handler for further processing on the passthru device. Thanks in advance! Thomas Martitz (1): macvlan: allow source mode devices along with passthru drivers/net/macvlan.c | 107 ++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 34 deletions(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/1] macvlan: allow source mode devices along with passthru 2026-07-09 10:05 [PATCH v2 0/1] macvlan: allow source mode devices along with passthru Thomas Martitz @ 2026-07-09 10:05 ` Thomas Martitz 2026-07-10 9:56 ` [syzbot ci] " syzbot ci 1 sibling, 0 replies; 4+ messages in thread From: Thomas Martitz @ 2026-07-09 10:05 UTC (permalink / raw) To: Simon Horman, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, open list:NETWORKING DRIVERS, open list Cc: Thomas Martitz, open list:NETWORKING DRIVERS, open list This allows for configurations where there are a few known senders in the system (e.g. multiple SoCs on the same board) along with unlimited external senders. The source mode devices represent the known senders while all external senders terminate on passthru device. Although you could still receive packets on the lower device without the need for the passthru vlan device, there are use cases where you need additional packet processing in the pipeline that hooks via rx_handler. But the rx_handler is already bound to the macvlan port. With this patch the rx_handler can be attached to the passthru device while macvlan itself remains attached to the lower device. We use this to use the share the only available high-speed interface for inter-SoC networking and external networking (user traffic). Inter-SoC packets are received on the source mode interface, identified by a well-known source address. Some of our chips have simply no other viable link for inter-SoC traffic. Signed-off-by: Thomas Martitz <t.martitz@fritz.com> --- drivers/net/macvlan.c | 107 ++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9a4bc99dbf53b..2505f5f2e9d30 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -83,6 +83,11 @@ static inline void macvlan_set_passthru(struct macvlan_port *port) port->flags |= MACVLAN_F_PASSTHRU; } +static inline void macvlan_clear_passthru(struct macvlan_port *port) +{ + port->flags &= ~MACVLAN_F_PASSTHRU; +} + static inline bool macvlan_addr_change(const struct macvlan_port *port) { return port->flags & MACVLAN_F_ADDRCHANGE; @@ -637,7 +642,7 @@ static int macvlan_open(struct net_device *dev) struct net_device *lowerdev = vlan->lowerdev; int err; - if (macvlan_passthru(vlan->port)) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) { err = dev_set_promiscuity(lowerdev, 1); if (err < 0) @@ -712,7 +717,7 @@ static int macvlan_stop(struct net_device *dev) dev_uc_unsync(lowerdev, dev); dev_mc_unsync(lowerdev, dev); - if (macvlan_passthru(vlan->port)) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) dev_set_promiscuity(lowerdev, -1); goto hash_del; @@ -792,6 +797,23 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) return macvlan_sync_address(dev, addr->__data); } +static void macvlan_port_release_mac(struct net_device *dev) +{ + struct macvlan_port *port = macvlan_port_get_rtnl(dev); + + /* If the lower device address has been changed by passthru + * macvlan, put it back. + */ + if (macvlan_passthru(port) && + !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) { + struct sockaddr_storage ss; + + ss.ss_family = port->dev->type; + memcpy(&ss.__data, port->perm_addr, port->dev->addr_len); + dev_set_mac_address(port->dev, &ss, NULL); + } +} + static void macvlan_change_rx_flags(struct net_device *dev, int change) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -977,8 +999,18 @@ static void macvlan_uninit(struct net_device *dev) macvlan_flush_sources(port, vlan); port->count -= 1; - if (!port->count) - macvlan_port_destroy(port->dev); + if (port->count) { + /* In case of remaining source interfaces undo + * passthru-specific properties. + */ + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { + macvlan_port_release_mac(dev); + macvlan_clear_passthru(vlan->port); + } + return; + } + + macvlan_port_destroy(port->dev); } static void macvlan_dev_get_stats64(struct net_device *dev, @@ -1052,7 +1084,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], /* Support unicast filter only on passthru devices. * Multicast filter should be allowed on all devices. */ - if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr)) + if (vlan->mode != MACVLAN_MODE_PASSTHRU && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (flags & NLM_F_REPLACE) @@ -1077,7 +1109,7 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], /* Support unicast filter only on passthru devices. * Multicast filter should be allowed on all devices. */ - if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr)) + if (vlan->mode != MACVLAN_MODE_PASSTHRU && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) @@ -1308,17 +1340,7 @@ static void macvlan_port_destroy(struct net_device *dev) kfree_skb(skb); } - /* If the lower device address has been changed by passthru - * macvlan, put it back. - */ - if (macvlan_passthru(port) && - !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) { - struct sockaddr_storage ss; - - ss.ss_family = port->dev->type; - memcpy(&ss.__data, port->perm_addr, port->dev->addr_len); - dev_set_mac_address(port->dev, &ss, NULL); - } + macvlan_port_release_mac(dev); kfree(port); } @@ -1506,15 +1528,6 @@ int macvlan_common_newlink(struct net_device *dev, } port = macvlan_port_get_rtnl(lowerdev); - /* Only 1 macvlan device can be created in passthru mode */ - if (macvlan_passthru(port)) { - /* The macvlan port must be not created this time, - * still goto destroy_macvlan_port for readability. - */ - err = -EINVAL; - goto destroy_macvlan_port; - } - vlan->lowerdev = lowerdev; vlan->dev = dev; vlan->port = port; @@ -1527,10 +1540,30 @@ int macvlan_common_newlink(struct net_device *dev, if (data && data[IFLA_MACVLAN_FLAGS]) vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); + /* Only 1 macvlan device can be created in passthru mode. There may be + * additional source mode devices but nothing else at the moment. + * + * First check if adding a source mode device to an existing passthru vlan. + */ + if (macvlan_passthru(port) && vlan->mode != MACVLAN_MODE_SOURCE) { + /* The macvlan port must be not created this time, + * still goto destroy_macvlan_port for readability. + */ + err = -EINVAL; + goto destroy_macvlan_port; + } + + /* Now check if adding a passthru device to an existing set of source mode + * devices. + */ if (vlan->mode == MACVLAN_MODE_PASSTHRU) { - if (port->count) { - err = -EINVAL; - goto destroy_macvlan_port; + struct macvlan_dev *p; + + list_for_each_entry(p, &port->vlans, list) { + if (p->mode != MACVLAN_MODE_SOURCE) { + err = -EINVAL; + goto destroy_macvlan_port; + } } macvlan_set_passthru(port); eth_hw_addr_inherit(dev, lowerdev); @@ -1564,7 +1597,11 @@ int macvlan_common_newlink(struct net_device *dev, if (err) goto unregister_netdev; - list_add_tail_rcu(&vlan->list, &port->vlans); + /* macvlan_handle_frame expects the (one and only) passthru device first. */ + if (vlan->mode == MACVLAN_MODE_PASSTHRU) + list_add_rcu(&vlan->list, &port->vlans); + else + list_add_tail_rcu(&vlan->list, &port->vlans); update_port_bc_queue_len(vlan->port); netif_stacked_transfer_operstate(lowerdev, dev); linkwatch_fire_event(dev); @@ -1627,9 +1664,11 @@ static int macvlan_changelink(struct net_device *dev, if (data && data[IFLA_MACVLAN_MODE]) { set_mode = true; mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); - /* Passthrough mode can't be set or cleared dynamically */ - if ((mode == MACVLAN_MODE_PASSTHRU) != - (vlan->mode == MACVLAN_MODE_PASSTHRU)) + /* Passthrough mode can't be set or cleared dynamically, + * regardless of existing source interfaces. Furthermore, source + * interfaces can't switch modes within a passhtrough port. + */ + if (macvlan_passthru(vlan->port) && mode != vlan->mode) return -EINVAL; if (vlan->mode == MACVLAN_MODE_SOURCE && vlan->mode != mode) @@ -1639,7 +1678,7 @@ static int macvlan_changelink(struct net_device *dev, if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; - if (macvlan_passthru(vlan->port) && promisc) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU && promisc) { int err; if (flags & MACVLAN_FLAG_NOPROMISC) -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [syzbot ci] Re: macvlan: allow source mode devices along with passthru 2026-07-09 10:05 [PATCH v2 0/1] macvlan: allow source mode devices along with passthru Thomas Martitz 2026-07-09 10:05 ` [PATCH v2 1/1] " Thomas Martitz @ 2026-07-10 9:56 ` syzbot ci 1 sibling, 0 replies; 4+ messages in thread From: syzbot ci @ 2026-07-10 9:56 UTC (permalink / raw) To: andrew, davem, edumazet, horms, kuba, linux-kernel, netdev, pabeni, t.martitz Cc: syzbot, syzkaller-bugs syzbot ci has tested the following series [v2] macvlan: allow source mode devices along with passthru https://lore.kernel.org/all/20260709100512.1383421-1-t.martitz@fritz.com * [PATCH v2 1/1] macvlan: allow source mode devices along with passthru and found the following issue: general protection fault in macvlan_port_release_mac Full report is available here: https://ci.syzbot.org/series/2632619d-fb66-47ac-85a1-a781bbb0d57d *** general protection fault in macvlan_port_release_mac tree: net-next URL: https://kernel.googlesource.com/pub/scm/linux/kernel/git/netdev/net-next.git base: fe3e786ef4eb6e47d2901f568a27bd920477bbe9 arch: amd64 compiler: Debian clang version 22.1.6 (++20260514074242+fc4aad7b5db3-1~exp1~20260514074407.73), Debian LLD 22.1.6 config: https://ci.syzbot.org/builds/90f86060-ab12-43d6-a718-5d0f5eb5df09/config syz repro: https://ci.syzbot.org/findings/d1f12788-51d7-4251-8fc9-6bfda6a1e20a/syz_repro batman_adv: batadv0: Removing interface: batadv_slave_1 veth1_macvtap: left promiscuous mode veth0_macvtap: left promiscuous mode veth1_vlan: left promiscuous mode veth0_vlan: left promiscuous mode Oops: general protection fault, probably for non-canonical address 0xdffffc0000000118: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x00000000000008c0-0x00000000000008c7] CPU: 0 UID: 0 PID: 12 Comm: kworker/u8:0 Not tainted syzkaller #0 PREEMPT(full) Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.2-debian-1.16.2-1 04/01/2014 Workqueue: netns cleanup_net RIP: 0010:macvlan_passthru drivers/net/macvlan.c:78 [inline] RIP: 0010:macvlan_port_release_mac+0x138/0x490 drivers/net/macvlan.c:807 Code: 01 00 00 48 89 d8 48 c1 e8 03 42 80 3c 20 00 74 08 48 89 df e8 b9 30 ae fb 48 8b 1b 4c 8d b3 c0 08 00 00 4c 89 f0 48 c1 e8 03 <42> 0f b6 04 20 84 c0 0f 85 44 02 00 00 45 8b 36 44 89 f6 83 e6 01 RSP: 0018:ffffc90000117500 EFLAGS: 00010206 RAX: 0000000000000118 RBX: 0000000000000000 RCX: ffff888102e98000 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 RBP: ffffc90000117630 R08: ffffffff9032faf7 R09: 1ffffffff2065f5e R10: dffffc0000000000 R11: fffffbfff2065f5f R12: dffffc0000000000 R13: 1ffff92000022ea4 R14: 00000000000008c0 R15: ffff88816b068818 FS: 0000000000000000(0000) GS:ffff88818dc23000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fb0fefe8158 CR3: 0000000113c9a000 CR4: 00000000000006f0 Call Trace: <TASK> macvlan_port_destroy+0x2eb/0x310 drivers/net/macvlan.c:1343 unregister_netdevice_many_notify+0x1ad2/0x2150 net/core/dev.c:12464 unregister_netdevice_many net/core/dev.c:12506 [inline] default_device_exit_batch+0x961/0x9e0 net/core/dev.c:13098 ops_exit_list net/core/net_namespace.c:205 [inline] ops_undo_list+0x4b4/0x8d0 net/core/net_namespace.c:252 cleanup_net+0x572/0x810 net/core/net_namespace.c:702 process_one_work kernel/workqueue.c:3322 [inline] process_scheduled_works+0xa8e/0x14e0 kernel/workqueue.c:3405 worker_thread+0xa47/0xfb0 kernel/workqueue.c:3486 kthread+0x388/0x470 kernel/kthread.c:436 ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 </TASK> Modules linked in: ---[ end trace 0000000000000000 ]--- RIP: 0010:macvlan_passthru drivers/net/macvlan.c:78 [inline] RIP: 0010:macvlan_port_release_mac+0x138/0x490 drivers/net/macvlan.c:807 Code: 01 00 00 48 89 d8 48 c1 e8 03 42 80 3c 20 00 74 08 48 89 df e8 b9 30 ae fb 48 8b 1b 4c 8d b3 c0 08 00 00 4c 89 f0 48 c1 e8 03 <42> 0f b6 04 20 84 c0 0f 85 44 02 00 00 45 8b 36 44 89 f6 83 e6 01 RSP: 0018:ffffc90000117500 EFLAGS: 00010206 RAX: 0000000000000118 RBX: 0000000000000000 RCX: ffff888102e98000 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 RBP: ffffc90000117630 R08: ffffffff9032faf7 R09: 1ffffffff2065f5e R10: dffffc0000000000 R11: fffffbfff2065f5f R12: dffffc0000000000 R13: 1ffff92000022ea4 R14: 00000000000008c0 R15: ffff88816b068818 FS: 0000000000000000(0000) GS:ffff88818dc23000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000001b33163fff CR3: 0000000175a06000 CR4: 00000000000006f0 ---------------- Code disassembly (best guess): 0: 01 00 add %eax,(%rax) 2: 00 48 89 add %cl,-0x77(%rax) 5: d8 48 c1 fmuls -0x3f(%rax) 8: e8 03 42 80 3c call 0x3c804210 d: 20 00 and %al,(%rax) f: 74 08 je 0x19 11: 48 89 df mov %rbx,%rdi 14: e8 b9 30 ae fb call 0xfbae30d2 19: 48 8b 1b mov (%rbx),%rbx 1c: 4c 8d b3 c0 08 00 00 lea 0x8c0(%rbx),%r14 23: 4c 89 f0 mov %r14,%rax 26: 48 c1 e8 03 shr $0x3,%rax * 2a: 42 0f b6 04 20 movzbl (%rax,%r12,1),%eax <-- trapping instruction 2f: 84 c0 test %al,%al 31: 0f 85 44 02 00 00 jne 0x27b 37: 45 8b 36 mov (%r14),%r14d 3a: 44 89 f6 mov %r14d,%esi 3d: 83 e6 01 and $0x1,%esi *** If these findings have caused you to resend the series or submit a separate fix, please add the following tag to your commit message: Tested-by: syzbot@syzkaller.appspotmail.com --- This report is generated by a bot. It may contain errors. syzbot ci engineers can be reached at syzkaller@googlegroups.com. To test a patch for this bug, please reply with `#syz test` (should be on a separate line). The patch should be attached to the email. Note: arguments like custom git repos and branches are not supported. ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH RESEND RFC 0/1] macvlan: allow source mode devices along with passthru @ 2026-07-02 6:56 Thomas Martitz 2026-07-09 9:11 ` [PATCH v2 " Thomas Martitz 0 siblings, 1 reply; 4+ messages in thread From: Thomas Martitz @ 2026-07-02 6:56 UTC (permalink / raw) To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, open list:NETWORKING DRIVERS, open list Cc: Thomas Martitz, open list:NETWORKING DRIVERS, open list Hello, we're trying to solve a use case on our devices where two SoC are connected on the same board, using the only available high-speed. One SoC runs the main Linux system including the full routing stack (FRITZ!OS) and the other SoC implements most of the GPON ONT side. The high-speed interface is of course also used for the user traffic. Therefore we must tell the inter-SoC traffic apart from the user traffic. We achieve this by matching the well-known MAC address of the ONT SoC. The user traffic passes through the ONT SoC without modifying MAC headers. Now we would like to use macvlan (with source mode devices) on the main SoC side for this but our routing stack requires the rx_handler to be available. Therefore macvlan is currently not an option. With this patch macvlan becomes an option because the current limitation of either "one passthru device" or "any other configuration" is relaxed for the combination of passthru and any number of source mode devices. This allows us to configure a source mode device for the other SoC and register an rx_handler for further processing on the passthru device. The patch is still in an RFC state. I am not 100% confident that all the cases where the code checks "macvlan_passthru(port)" are handled appropriately. I hope you can guide me a little bit and provide feedback on the general approach. Thanks in advance! Thomas Martitz (1): macvlan: allow source mode devices along with passthru drivers/net/macvlan.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 0/1] macvlan: allow source mode devices along with passthru 2026-07-02 6:56 [PATCH RESEND RFC 0/1] " Thomas Martitz @ 2026-07-09 9:11 ` Thomas Martitz 2026-07-09 9:11 ` [PATCH v2 1/1] " Thomas Martitz 0 siblings, 1 reply; 4+ messages in thread From: Thomas Martitz @ 2026-07-09 9:11 UTC (permalink / raw) To: Simon Horman, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, open list:NETWORKING DRIVERS, open list Cc: Thomas Martitz, open list:NETWORKING DRIVERS, open list Hello, we're trying to solve a use case on our devices where two SoC are connected on the same board, using the only available high-speed interface. One SoC runs the main Linux system including the full routing stack (FRITZ!OS) and the other SoC implements most of the GPON ONT side. The high-speed interface is of course also used for the user traffic. Therefore we must tell the inter-SoC traffic apart from the user traffic. We achieve this by matching the well-known MAC address of the ONT SoC. The user traffic passes through the ONT SoC without modifying MAC headers. Now we would like to use macvlan (with source mode devices) on the main SoC side for this but our routing stack requires the rx_handler to be available. Therefore macvlan is currently not an option. With this patch macvlan becomes an option because the current limitation of either "one passthru device" or "any other configuration" is relaxed for the combination of passthru and any number of source mode devices. This allows us to configure a source mode device for the other SoC and register an rx_handler for further processing on the passthru device. Thanks in advance! Thomas Martitz (1): macvlan: allow source mode devices along with passthru drivers/net/macvlan.c | 107 ++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 34 deletions(-) -- 2.54.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/1] macvlan: allow source mode devices along with passthru 2026-07-09 9:11 ` [PATCH v2 " Thomas Martitz @ 2026-07-09 9:11 ` Thomas Martitz 0 siblings, 0 replies; 4+ messages in thread From: Thomas Martitz @ 2026-07-09 9:11 UTC (permalink / raw) To: Simon Horman, Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni, open list:NETWORKING DRIVERS, open list Cc: Thomas Martitz, open list:NETWORKING DRIVERS, open list This allows for configurations where there are a few known senders in the system (e.g. multiple SoCs on the same board) along with unlimited external senders. The source mode devices represent the known senders while all external senders terminate on passthru device. Although you could still receive packets on the lower device without the need for the passthru vlan device, there are use cases where you need additional packet processing in the pipeline that hooks via rx_handler. But the rx_handler is already bound to the macvlan port. With this patch the rx_handler can be attached to the passthru device while macvlan itself remains attached to the lower device. We use this to use the share the only available high-speed interface for inter-SoC networking and external networking (user traffic). Inter-SoC packets are received on the source mode interface, identified by a well-known source address. Some of our chips have simply no other viable link for inter-SoC traffic. Signed-off-by: Thomas Martitz <t.martitz@fritz.com> --- drivers/net/macvlan.c | 107 ++++++++++++++++++++++++++++-------------- 1 file changed, 73 insertions(+), 34 deletions(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 9a4bc99dbf53b..2505f5f2e9d30 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -83,6 +83,11 @@ static inline void macvlan_set_passthru(struct macvlan_port *port) port->flags |= MACVLAN_F_PASSTHRU; } +static inline void macvlan_clear_passthru(struct macvlan_port *port) +{ + port->flags &= ~MACVLAN_F_PASSTHRU; +} + static inline bool macvlan_addr_change(const struct macvlan_port *port) { return port->flags & MACVLAN_F_ADDRCHANGE; @@ -637,7 +642,7 @@ static int macvlan_open(struct net_device *dev) struct net_device *lowerdev = vlan->lowerdev; int err; - if (macvlan_passthru(vlan->port)) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) { err = dev_set_promiscuity(lowerdev, 1); if (err < 0) @@ -712,7 +717,7 @@ static int macvlan_stop(struct net_device *dev) dev_uc_unsync(lowerdev, dev); dev_mc_unsync(lowerdev, dev); - if (macvlan_passthru(vlan->port)) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { if (!(vlan->flags & MACVLAN_FLAG_NOPROMISC)) dev_set_promiscuity(lowerdev, -1); goto hash_del; @@ -792,6 +797,23 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p) return macvlan_sync_address(dev, addr->__data); } +static void macvlan_port_release_mac(struct net_device *dev) +{ + struct macvlan_port *port = macvlan_port_get_rtnl(dev); + + /* If the lower device address has been changed by passthru + * macvlan, put it back. + */ + if (macvlan_passthru(port) && + !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) { + struct sockaddr_storage ss; + + ss.ss_family = port->dev->type; + memcpy(&ss.__data, port->perm_addr, port->dev->addr_len); + dev_set_mac_address(port->dev, &ss, NULL); + } +} + static void macvlan_change_rx_flags(struct net_device *dev, int change) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -977,8 +999,18 @@ static void macvlan_uninit(struct net_device *dev) macvlan_flush_sources(port, vlan); port->count -= 1; - if (!port->count) - macvlan_port_destroy(port->dev); + if (port->count) { + /* In case of remaining source interfaces undo + * passthru-specific properties. + */ + if (vlan->mode == MACVLAN_MODE_PASSTHRU) { + macvlan_port_release_mac(dev); + macvlan_clear_passthru(vlan->port); + } + return; + } + + macvlan_port_destroy(port->dev); } static void macvlan_dev_get_stats64(struct net_device *dev, @@ -1052,7 +1084,7 @@ static int macvlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], /* Support unicast filter only on passthru devices. * Multicast filter should be allowed on all devices. */ - if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr)) + if (vlan->mode != MACVLAN_MODE_PASSTHRU && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (flags & NLM_F_REPLACE) @@ -1077,7 +1109,7 @@ static int macvlan_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], /* Support unicast filter only on passthru devices. * Multicast filter should be allowed on all devices. */ - if (!macvlan_passthru(vlan->port) && is_unicast_ether_addr(addr)) + if (vlan->mode != MACVLAN_MODE_PASSTHRU && is_unicast_ether_addr(addr)) return -EOPNOTSUPP; if (is_unicast_ether_addr(addr)) @@ -1308,17 +1340,7 @@ static void macvlan_port_destroy(struct net_device *dev) kfree_skb(skb); } - /* If the lower device address has been changed by passthru - * macvlan, put it back. - */ - if (macvlan_passthru(port) && - !ether_addr_equal(port->dev->dev_addr, port->perm_addr)) { - struct sockaddr_storage ss; - - ss.ss_family = port->dev->type; - memcpy(&ss.__data, port->perm_addr, port->dev->addr_len); - dev_set_mac_address(port->dev, &ss, NULL); - } + macvlan_port_release_mac(dev); kfree(port); } @@ -1506,15 +1528,6 @@ int macvlan_common_newlink(struct net_device *dev, } port = macvlan_port_get_rtnl(lowerdev); - /* Only 1 macvlan device can be created in passthru mode */ - if (macvlan_passthru(port)) { - /* The macvlan port must be not created this time, - * still goto destroy_macvlan_port for readability. - */ - err = -EINVAL; - goto destroy_macvlan_port; - } - vlan->lowerdev = lowerdev; vlan->dev = dev; vlan->port = port; @@ -1527,10 +1540,30 @@ int macvlan_common_newlink(struct net_device *dev, if (data && data[IFLA_MACVLAN_FLAGS]) vlan->flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); + /* Only 1 macvlan device can be created in passthru mode. There may be + * additional source mode devices but nothing else at the moment. + * + * First check if adding a source mode device to an existing passthru vlan. + */ + if (macvlan_passthru(port) && vlan->mode != MACVLAN_MODE_SOURCE) { + /* The macvlan port must be not created this time, + * still goto destroy_macvlan_port for readability. + */ + err = -EINVAL; + goto destroy_macvlan_port; + } + + /* Now check if adding a passthru device to an existing set of source mode + * devices. + */ if (vlan->mode == MACVLAN_MODE_PASSTHRU) { - if (port->count) { - err = -EINVAL; - goto destroy_macvlan_port; + struct macvlan_dev *p; + + list_for_each_entry(p, &port->vlans, list) { + if (p->mode != MACVLAN_MODE_SOURCE) { + err = -EINVAL; + goto destroy_macvlan_port; + } } macvlan_set_passthru(port); eth_hw_addr_inherit(dev, lowerdev); @@ -1564,7 +1597,11 @@ int macvlan_common_newlink(struct net_device *dev, if (err) goto unregister_netdev; - list_add_tail_rcu(&vlan->list, &port->vlans); + /* macvlan_handle_frame expects the (one and only) passthru device first. */ + if (vlan->mode == MACVLAN_MODE_PASSTHRU) + list_add_rcu(&vlan->list, &port->vlans); + else + list_add_tail_rcu(&vlan->list, &port->vlans); update_port_bc_queue_len(vlan->port); netif_stacked_transfer_operstate(lowerdev, dev); linkwatch_fire_event(dev); @@ -1627,9 +1664,11 @@ static int macvlan_changelink(struct net_device *dev, if (data && data[IFLA_MACVLAN_MODE]) { set_mode = true; mode = nla_get_u32(data[IFLA_MACVLAN_MODE]); - /* Passthrough mode can't be set or cleared dynamically */ - if ((mode == MACVLAN_MODE_PASSTHRU) != - (vlan->mode == MACVLAN_MODE_PASSTHRU)) + /* Passthrough mode can't be set or cleared dynamically, + * regardless of existing source interfaces. Furthermore, source + * interfaces can't switch modes within a passhtrough port. + */ + if (macvlan_passthru(vlan->port) && mode != vlan->mode) return -EINVAL; if (vlan->mode == MACVLAN_MODE_SOURCE && vlan->mode != mode) @@ -1639,7 +1678,7 @@ static int macvlan_changelink(struct net_device *dev, if (data && data[IFLA_MACVLAN_FLAGS]) { __u16 flags = nla_get_u16(data[IFLA_MACVLAN_FLAGS]); bool promisc = (flags ^ vlan->flags) & MACVLAN_FLAG_NOPROMISC; - if (macvlan_passthru(vlan->port) && promisc) { + if (vlan->mode == MACVLAN_MODE_PASSTHRU && promisc) { int err; if (flags & MACVLAN_FLAG_NOPROMISC) -- 2.54.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-07-10 9:56 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-09 10:05 [PATCH v2 0/1] macvlan: allow source mode devices along with passthru Thomas Martitz 2026-07-09 10:05 ` [PATCH v2 1/1] " Thomas Martitz 2026-07-10 9:56 ` [syzbot ci] " syzbot ci -- strict thread matches above, loose matches on Subject: below -- 2026-07-02 6:56 [PATCH RESEND RFC 0/1] " Thomas Martitz 2026-07-09 9:11 ` [PATCH v2 " Thomas Martitz 2026-07-09 9:11 ` [PATCH v2 1/1] " Thomas Martitz
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox