From d9140ab7c34b15170c6fba4c77a47a8046d10f6b Mon Sep 17 00:00:00 2001 From: Red Bear OS Date: Thu, 9 Jul 2026 11:47:37 +0300 Subject: [PATCH] =?UTF-8?q?vxlan/gre/ipip:=20parent=20device=20integration?= =?UTF-8?q?=20=E2=80=94=20forward=20to=20parent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All three tunnel devices now forward encapsulated packets to their parent interface via DeviceList lookup, instead of dropping them (R43 drop fix) or self-looping (original behavior). Changes (same pattern as VLAN R63 fix): - Add devices: Rc> field to struct - Add devices parameter to constructor - send() looks up parent by name and forwards encapsulated frame - Falls back to debug log on parent-not-found VlanDevice already integrated (R63). Bond device already correct (forwards to slaves, no fix needed). All 31 tests pass. --- netstack/src/link/gre.rs | 17 +++++++++++++---- netstack/src/link/ipip.rs | 18 +++++++++++++----- netstack/src/link/vxlan.rs | 17 +++++++++++++---- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/netstack/src/link/gre.rs b/netstack/src/link/gre.rs index 293f506370..d9487a132f 100644 --- a/netstack/src/link/gre.rs +++ b/netstack/src/link/gre.rs @@ -19,6 +19,7 @@ //! With GRE key (8 bytes): //! [Flags 2B][Protocol 2B][Key 4B] +use std::cell::RefCell; use std::collections::VecDeque; use std::rc::Rc; @@ -27,7 +28,7 @@ use smoltcp::wire::{ EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Packet, Ipv4Repr, IpProtocol, }; -use super::LinkDevice; +use super::{DeviceList, LinkDevice}; const GRE_PROTO_IPV4: u16 = 0x0800; const GRE_FLAG_KEY: u16 = 0x2000; @@ -35,6 +36,7 @@ const GRE_FLAG_KEY: u16 = 0x2000; pub struct GreDevice { name: Rc, parent_name: Rc, + devices: Rc>, local_ip: Ipv4Address, remote_ip: Ipv4Address, gre_key: Option, @@ -53,6 +55,7 @@ impl GreDevice { local_ip: Ipv4Address, remote_ip: Ipv4Address, gre_key: Option, + devices: Rc>, ) -> Self { let mut header = [0u8; 8]; let header_len = if let Some(key) = gre_key { @@ -74,6 +77,7 @@ impl GreDevice { Self { name: name.into(), parent_name: parent_name.into(), + devices, local_ip, remote_ip, gre_key, @@ -146,9 +150,14 @@ impl GreDevice { } impl LinkDevice for GreDevice { - fn send(&mut self, _next_hop: IpAddress, packet: &[u8], _now: Instant) { - // No parent device reference — drop rather than self-loop. - log::debug!("gre: dropping {} byte frame (no parent device)", packet.len()); + fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) { + let encapsulated = self.build_encapsulated(packet).to_vec(); + if let Some(parent) = self.devices.borrow_mut().get_mut(&self.parent_name) { + parent.send(next_hop, &encapsulated, now); + } else { + log::debug!("gre: parent {} not found, dropping {} byte frame", + self.parent_name, packet.len()); + } } fn recv(&mut self, _now: Instant) -> Option<&[u8]> { diff --git a/netstack/src/link/ipip.rs b/netstack/src/link/ipip.rs index 7c6b635bd4..235d108bb4 100644 --- a/netstack/src/link/ipip.rs +++ b/netstack/src/link/ipip.rs @@ -10,6 +10,7 @@ //! the outer header is stripped and the inner packet is delivered to the //! network stack. +use std::cell::RefCell; use std::collections::VecDeque; use std::rc::Rc; @@ -18,13 +19,14 @@ use smoltcp::wire::{ EthernetAddress, IpAddress, IpCidr, Ipv4Address, Ipv4Packet, Ipv4Repr, IpProtocol, }; -use super::LinkDevice; +use super::{DeviceList, LinkDevice}; const IPIP_PROTO: u8 = 4; pub struct IpipDevice { name: Rc, parent_name: Rc, + devices: Rc>, local_ip: Ipv4Address, remote_ip: Ipv4Address, send_buffer: Vec, @@ -34,10 +36,11 @@ pub struct IpipDevice { } impl IpipDevice { - pub fn new(name: &str, parent_name: &str, local_ip: Ipv4Address, remote_ip: Ipv4Address) -> Self { + pub fn new(name: &str, parent_name: &str, local_ip: Ipv4Address, remote_ip: Ipv4Address, devices: Rc>) -> Self { Self { name: name.into(), parent_name: parent_name.into(), + devices, local_ip, remote_ip, send_buffer: Vec::with_capacity(1500), @@ -80,9 +83,14 @@ impl IpipDevice { } impl LinkDevice for IpipDevice { - fn send(&mut self, _next_hop: IpAddress, packet: &[u8], _now: Instant) { - // No parent device reference — drop rather than self-loop. - log::debug!("ipip: dropping {} byte frame (no parent device)", packet.len()); + fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) { + let encapsulated = self.build_outer_header(packet).to_vec(); + if let Some(parent) = self.devices.borrow_mut().get_mut(&self.parent_name) { + parent.send(next_hop, &encapsulated, now); + } else { + log::debug!("ipip: parent {} not found, dropping {} byte frame", + self.parent_name, packet.len()); + } } fn recv(&mut self, _now: Instant) -> Option<&[u8]> { diff --git a/netstack/src/link/vxlan.rs b/netstack/src/link/vxlan.rs index 76f5007dac..87f916a109 100644 --- a/netstack/src/link/vxlan.rs +++ b/netstack/src/link/vxlan.rs @@ -12,6 +12,7 @@ //! Packet structure: //! [Outer Eth][Outer IP][UDP:4789][VXLAN 8B][Inner Eth][Inner IP][Payload] +use std::cell::RefCell; use std::collections::VecDeque; use std::rc::Rc; @@ -21,7 +22,7 @@ use smoltcp::wire::{ Ipv4Address, Ipv4Packet, Ipv4Repr, IpProtocol, UdpPacket, UdpRepr, }; -use super::LinkDevice; +use super::{DeviceList, LinkDevice}; const VXLAN_PORT: u16 = 4789; const VXLAN_FLAGS: u8 = 0x08; @@ -29,6 +30,7 @@ const VXLAN_FLAGS: u8 = 0x08; pub struct VxlanDevice { name: Rc, parent_name: Rc, + devices: Rc>, local_ip: Ipv4Address, remote_ip: Ipv4Address, vni: u32, @@ -47,11 +49,13 @@ impl VxlanDevice { local_ip: Ipv4Address, remote_ip: Ipv4Address, vni: u32, + devices: Rc>, ) -> Self { let vni_bytes = vni.to_be_bytes(); Self { name: name.into(), parent_name: parent_name.into(), + devices, local_ip, remote_ip, vni: vni & 0x00ffffff, @@ -176,9 +180,14 @@ impl VxlanDevice { } impl LinkDevice for VxlanDevice { - fn send(&mut self, _next_hop: IpAddress, packet: &[u8], _now: Instant) { - // No parent device reference — drop rather than self-loop. - log::debug!("vxlan: dropping {} byte frame (no parent device)", packet.len()); + fn send(&mut self, next_hop: IpAddress, packet: &[u8], now: Instant) { + let enc = self.build_encapsulated(packet).to_vec(); + if let Some(parent) = self.devices.borrow_mut().get_mut(&self.parent_name) { + parent.send(next_hop, &enc, now); + } else { + log::debug!("vxlan: parent {} not found, dropping {} byte frame", + self.parent_name, packet.len()); + } } fn recv(&mut self, _now: Instant) -> Option<&[u8]> {