Skip to content

Commit f5bc7c1

Browse files
committed
bridge: bind ip for aardvark-dns in unmanaged mode if gateway ip is not on the host
Signed-off-by: Shivang K Raghuvanshi <[email protected]>
1 parent 88c9c51 commit f5bc7c1

File tree

4 files changed

+60
-23
lines changed

4 files changed

+60
-23
lines changed

examples/host-device-plugin.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ impl Plugin for Exec {
5050
}
5151
}
5252

53-
let addresses = host.netlink.dump_addresses(None)?;
53+
let addresses = host.netlink.dump_addresses(None, None, None)?;
5454
let mut subnets = Vec::new();
5555
for address in addresses {
5656
if address.header.index == link.header.index {

src/network/bridge.rs

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use netlink_packet_route::link::{
66
BridgeVlanInfoFlags, InfoBridge, InfoData, InfoKind, InfoVeth, LinkAttribute, LinkInfo,
77
LinkMessage,
88
};
9+
use netlink_packet_route::{address::AddressScope, AddressFamily};
910

1011
use crate::dns::aardvark::SafeString;
1112
use crate::network::core_utils::get_default_route_interface;
@@ -166,7 +167,7 @@ impl driver::NetworkDriver for Bridge<'_> {
166167

167168
let (host_sock, netns_sock) = netlink_sockets;
168169

169-
let (container_veth_mac, sysctl_writer) = create_interfaces(
170+
let (container_veth_mac, sysctl_writer, bridge_index) = create_interfaces(
170171
host_sock,
171172
netns_sock,
172173
data,
@@ -252,18 +253,40 @@ impl driver::NetworkDriver for Bridge<'_> {
252253
}
253254
}
254255

255-
let gw = data
256-
.ipam
257-
.gateway_addresses
258-
.iter()
259-
.map(|ipnet| ipnet.addr())
260-
.collect();
256+
// Fixes #1177: In unmanaged mode, the gateway IP may not be on the host.
257+
// We need to find an IP on the bridge itself for aardvark-dns to bind to.
258+
let bind_addr: Vec<IpAddr> = if data.mode == BridgeMode::Unmanaged {
259+
let addresses = host_sock.dump_addresses(
260+
Some(bridge_index),
261+
Some(AddressFamily::Inet),
262+
Some(AddressScope::Universe),
263+
)?;
264+
let mut bind_addr = Vec::with_capacity(addresses.len());
265+
for addr_msg in addresses {
266+
for attr in addr_msg.attributes {
267+
if let netlink_packet_route::address::AddressAttribute::Address(ip) = attr {
268+
bind_addr.push(ip);
269+
}
270+
}
271+
}
272+
if bind_addr.is_empty() {
273+
return Err(NetavarkError::msg(format!("bridge '{}' in unmanaged mode has no universe scope IP addresses, but aardvark-dns requires at least one universe scope address to bind to. Please add an universe scope IP address or disable DNS for this network (--disable-dns).", data.bridge_interface_name)));
274+
}
275+
response.dns_server_ips = Some(bind_addr.clone());
276+
bind_addr
277+
} else {
278+
data.ipam
279+
.gateway_addresses
280+
.iter()
281+
.map(|ipnet| ipnet.addr())
282+
.collect()
283+
};
261284

262285
match self.info.container_id.as_str().try_into() {
263286
Ok(id) => Some(AardvarkEntry {
264287
network_name: &self.info.network.name,
265288
container_id: id,
266-
network_gateways: gw,
289+
network_gateways: bind_addr,
267290
network_dns_servers: &self.info.network.network_dns_servers,
268291
container_ips_v4: ipv4,
269292
container_ips_v6: ipv6,
@@ -556,6 +579,7 @@ fn create_interfaces(
556579
) -> NetavarkResult<(
557580
String,
558581
Option<sysctl::SysctlDWriter<'static, String, String>>,
582+
u32,
559583
)> {
560584
let mut sysctl_writer = None;
561585
let (bridge_index, mtu, mac) = match host.get_link(netlink::LinkID::Name(
@@ -738,7 +762,7 @@ fn create_interfaces(
738762
netns_fd,
739763
mtu,
740764
)?;
741-
Ok((mac, sysctl_writer))
765+
Ok((mac, sysctl_writer, bridge_index))
742766
}
743767

744768
/// return the container veth mac address

src/network/netlink.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use netlink_packet_core::{
1414
NLM_F_REQUEST,
1515
};
1616
use netlink_packet_route::{
17-
address::AddressMessage,
17+
address::{self, AddressMessage, AddressScope},
1818
link::{
1919
AfSpecBridge, BridgeVlanInfo, BridgeVlanInfoFlags, InfoBridge, InfoData, InfoKind,
2020
LinkAttribute, LinkFlags, LinkInfo, LinkMessage,
@@ -414,19 +414,20 @@ impl Socket {
414414
// If interface's LinkID is supplied, then only the ip addresses of that specific interface is returned. Otherwise all ip addresses of all interfaces are returned
415415
pub fn dump_addresses(
416416
&mut self,
417-
interface: Option<LinkID>,
417+
interface_id_filter: Option<u32>,
418+
address_filter: Option<AddressFamily>,
419+
scope_filter: Option<AddressScope>,
418420
) -> NetavarkResult<Vec<AddressMessage>> {
419421
let mut msg = AddressMessage::default();
420422

421-
match interface {
422-
Some(LinkID::ID(id)) => {
423-
msg.header.index = id;
424-
}
425-
Some(LinkID::Name(name)) => {
426-
let link_message = self.get_link(LinkID::Name(name))?;
427-
msg.header.index = link_message.header.index;
428-
}
429-
None => {}
423+
if let Some(id) = interface_id_filter {
424+
msg.header.index = id;
425+
}
426+
if let Some(addr_family) = address_filter {
427+
msg.header.family = addr_family;
428+
}
429+
if let Some(scope) = scope_filter {
430+
msg.header.scope = scope;
430431
}
431432

432433
let results =

src/test/netlink.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,9 @@ mod tests {
175175
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
176176
assert!(out.status.success(), "failed to set up lo via ip");
177177

178-
let addresses = sock.dump_addresses(None).expect("dump_addresses failed");
178+
let addresses = sock
179+
.dump_addresses(None, None, None)
180+
.expect("dump_addresses failed");
179181
for nla in addresses[0].attributes.iter() {
180182
if let address::AddressAttribute::Address(ip) = nla {
181183
assert_eq!(ip, &IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)))
@@ -206,8 +208,18 @@ mod tests {
206208
eprintln!("{}", String::from_utf8(out.stderr).unwrap());
207209
assert!(out.status.success(), "failed to set up lo via ip");
208210

211+
let bridge_id: u32 = sock
212+
.get_link(LinkID::Name("test1".to_string()))
213+
.expect("get_link failed")
214+
.header
215+
.index;
216+
209217
let addresses = sock
210-
.dump_addresses(Some(LinkID::Name("test1".to_string())))
218+
.dump_addresses(
219+
Some(bridge_id),
220+
Some(netlink_packet_route::AddressFamily::Inet),
221+
Some(address::AddressScope::Universe),
222+
)
211223
.expect("dump_address_filter failed");
212224
for nla in addresses[0].attributes.iter() {
213225
if let address::AddressAttribute::Address(ip) = nla {

0 commit comments

Comments
 (0)