libcontainer/network/
link.rs1use std::os::fd::RawFd;
2
3use netlink_packet_core::{
4 NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REQUEST, NetlinkMessage, NetlinkPayload,
5};
6use netlink_packet_route::RouteNetlinkMessage;
7use netlink_packet_route::link::{LinkAttribute, LinkFlags, LinkMessage};
8
9use super::traits::{Client, NetlinkMessageHandler};
10use super::wrapper::ClientWrapper;
11use super::{NetlinkResponse, NetworkError, Result};
12
13pub struct LinkMessageHandler;
18
19impl NetlinkMessageHandler for LinkMessageHandler {
20 type Response = LinkMessage;
21
22 fn handle_payload(
23 &self,
24 payload: NetlinkPayload<RouteNetlinkMessage>,
25 ) -> Result<NetlinkResponse<Self::Response>> {
26 match payload {
27 NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewLink(link)) => {
28 Ok(NetlinkResponse::Success(link))
29 }
30 NetlinkPayload::Error(e) => match e.code {
31 None => Ok(NetlinkResponse::Success(LinkMessage::default())),
35 Some(code) => Ok(NetlinkResponse::Error(code.get())),
36 },
37 NetlinkPayload::Done(_) => Ok(NetlinkResponse::Done),
38 _ => Err(NetworkError::IO(std::io::Error::other(format!(
39 "Unexpected message type: {:?}",
40 payload
41 )))),
42 }
43 }
44}
45
46pub struct LinkClient {
51 client: ClientWrapper,
52}
53
54impl LinkClient {
55 pub fn new(client: ClientWrapper) -> Result<Self> {
61 Ok(Self { client })
62 }
63
64 pub fn get_by_name(&mut self, name: &str) -> Result<LinkMessage> {
74 let mut message = LinkMessage::default();
75 message
76 .attributes
77 .push(LinkAttribute::IfName(name.to_string()));
78
79 let mut req = NetlinkMessage::from(RouteNetlinkMessage::GetLink(message));
80 req.header.flags = NLM_F_REQUEST;
81 req.finalize();
82
83 self.client.send_and_receive(&req, LinkMessageHandler)
84 }
85
86 pub fn set_up(&mut self, index: u32) -> Result<()> {
96 let mut message = LinkMessage::default();
97 message.header.index = index;
98
99 let mut req = NetlinkMessage::from(RouteNetlinkMessage::SetLink(message));
100 if let NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(ref mut link)) =
101 req.payload
102 {
103 link.header.change_mask |= LinkFlags::Up;
105 link.header.flags |= LinkFlags::Up;
107 }
108 req.header.flags = NLM_F_REQUEST | NLM_F_ACK;
111 req.finalize();
112
113 self.client.send_and_receive(&req, LinkMessageHandler)?;
114 Ok(())
115 }
116
117 pub fn set_down(&mut self, index: u32) -> Result<()> {
127 let mut message = LinkMessage::default();
128 message.header.index = index;
129
130 let mut req = NetlinkMessage::from(RouteNetlinkMessage::SetLink(message));
131 if let NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(ref mut link)) =
132 req.payload
133 {
134 link.header.change_mask |= LinkFlags::Up;
136 link.header.flags.remove(LinkFlags::Up);
138 }
139 req.header.flags = NLM_F_REQUEST | NLM_F_ACK;
142 req.finalize();
143
144 self.client.send_and_receive(&req, LinkMessageHandler)?;
145 Ok(())
146 }
147
148 pub fn set_ns_fd(&mut self, index: u32, new_name: &str, ns_path: RawFd) -> Result<()> {
160 let mut message = LinkMessage::default();
161 message.header.index = index;
162 message
163 .attributes
164 .push(LinkAttribute::IfName(new_name.to_string()));
165 message.attributes.push(LinkAttribute::NetNsFd(ns_path));
166
167 let mut req = NetlinkMessage::from(RouteNetlinkMessage::SetLink(message));
168 req.header.flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
173 req.finalize();
174
175 self.client.send_and_receive(&req, LinkMessageHandler)?;
176 Ok(())
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use serial_test::serial;
183
184 use super::*;
185 use crate::network::NetlinkResponse;
186 use crate::network::fake::FakeNetlinkClient;
187 use crate::network::wrapper::{ClientWrapper, create_network_client};
188
189 #[test]
190 #[serial]
191 fn test_link_message_handler_success() {
192 let handler = LinkMessageHandler;
193 let mut link_msg = LinkMessage::default();
194 link_msg.header.index = 1;
195 link_msg
196 .attributes
197 .push(LinkAttribute::IfName("eth0".to_string()));
198
199 let payload = NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewLink(link_msg.clone()));
200 let result = handler.handle_payload(payload);
201
202 assert!(result.is_ok());
203 match result.unwrap() {
204 NetlinkResponse::Success(response) => {
205 assert_eq!(response.header.index, 1);
206 assert_eq!(response.attributes.len(), 1);
207 }
208 _ => panic!("Expected Success response"),
209 }
210 }
211
212 #[test]
213 #[serial]
214 fn test_link_message_handler_errorcode_zero() {
215 let handler = LinkMessageHandler;
216 let mut error_msg = netlink_packet_core::ErrorMessage::default();
217 error_msg.code = std::num::NonZeroI32::new(0);
218 let error_payload = NetlinkPayload::Error(error_msg);
219 let result = handler.handle_payload(error_payload);
220
221 assert!(result.is_ok());
222 match result.unwrap() {
223 NetlinkResponse::Success(_) => {}
224 _ => panic!("Expected Success response"),
225 }
226 }
227
228 #[test]
229 #[serial]
230 fn test_link_message_handler_error() {
231 let handler = LinkMessageHandler;
232 let mut error_msg = netlink_packet_core::ErrorMessage::default();
233 error_msg.code = std::num::NonZeroI32::new(1);
234 let error_payload = NetlinkPayload::Error(error_msg);
235 let result = handler.handle_payload(error_payload);
236
237 assert!(result.is_ok());
238 match result.unwrap() {
239 NetlinkResponse::Error(code) => {
240 assert_eq!(code, 1);
241 }
242 _ => panic!("Expected Error response"),
243 }
244 }
245
246 #[test]
247 #[serial]
248 fn test_link_message_handler_done() {
249 let handler = LinkMessageHandler;
250 let done_payload = NetlinkPayload::Done(netlink_packet_core::DoneMessage::default());
251 let result = handler.handle_payload(done_payload);
252
253 assert!(result.is_ok());
254 match result.unwrap() {
255 NetlinkResponse::Done => {}
256 _ => panic!("Expected Done response"),
257 }
258 }
259
260 #[test]
261 #[serial]
262 fn test_link_message_handler_unexpected() {
263 let handler = LinkMessageHandler;
264 let unexpected_payload = NetlinkPayload::InnerMessage(RouteNetlinkMessage::NewAddress(
265 netlink_packet_route::address::AddressMessage::default(),
266 ));
267 let result = handler.handle_payload(unexpected_payload);
268
269 assert!(result.is_err());
270 }
271
272 #[test]
273 #[serial]
274 fn test_link_client_new() {
275 let result = LinkClient::new(create_network_client());
276
277 assert!(result.is_ok());
278 }
279
280 #[test]
281 #[serial]
282 fn test_link_client_get_by_name_without_response() {
283 let fake_client = FakeNetlinkClient::new();
284 let mut link_client = LinkClient::new(ClientWrapper::Fake(fake_client)).unwrap();
285 let result = link_client.get_by_name("eth0");
286
287 assert!(result.is_err());
289 }
290
291 #[test]
292 #[serial]
293 fn test_link_client_get_by_name_with_response() {
294 let mut fake_client = FakeNetlinkClient::new();
295
296 let mut link1 = LinkMessage::default();
298 link1.header.index = 1;
299 link1
300 .attributes
301 .push(LinkAttribute::IfName("eth0".to_string()));
302
303 let responses = vec![RouteNetlinkMessage::NewLink(link1)];
304 fake_client.set_expected_responses(responses);
305
306 let mut link_client = LinkClient::new(ClientWrapper::Fake(fake_client)).unwrap();
307 let result = link_client.get_by_name("eth0");
308
309 assert!(result.is_ok());
311 let response = result.unwrap();
312 assert_eq!(response.header.index, 1);
313 assert_eq!(response.attributes.len(), 1);
314 }
315
316 #[test]
317 #[serial]
318 fn test_link_client_set_up_failure() {
319 let mut fake_client = FakeNetlinkClient::new();
320 fake_client.set_failure("Set up failed".to_string());
321
322 let client_wrapper = ClientWrapper::Fake(fake_client);
323 let mut link_client = LinkClient::new(client_wrapper).unwrap();
324
325 let result = link_client.set_up(1);
326 assert!(result.is_err());
327 }
328
329 #[test]
330 #[serial]
331 fn test_link_client_set_up_success() {
332 let mut fake_client = FakeNetlinkClient::new();
333
334 let mut error_msg = netlink_packet_core::ErrorMessage::default();
336 error_msg.code = std::num::NonZeroI32::new(0);
337 let responses = vec![RouteNetlinkMessage::NewLink(LinkMessage::default())];
338 fake_client.set_expected_responses(responses);
339
340 let client_wrapper = ClientWrapper::Fake(fake_client);
341 let mut link_client = LinkClient::new(client_wrapper).unwrap();
342
343 let result = link_client.set_up(42);
344 assert!(result.is_ok());
345
346 if let ClientWrapper::Fake(fake_client) = &mut link_client.client {
348 let send_calls = fake_client.get_send_calls();
349 assert_eq!(send_calls.len(), 1);
350
351 if let NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(link)) =
353 &send_calls[0].payload
354 {
355 assert_eq!(link.header.index, 42);
356 assert!(link.header.flags.contains(LinkFlags::Up));
357 assert!(link.header.change_mask.contains(LinkFlags::Up));
358 } else {
359 panic!("Expected SetLink message");
360 }
361
362 let expected_flags = NLM_F_REQUEST | NLM_F_ACK;
364 assert_eq!(send_calls[0].header.flags, expected_flags);
365 } else {
366 panic!("Expected Fake client");
367 }
368 }
369
370 #[test]
371 #[serial]
372 fn test_link_client_set_down_failure() {
373 let mut fake_client = FakeNetlinkClient::new();
374 fake_client.set_failure("Set down failed".to_string());
375
376 let client_wrapper = ClientWrapper::Fake(fake_client);
377 let mut link_client = LinkClient::new(client_wrapper).unwrap();
378
379 let result = link_client.set_down(1);
380 assert!(result.is_err());
381 }
382
383 #[test]
384 #[serial]
385 fn test_link_client_set_down_success() {
386 let mut fake_client = FakeNetlinkClient::new();
387
388 let responses = vec![RouteNetlinkMessage::NewLink(LinkMessage::default())];
389 fake_client.set_expected_responses(responses);
390
391 let client_wrapper = ClientWrapper::Fake(fake_client);
392 let mut link_client = LinkClient::new(client_wrapper).unwrap();
393
394 let result = link_client.set_down(42);
395 assert!(result.is_ok());
396
397 if let ClientWrapper::Fake(fake_client) = &mut link_client.client {
399 let send_calls = fake_client.get_send_calls();
400 assert_eq!(send_calls.len(), 1);
401
402 if let NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(link)) =
404 &send_calls[0].payload
405 {
406 assert_eq!(link.header.index, 42);
407 assert!(!link.header.flags.contains(LinkFlags::Up));
408 assert!(link.header.change_mask.contains(LinkFlags::Up));
409 } else {
410 panic!("Expected SetLink message");
411 }
412
413 let expected_flags = NLM_F_REQUEST | NLM_F_ACK;
415 assert_eq!(send_calls[0].header.flags, expected_flags);
416 } else {
417 panic!("Expected Fake client");
418 }
419 }
420
421 #[test]
422 #[serial]
423 fn test_link_client_set_ns_fd_failure() {
424 let mut fake_client = FakeNetlinkClient::new();
425 fake_client.set_failure("Set namespace failed".to_string());
426
427 let client_wrapper = ClientWrapper::Fake(fake_client);
428 let mut link_client = LinkClient::new(client_wrapper).unwrap();
429
430 let result = link_client.set_ns_fd(1, "veth0", 123);
431 assert!(result.is_err());
432 }
433
434 #[test]
435 #[serial]
436 fn test_link_client_set_ns_fd_success() {
437 let mut fake_client = FakeNetlinkClient::new();
438
439 let responses = vec![RouteNetlinkMessage::NewLink(LinkMessage::default())];
440 fake_client.set_expected_responses(responses);
441
442 let client_wrapper = ClientWrapper::Fake(fake_client);
443 let mut link_client = LinkClient::new(client_wrapper).unwrap();
444
445 let result = link_client.set_ns_fd(42, "new_veth", 456);
446 assert!(result.is_ok());
447
448 if let ClientWrapper::Fake(fake_client) = &mut link_client.client {
450 let send_calls = fake_client.get_send_calls();
451 assert_eq!(send_calls.len(), 1);
452
453 if let NetlinkPayload::InnerMessage(RouteNetlinkMessage::SetLink(link)) =
455 &send_calls[0].payload
456 {
457 assert_eq!(link.header.index, 42);
458 assert_eq!(link.attributes.len(), 2);
459
460 let mut found_ifname = false;
462 let mut found_netns_fd = false;
463 for attr in &link.attributes {
464 match attr {
465 LinkAttribute::IfName(name) => {
466 assert_eq!(name, "new_veth");
467 found_ifname = true;
468 }
469 LinkAttribute::NetNsFd(fd) => {
470 assert_eq!(*fd, 456);
471 found_netns_fd = true;
472 }
473 _ => {}
474 }
475 }
476 assert!(found_ifname, "IfName attribute not found");
477 assert!(found_netns_fd, "NetNsFd attribute not found");
478 } else {
479 panic!("Expected SetLink message");
480 }
481
482 let expected_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE;
484 assert_eq!(send_calls[0].header.flags, expected_flags);
485 } else {
486 panic!("Expected Fake client");
487 }
488 }
489}