runtime: add the mtu support for updating routes

Some cni plugins will set the MTU of some routes, such as cilium will
modify the MTU of the default route. If the mtu of the route is not set
correctly, it may cause excessive fragmentation or even packet loss of
network packets. Therefore, this PR adds the setting of the MTU of the
route. First, when obtaining the route, if the MTU is set, the MTU will
also be obtained and set to the route in the guest.

Signed-off-by: Fupan Li <fupan.lfp@antgroup.com>
This commit is contained in:
Fupan Li 2025-05-02 21:18:16 +08:00 committed by Fabiano Fidêncio
parent fbf7faa9f4
commit 492329fc02
9 changed files with 44 additions and 3 deletions

View File

@ -6,10 +6,13 @@
use anyhow::{anyhow, Context, Result};
use futures::{future, StreamExt, TryStreamExt};
use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network};
use netlink_packet_route::address::{AddressAttribute, AddressMessage};
use netlink_packet_route::link::{LinkAttribute, LinkMessage};
use netlink_packet_route::neighbour::{self, NeighbourFlag};
use netlink_packet_route::route::{RouteFlag, RouteHeader, RouteProtocol, RouteScope, RouteType};
use netlink_packet_route::{
address::{AddressAttribute, AddressMessage},
route::RouteMetric,
};
use netlink_packet_route::{
neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourState},
route::{RouteAddress, RouteAttribute, RouteMessage},
@ -388,6 +391,15 @@ impl Handle {
.unwrap_or_default();
}
if let RouteAttribute::Metrics(metrics) = attribute {
for m in metrics {
if let RouteMetric::Mtu(mtu) = m {
route.mtu = *mtu;
break;
}
}
}
if let RouteAttribute::Oif(index) = attribute {
route.device = self.find_link(LinkFilter::Index(*index)).await?.name();
}
@ -453,6 +465,13 @@ impl Handle {
message.header.flags = flags;
if route.mtu != 0 {
let route_metrics = vec![RouteMetric::Mtu(route.mtu)];
message
.attributes
.push(RouteAttribute::Metrics(route_metrics));
}
// `rtnetlink` offers a separate request builders for different IP versions (IP v4 and v6).
// This if branch is a bit clumsy because it does almost the same.
if route.family() == IPFamily::v6 {

View File

@ -59,6 +59,7 @@ message Route {
uint32 scope = 5;
IPFamily family = 6;
uint32 flags = 7;
uint32 mtu = 8;
}
message ARPNeighbor {

View File

@ -230,6 +230,7 @@ impl From<Route> for types::Route {
scope: from.scope,
family: protobuf::EnumOrUnknown::new(from.family.into()),
flags: from.flags,
mtu: from.mtu,
..Default::default()
}
}
@ -245,6 +246,7 @@ impl From<types::Route> for Route {
scope: src.scope,
family: src.family.unwrap().into(),
flags: src.flags,
mtu: src.mtu,
}
}
}

View File

@ -114,6 +114,7 @@ pub struct Route {
pub scope: u32,
pub family: IPFamily,
pub flags: u32,
pub mtu: u32,
}
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]

View File

@ -292,6 +292,8 @@ pub(crate) struct Route {
pub scope: u32,
#[serde(default)]
pub flags: u32,
#[serde(default)]
pub mtu: u32,
}
impl Route {
@ -369,7 +371,8 @@ mod tests {
"source": "172.18.0.1",
"gateway": "172.18.31.1",
"scope": 0,
"flags": 0
"flags": 0,
"mtu": 1450
}],
"neighbors": [{
"ip_address": "192.168.0.3/16",
@ -402,6 +405,7 @@ mod tests {
gateway: "172.18.31.1".to_owned(),
scope: 0,
flags: 0,
mtu: 1450,
}],
neighbors: vec![ARPNeighbor {
ip_address: Some("192.168.0.3/16".to_owned()),

View File

@ -75,6 +75,7 @@ impl NetworkInfoFromDan {
scope: route.scope,
family,
flags: route.flags,
mtu: route.mtu,
})
})
.collect();
@ -161,6 +162,7 @@ mod tests {
gateway: "172.18.31.1".to_owned(),
scope: 0,
flags: 0,
mtu: 1450,
}],
neighbors: vec![DanARPNeighbor {
ip_address: Some("192.168.0.3/16".to_owned()),
@ -197,6 +199,7 @@ mod tests {
scope: 0,
family: IPFamily::V4,
flags: 0,
mtu: 1450,
}];
assert_eq!(routes, network_info.routes().await.unwrap());

View File

@ -13,7 +13,7 @@ use futures::stream::TryStreamExt;
use netlink_packet_route::{
self,
neighbour::{NeighbourAddress, NeighbourAttribute, NeighbourMessage},
route::{RouteAddress, RouteAttribute, RouteMessage},
route::{RouteAddress, RouteAttribute, RouteMessage, RouteMetric},
};
use super::NetworkInfo;
@ -201,6 +201,14 @@ fn generate_route(name: &str, route_msg: &RouteMessage) -> Result<Option<Route>>
route.source = dest.to_string();
}
RouteAttribute::Metrics(metrics) => {
for m in metrics {
if let RouteMetric::Mtu(mtu) = m {
route.mtu = *mtu;
break;
}
}
}
_ => {}
}
}

View File

@ -310,6 +310,8 @@ func generateVCNetworkStructures(ctx context.Context, endpoints []Endpoint) ([]*
r.Scope = uint32(route.Scope)
r.Family = utils.ConvertAddressFamily((int32)(route.Family))
r.Flags = uint32(route.Flags)
r.Mtu = uint32(route.MTU)
routes = append(routes, &r)
}

View File

@ -308,6 +308,7 @@ type Route struct {
Scope uint32 `protobuf:"varint,5,opt,name=scope,proto3" json:"scope,omitempty"`
Family IPFamily `protobuf:"varint,6,opt,name=family,proto3,enum=types.IPFamily" json:"family,omitempty"`
Flags uint32 `protobuf:"varint,7,opt,name=flags,proto3" json:"flags,omitempty"`
Mtu uint32 `protobuf:"varint,8,opt,name=mtu,proto3" json:"mtu,omitempty"`
}
func (x *Route) Reset() {