Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion kernel/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ linkme = "=0.3.27"
num = { version = "=0.4.0", default-features = false }
num-derive = "=0.3"
num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num-traits.git", rev = "1597c1c", default-features = false }
smoltcp = { version = "=0.12.0", git = "https://github.com/DragonOS-Community/smoltcp", rev = "4b83f9f30d13df5ddea169db015bec3c01208d77", default-features = false, features = [
smoltcp = { version = "=0.12.0", git = "https://github.com/DragonOS-Community/smoltcp.git", rev = "a2c9cc0da88f41baab5ecc603c33af68384d4cea", default-features = false, features = [
"alloc",
"medium-ethernet",
"socket-raw",
Expand Down
63 changes: 39 additions & 24 deletions kernel/src/driver/net/iface_common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,11 @@ impl IfaceCommon {
|| nft_ruleset.as_ref().is_some_and(|ruleset| {
ruleset.requires_route_lookup() || ruleset.has_output_hook()
});
let router = if needs_routed_poll {
// ARP ownership needs the namespace FIB even on an otherwise
// unfiltered Ethernet fast path. A read view alone must not
// switch IP output backends or local-input polling modes.
let needs_route_view = needs_routed_poll || self.type_ == InterfaceType::ETHER;
let router = if needs_route_view {
netns.as_ref().map(|netns| netns.router())
} else {
None
Expand All @@ -810,7 +814,7 @@ impl IfaceCommon {
{
return false;
}
let routed_this_round = route_policy.is_some();
let routed_this_round = needs_routed_poll && route_policy.is_some();
let owner_is_up = scope == IfacePollScope::Full;

let Some(_poll_guard) = self.enter_poll_epoch(namespace_epoch) else {
Expand Down Expand Up @@ -853,16 +857,20 @@ impl IfaceCommon {
force_authoritative |= restart == PollModeRecheck::Authoritative;
continue;
}
let backend_policy = route_policy.as_ref().map(|routes| OutputBackendPolicy {
netns: netns.as_deref().unwrap(),
routes,
ruleset: nft_ruleset.as_deref(),
device_names: &nft_device_names,
configured_neighbors: configured_neighbors.as_ref(),
owner_ifindex: self.iface_id as u32,
owner_is_up,
authoritative_output,
});
let backend_policy =
route_policy
.as_ref()
.filter(|_| routed_this_round)
.map(|routes| OutputBackendPolicy {
netns: netns.as_deref().unwrap(),
routes,
ruleset: nft_ruleset.as_deref(),
device_names: &nft_device_names,
configured_neighbors: configured_neighbors.as_ref(),
owner_ifindex: self.iface_id as u32,
owner_is_up,
authoritative_output,
});

let ingress_stage = Cell::new(IngressStage::Pending);
let handoff_broadcast = Cell::new(false);
Expand Down Expand Up @@ -1143,7 +1151,10 @@ impl IfaceCommon {
|| nft_ruleset.as_ref().is_some_and(|ruleset| {
ruleset.requires_route_lookup() || ruleset.has_output_hook()
});
let router = if needs_routed_poll {
// Keep ARP address ownership independent of nft/conntrack and
// of the IP TX backend selected for this NAPI round.
let needs_route_view = needs_routed_poll || self.type_ == InterfaceType::ETHER;
let router = if needs_route_view {
netns.as_ref().map(|netns| netns.router())
} else {
None
Expand All @@ -1160,7 +1171,7 @@ impl IfaceCommon {
{
return napi::NapiPollResult::new(0, true);
}
let routed_this_round = route_policy.is_some();
let routed_this_round = needs_routed_poll && route_policy.is_some();
let owner_is_up = scope == IfacePollScope::Full;

let Some(_poll_guard) = self.enter_poll_epoch(namespace_epoch) else {
Expand Down Expand Up @@ -1200,16 +1211,20 @@ impl IfaceCommon {
force_authoritative |= restart == PollModeRecheck::Authoritative;
continue;
}
let backend_policy = route_policy.as_ref().map(|routes| OutputBackendPolicy {
netns: netns.as_deref().unwrap(),
routes,
ruleset: nft_ruleset.as_deref(),
device_names: &nft_device_names,
configured_neighbors: configured_neighbors.as_ref(),
owner_ifindex: self.iface_id as u32,
owner_is_up,
authoritative_output,
});
let backend_policy =
route_policy
.as_ref()
.filter(|_| routed_this_round)
.map(|routes| OutputBackendPolicy {
netns: netns.as_deref().unwrap(),
routes,
ruleset: nft_ruleset.as_deref(),
device_names: &nft_device_names,
configured_neighbors: configured_neighbors.as_ref(),
owner_ifindex: self.iface_id as u32,
owner_is_up,
authoritative_output,
});

let mut ingress_work: Vec<RoutedIngressWork> = Vec::new();
let (processed, had_packet, ingress_budget, poll_again, deadline_rearm) = {
Expand Down
22 changes: 21 additions & 1 deletion kernel/src/net/ingress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use smoltcp::{
phy::PacketMeta,
wire::{
ipv6::AddressExt, EthernetAddress, HardwareAddress, Icmpv6Message, IpAddress, IpProtocol,
IpVersion, Ipv4Packet, Ipv6ExtHeader, Ipv6Packet,
IpVersion, Ipv4Address, Ipv4Packet, Ipv6ExtHeader, Ipv6Packet,
},
};
use system_error::SystemError;
Expand Down Expand Up @@ -853,6 +853,26 @@ fn is_ipv6_ndisc(packet: &Ipv6Packet<&[u8]>) -> bool {
}

impl IpIngressFilter for NetIngressFilter<'_> {
fn arp_reply_allowed(&self, source: Ipv4Address, target: Ipv4Address) -> Option<bool> {
// Linux's default Ethernet ARP policy does not expose loopback or
// multicast targets. IP AnyIP admission is not proxy-ARP permission.
let sender_allowed =
source.is_unspecified() || (!source.is_loopback() && source.octets()[0] != 0);
let allowed = sender_allowed
&& !target.is_unspecified()
&& !target.is_loopback()
&& !target.is_multicast()
&& target != Ipv4Address::BROADCAST
&& self.fib_routes.is_some_and(|routes| {
routes
.lookup_ingress(target.into(), self.owner_ifindex)
.is_some_and(|route| route.matched.kind == RTN_LOCAL)
});
// Never fall back to smoltcp's AnyIP ARP replies when this integration
// cannot establish ownership from its pre-acquired namespace view.
Some(allowed)
}

fn continue_ingress_poll(&self) -> bool {
let current = self.ruleset.generation == self.netns.nftables().generation();
if current {
Expand Down
Loading
Loading