vxlan/gre/ipip: parent device integration — forward to parent

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<RefCell<DeviceList>> 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.
This commit is contained in:
Red Bear OS
2026-07-09 11:47:37 +03:00
parent 2551784cea
commit d9140ab7c3
3 changed files with 39 additions and 13 deletions
+13 -4
View File
@@ -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<str>,
parent_name: Rc<str>,
devices: Rc<RefCell<DeviceList>>,
local_ip: Ipv4Address,
remote_ip: Ipv4Address,
gre_key: Option<u32>,
@@ -53,6 +55,7 @@ impl GreDevice {
local_ip: Ipv4Address,
remote_ip: Ipv4Address,
gre_key: Option<u32>,
devices: Rc<RefCell<DeviceList>>,
) -> 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]> {
+13 -5
View File
@@ -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<str>,
parent_name: Rc<str>,
devices: Rc<RefCell<DeviceList>>,
local_ip: Ipv4Address,
remote_ip: Ipv4Address,
send_buffer: Vec<u8>,
@@ -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<RefCell<DeviceList>>) -> 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]> {
+13 -4
View File
@@ -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<str>,
parent_name: Rc<str>,
devices: Rc<RefCell<DeviceList>>,
local_ip: Ipv4Address,
remote_ip: Ipv4Address,
vni: u32,
@@ -47,11 +49,13 @@ impl VxlanDevice {
local_ip: Ipv4Address,
remote_ip: Ipv4Address,
vni: u32,
devices: Rc<RefCell<DeviceList>>,
) -> 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]> {