1use netlink_packet_core::constants::*;
21use netlink_packet_core::NetlinkPayload::InnerMessage;
22use netlink_packet_core::*;
23use netlink_packet_route::RtnlMessage::*;
24use netlink_packet_route::{constants::*, AddressMessage, LinkMessage, RouteMessage, RtnlMessage};
25use netlink_sys::TokioSocket as Socket;
26use netlink_sys::{protocols, AsyncSocket as _, AsyncSocketExt as _, SocketAddr};
27
28#[cfg(not(test))]
29use log::{trace, warn};
30
31#[cfg(test)]
32use {println as trace, println as warn};
33
34#[derive(Clone, PartialEq, Eq)]
35pub enum LinkLayer {
36 Ethernet([u8; 6]),
37 None,
38}
39
40impl std::fmt::Debug for LinkLayer {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 match *self {
43 LinkLayer::Ethernet(e) => write!(
44 f,
45 "Ethernet({})",
46 e.iter()
47 .map(|b| format!("{:0>2x}", b))
48 .collect::<Vec<String>>()
49 .join(":")
50 ),
51 LinkLayer::None => write!(f, "None"),
52 }
53 }
54}
55
56#[derive(Debug, Clone, Copy)]
57pub struct IfFlags(u32);
58
59impl IfFlags {
60 pub const fn has_multicast(&self) -> bool {
61 self.0 & IFF_MULTICAST != 0
62 }
63}
64
65#[derive(Debug)]
66struct IfInfo {
67 name: String,
68 addresses: Vec<(std::net::IpAddr, u8)>,
69 lladdr: LinkLayer,
70 mtu: u32,
71 flags: IfFlags,
73}
74
75#[derive(Debug, Eq, PartialEq)]
76pub struct RouteInfo {
77 pub addr: std::net::IpAddr,
78 pub prefixlen: u8,
79 pub oifidx: Option<u32>,
80 pub nexthop: Option<std::net::IpAddr>,
81}
82
83impl std::fmt::Display for RouteInfo {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(f, "{}/{}", self.addr, self.prefixlen)?;
86 if let Some(nexthop) = self.nexthop {
87 write!(f, " via {}", nexthop)?;
88 }
89 if let Some(oifidx) = self.oifidx {
90 write!(f, " dev if#{}", oifidx)?;
91 }
92 Ok(())
93 }
94}
95
96#[derive(Debug)]
97struct NetInfo {
98 name2idx: std::collections::HashMap<String, u32>,
99 intf: std::collections::HashMap<u32, IfInfo>,
100 routeinfo: Vec<RouteInfo>,
101}
102
103impl NetInfo {
104 fn new() -> Self {
105 NetInfo {
106 name2idx: std::collections::HashMap::new(),
107 intf: std::collections::HashMap::new(),
108 routeinfo: vec![],
109 }
110 }
111 fn add_interface(&mut self, ifidx: u32, ifinfo: IfInfo) {
112 self.name2idx.insert(ifinfo.name.clone(), ifidx);
113 self.intf.insert(ifidx, ifinfo);
114 }
115}
116
117#[derive(Clone)]
118pub struct SharedNetInfo(std::sync::Arc<tokio::sync::RwLock<NetInfo>>);
119
120fn convert_address(addr: &[u8], family: u16) -> std::net::IpAddr {
121 match family {
122 AF_INET => {
123 std::net::IpAddr::V4(std::net::Ipv4Addr::new(addr[0], addr[1], addr[2], addr[3]))
124 }
125 AF_INET6 => std::net::IpAddr::V6(
126 [
127 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8],
128 addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15],
129 ]
130 .into(),
131 ),
132 x => panic!("Unknown address family {:?}", x),
133 }
134}
135
136struct NetLinkNetInfo {}
137
138impl NetLinkNetInfo {
139 fn decode_linklayer(linktype: u16, addr: &[u8]) -> LinkLayer {
140 match linktype {
141 ARPHRD_ETHER => {
142 LinkLayer::Ethernet([addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]])
143 }
144 ARPHRD_LOOPBACK => LinkLayer::None,
145 ARPHRD_SIT => LinkLayer::None, l => {
147 warn!("Unknown Linklayer: {:?}", l);
148 LinkLayer::None
149 }
150 }
151 }
152
153 fn parse_addr(addr: &AddressMessage) -> (std::net::IpAddr, u8) {
154 use netlink_packet_route::address::nlas::Nla::*;
155 let mut ifaddr = None;
156 let iffamily = addr.header.family;
157 let ifprefixlen = addr.header.prefix_len;
158 for i in &addr.nlas {
159 if let Address(a) = i {
160 ifaddr = Some(convert_address(a, iffamily.into()));
161 }
162 }
163 (ifaddr.unwrap(), ifprefixlen)
164 }
165
166 async fn process_newaddr(ni: &SharedNetInfo, addr: &AddressMessage) {
167 let ifindex = addr.header.index;
168 let ifaddr = NetLinkNetInfo::parse_addr(addr);
169 let mut ni = ni.0.write().await;
170 let ii = ni.intf.get_mut(&ifindex).unwrap(); if !ii.addresses.contains(&ifaddr) {
172 ii.addresses.push(ifaddr);
176 let (ip, prefixlen) = ifaddr;
177 trace!(
178 "Found addr {}/{} for {}(#{}), now {:?}",
179 ip,
180 prefixlen,
181 ii.name,
182 ifindex,
183 ii.addresses
184 );
185 }
186 }
187
188 async fn process_deladdr(sni: &SharedNetInfo, addr: &AddressMessage) {
189 let ifindex = addr.header.index;
190 let ifaddr = NetLinkNetInfo::parse_addr(addr);
191 let mut ni = sni.0.write().await;
192 let ii = ni.intf.get_mut(&ifindex).unwrap(); ii.addresses.retain(|&x| x != ifaddr);
194 let (ip, prefixlen) = ifaddr;
195 trace!(
196 "Lost addr {}/{} for {}(#{}), now {:?}",
197 ip,
198 prefixlen,
199 ii.name,
200 ifindex,
201 ii.addresses
202 );
203 }
204
205 async fn process_newlink(sni: &SharedNetInfo, link: &LinkMessage) {
206 use netlink_packet_route::link::nlas::Nla::*;
207 let mut ifname: Option<String> = None;
208 let mut ifmtu: Option<u32> = None;
209 let mut ifaddr = None;
210 let ifflags = link.header.flags;
211 let ifidx = link.header.index;
212 for i in &link.nlas {
213 match i {
214 IfName(name) => ifname = Some(name.clone()),
215 Mtu(mtu) => ifmtu = Some(*mtu),
216 Address(addr) => ifaddr = Some(addr.clone()),
217 _ => (),
218 }
219 }
220 let ifaddr = ifaddr.map_or(LinkLayer::None, |x| {
221 NetLinkNetInfo::decode_linklayer(link.header.link_layer_type, &x)
222 });
223
224 let mut netinfo = sni.0.write().await;
225 let old_ifinfo = netinfo.intf.remove(&ifidx);
230 let (old_name, old_addresses, old_mtu) = old_ifinfo
231 .map(|x| (Some(x.name), Some(x.addresses), Some(x.mtu)))
232 .unwrap_or((None, None, None));
233 let ifinfo = IfInfo {
234 name: ifname.or(old_name).expect("Interface with unknown name"),
235 mtu: ifmtu.or(old_mtu).expect("Interface missing MTU"),
236 addresses: old_addresses.unwrap_or_default(),
237 lladdr: ifaddr,
238 flags: IfFlags(ifflags),
239 };
240
241 trace!(
242 "Found new interface {}(#{}) {:?} ({:?})",
243 ifinfo.name,
244 ifidx,
245 ifinfo,
246 link
247 );
248 netinfo.add_interface(ifidx, ifinfo);
249 }
250
251 fn decode_route(route: &RouteMessage) -> Option<RouteInfo> {
252 use netlink_packet_route::rtnl::nlas::route::Nla::*;
253 use std::convert::TryFrom as _;
254 let mut destination = None;
255 let mut oifidx = None;
256 let mut gateway = None;
257 for nla in &route.nlas {
258 match nla {
259 Destination(dest) => {
260 destination = match route.header.address_family as u16 {
261 AF_INET => <[u8; 4]>::try_from(&dest[..])
262 .map(std::net::IpAddr::from)
263 .ok(),
264 AF_INET6 => <[u8; 16]>::try_from(&dest[..])
265 .map(std::net::IpAddr::from)
266 .ok(),
267 f => panic!("Unexpected family {}", f),
268 }
269 }
270 Gateway(via) => {
271 gateway = match route.header.address_family as u16 {
272 AF_INET => <[u8; 4]>::try_from(&via[..])
273 .map(std::net::IpAddr::from)
274 .ok(),
275 AF_INET6 => <[u8; 16]>::try_from(&via[..])
276 .map(std::net::IpAddr::from)
277 .ok(),
278 f => panic!("Unexpected family {}", f),
279 }
280 }
281 Oif(oif) => oifidx = Some(oif),
282 Table(254) => (),
283 Table(_) => return None, _ => (), }
286 }
287 Some(RouteInfo {
288 addr: destination.unwrap_or_else(|| match route.header.address_family as u16 {
289 AF_INET => "0.0.0.0".parse().unwrap(),
290 AF_INET6 => "::".parse().unwrap(),
291 _ => unreachable!(),
292 }),
293 prefixlen: route.header.destination_prefix_length,
294 oifidx: oifidx.copied(),
295 nexthop: gateway,
296 })
297 }
298
299 async fn process_newroute(sni: &SharedNetInfo, route: &RouteMessage) {
300 if let Some(ri) = NetLinkNetInfo::decode_route(route) {
301 trace!("New Route: {}", ri);
302 sni.0.write().await.routeinfo.push(ri);
303 }
304 }
305
306 async fn process_delroute(sni: &SharedNetInfo, route: &RouteMessage) {
307 if let Some(ri) = NetLinkNetInfo::decode_route(route) {
308 trace!("Del Route: {}", ri);
309 sni.0.write().await.routeinfo.retain(|r| *r != ri);
314 }
315 }
316
317 async fn send_linkdump(socket: &mut Socket, seq: &mut u32) {
318 let mut hdr = NetlinkHeader::default();
319 hdr.flags = NLM_F_REQUEST | NLM_F_DUMP;
320 hdr.sequence_number = *seq;
321 let mut packet = NetlinkMessage::new(
322 hdr,
323 NetlinkPayload::from(RtnlMessage::GetLink(LinkMessage::default())),
324 );
325 *seq += 1;
326
327 packet.finalize();
328
329 let mut buf = vec![0; packet.header.length as usize];
330
331 assert!(buf.len() == packet.buffer_len());
335
336 packet.serialize(&mut buf[..]);
337
338 socket.socket_mut().add_membership(RTNLGRP_LINK).unwrap();
339
340 if let Err(e) = socket.send(&buf[..]).await {
341 warn!("SEND ERROR {}", e);
342 }
343 }
344
345 async fn send_routedump(socket: &mut Socket, seq: &mut u32, address_family: u8) {
346 let mut hdr = NetlinkHeader::default();
347 hdr.flags = NLM_F_REQUEST | NLM_F_DUMP;
348 hdr.sequence_number = *seq;
349 let mut rmsg = RouteMessage::default();
350 rmsg.header.address_family = address_family;
351 let mut packet =
352 NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::GetRoute(rmsg)));
353
354 *seq += 1;
355
356 packet.finalize();
357
358 let mut buf = vec![0; packet.header.length as usize];
359
360 assert!(buf.len() == packet.buffer_len());
364
365 packet.serialize(&mut buf[..]);
366
367 match address_family as u16 {
368 AF_INET => socket
369 .socket_mut()
370 .add_membership(RTNLGRP_IPV4_ROUTE)
371 .unwrap(),
372 AF_INET6 => socket
373 .socket_mut()
374 .add_membership(RTNLGRP_IPV6_ROUTE)
375 .unwrap(),
376 _ => unreachable!(),
377 }
378
379 if let Err(e) = socket.send(&buf[..]).await {
380 warn!("SEND ERROR {}", e);
381 }
382 }
383
384 async fn send_addrdump(socket: &mut Socket, seq: &mut u32) {
385 let mut hdr = NetlinkHeader::default();
386 hdr.flags = NLM_F_REQUEST | NLM_F_DUMP;
387 hdr.sequence_number = *seq;
388
389 let mut amsg = AddressMessage::default();
390 amsg.header.family = AF_PACKET as u8;
391
392 let mut packet =
393 NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::GetAddress(amsg)));
394
395 *seq += 1;
396
397 packet.finalize();
398
399 let mut buf = vec![0; packet.header.length as usize];
400
401 assert!(buf.len() == packet.buffer_len());
405
406 packet.serialize(&mut buf[..]);
407
408 socket
409 .socket_mut()
410 .add_membership(RTNLGRP_IPV4_IFADDR)
411 .unwrap();
412 socket
413 .socket_mut()
414 .add_membership(RTNLGRP_IPV6_IFADDR)
415 .unwrap();
416
417 if let Err(e) = socket.send(&buf[..]).await {
418 warn!("SEND ERROR {}", e);
419 }
420 }
421
422 async fn process_message(sni: &SharedNetInfo, rx_packet: &NetlinkMessage<RtnlMessage>) -> bool {
423 match &rx_packet.payload {
424 InnerMessage(NewLink(link)) => {
425 NetLinkNetInfo::process_newlink(sni, link).await;
426 false
427 }
428 InnerMessage(NewAddress(addr)) => {
429 NetLinkNetInfo::process_newaddr(sni, addr).await;
430 false
431 }
432 InnerMessage(DelAddress(addr)) => {
433 NetLinkNetInfo::process_deladdr(sni, addr).await;
434 false
435 }
436 InnerMessage(NewRoute(route)) => {
437 NetLinkNetInfo::process_newroute(sni, route).await;
438 false
439 }
440 InnerMessage(DelRoute(route)) => {
441 NetLinkNetInfo::process_delroute(sni, route).await;
442 false
443 }
444 NetlinkPayload::Done => true,
445 e => {
446 warn!("Unknown: {:?}", e);
447 false
448 }
449 }
450 }
451
452 async fn run(sni: SharedNetInfo, chan: tokio::sync::mpsc::Sender<()>) {
453 let mut socket = Socket::new(protocols::NETLINK_ROUTE).unwrap();
454 let mut seq = 1;
455 socket.socket_mut().connect(&SocketAddr::new(0, 0)).unwrap();
456
457 NetLinkNetInfo::send_linkdump(&mut socket, &mut seq).await;
458 enum State {
459 ReadingLink,
460 ReadingAddr,
461 ReadingRoute4,
462 ReadingRoute6,
463 Done,
464 }
465 let mut state = State::ReadingLink;
466 while let Ok((pkt, _)) = socket.recv_from_full().await {
468 let rx_packet = <NetlinkMessage<RtnlMessage>>::deserialize(&pkt).unwrap();
469
470 if NetLinkNetInfo::process_message(&sni, &rx_packet).await {
471 match state {
472 State::ReadingLink => {
473 trace!("Finished Link");
474 NetLinkNetInfo::send_addrdump(&mut socket, &mut seq).await;
475 state = State::ReadingAddr
476 }
477 State::ReadingAddr => {
478 trace!("Finished Addr");
479 NetLinkNetInfo::send_routedump(&mut socket, &mut seq, AF_INET as u8).await;
480 state = State::ReadingRoute4
481 }
482 State::ReadingRoute4 => {
483 trace!("Finished Route4");
484 NetLinkNetInfo::send_routedump(&mut socket, &mut seq, AF_INET6 as u8).await;
485 state = State::ReadingRoute6
486 }
487 State::ReadingRoute6 => {
488 trace!("Finished Route6");
491 let _ = chan.try_send(());
492 state = State::Done
493 }
494 State::Done => {}
495 }
496 }
497 }
498 }
499}
500
501impl SharedNetInfo {
502 pub async fn new() -> Self {
503 let (s, mut c) = tokio::sync::mpsc::channel::<()>(1);
504 let shared = SharedNetInfo(std::sync::Arc::new(
505 tokio::sync::RwLock::new(NetInfo::new()),
506 ));
507 tokio::spawn(NetLinkNetInfo::run(shared.clone(), s));
508 c.recv().await;
510 shared
511 }
512
513 #[cfg(test)]
514 pub fn new_for_test() -> Self {
515 let mut ni = NetInfo::new();
516 ni.add_interface(
517 0,
518 IfInfo {
519 name: "lo".into(),
520 addresses: vec![("127.0.0.1".parse().unwrap(), 8)],
521 lladdr: LinkLayer::None,
522 mtu: 65536,
523 flags: IfFlags(IFF_MULTICAST),
524 },
525 );
526 ni.add_interface(
527 1,
528 IfInfo {
529 name: "eth0".into(),
530 addresses: vec![("192.0.2.254".parse().unwrap(), 24)],
531 lladdr: LinkLayer::Ethernet([0x00, 0x00, 0x5E, 0x00, 0x53, 0xFF]),
532 mtu: 1500,
533 flags: IfFlags(IFF_MULTICAST),
534 },
535 );
536 SharedNetInfo(std::sync::Arc::new(tokio::sync::RwLock::new(ni)))
537 }
538
539 #[allow(dead_code)]
540 pub async fn get_interfaces(&self) -> Vec<String> {
541 self.0
542 .read()
543 .await
544 .intf
545 .values()
546 .map(|x| x.name.clone())
547 .collect()
548 }
549
550 pub async fn get_ifindexes(&self) -> Vec<u32> {
551 self.0.read().await.intf.keys().copied().collect()
552 }
553
554 pub async fn get_linkaddr_by_ifidx(&self, ifidx: u32) -> Option<LinkLayer> {
555 self.0
556 .read()
557 .await
558 .intf
559 .get(&ifidx)
560 .map(|x| x.lladdr.clone())
561 }
562
563 pub async fn get_if_prefixes(&self) -> Vec<(std::net::IpAddr, u8)> {
564 self.0
565 .read()
566 .await
567 .intf
568 .iter()
569 .flat_map(|(_ifidx, x)| x.addresses.clone())
570 .collect()
571 }
572
573 pub async fn get_prefixes_by_ifidx(&self, ifidx: u32) -> Option<Vec<(std::net::IpAddr, u8)>> {
574 self.0
575 .read()
576 .await
577 .intf
578 .get(&ifidx)
579 .map(|x| x.addresses.clone())
580 }
581
582 pub async fn get_ipv4_by_ifidx(&self, ifidx: u32) -> Option<std::net::Ipv4Addr> {
583 self.get_prefixes_by_ifidx(ifidx)
584 .await
585 .and_then(|prefixes| {
586 prefixes
587 .iter()
588 .filter_map(|(prefix, _prefixlen)| {
589 if let std::net::IpAddr::V4(addr) = prefix {
590 Some(addr)
591 } else {
592 None
593 }
594 })
595 .copied()
596 .next()
597 })
598 }
599 pub async fn get_mtu_by_ifidx(&self, ifidx: u32) -> Option<u32> {
600 self.0.read().await.intf.get(&ifidx).map(|x| x.mtu)
601 }
602 pub async fn get_name_by_ifidx(&self, ifidx: u32) -> Option<String> {
603 self.0.read().await.intf.get(&ifidx).map(|x| x.name.clone())
604 }
605 pub async fn get_safe_name_by_ifidx(&self, ifidx: u32) -> String {
606 match self.get_name_by_ifidx(ifidx).await {
607 Some(ifname) => ifname,
608 None => format!("if#{}", ifidx),
609 }
610 }
611 pub async fn get_flags_by_ifidx(&self, ifidx: u32) -> Option<IfFlags> {
612 self.0.read().await.intf.get(&ifidx).map(|x| x.flags)
613 }
614
615 pub async fn get_ipv4_default_route(
616 &self,
617 ) -> Option<(Option<std::net::Ipv4Addr>, Option<u32>)> {
618 self.0.read().await.routeinfo.iter().find_map(|ri| {
619 if ri.prefixlen == 0 && ri.addr.is_ipv4() {
620 Some((
621 if let Some(std::net::IpAddr::V4(nexthop)) = ri.nexthop {
622 Some(nexthop)
623 } else {
624 None
625 },
626 ri.oifidx,
627 ))
628 } else {
629 None
630 }
631 })
632 }
633
634 pub async fn get_ipv6_default_route(
635 &self,
636 ) -> Option<(Option<std::net::Ipv6Addr>, Option<u32>)> {
637 self.0.read().await.routeinfo.iter().find_map(|ri| {
638 if ri.prefixlen == 0 && ri.addr.is_ipv6() {
639 Some((
640 if let Some(std::net::IpAddr::V6(nexthop)) = ri.nexthop {
641 Some(nexthop)
642 } else {
643 None
644 },
645 ri.oifidx,
646 ))
647 } else {
648 None
649 }
650 })
651 }
652}
653
654#[tokio::test]
655async fn test_interface() {
656 use netlink_packet_route::rtnl;
657 const IFIDX: u32 = 10;
658 let ni = SharedNetInfo::new_for_test();
659 let mut hdr = NetlinkHeader::default();
660 hdr.sequence_number = 1;
661 let mut lmsg = LinkMessage::default();
662 lmsg.header.index = IFIDX;
663 lmsg.header.link_layer_type = ARPHRD_ETHER;
664 lmsg.nlas = vec![
665 rtnl::link::nlas::Nla::IfName("test1".into()),
666 rtnl::link::nlas::Nla::Mtu(1500),
667 rtnl::link::nlas::Nla::Address(vec![0x00, 0x53, 0x00, 0x00, 0x00, 0x00]),
668 rtnl::link::nlas::Nla::Broadcast(vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]),
669 ];
670 NetLinkNetInfo::process_message(
671 &ni,
672 &NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::NewLink(lmsg))),
673 )
674 .await;
675 hdr.sequence_number = 2;
676 let mut amsg = AddressMessage::default();
677 amsg.header.index = IFIDX;
678 amsg.header.family = AF_INET as u8;
679 amsg.header.prefix_len = 24;
680 amsg.nlas = vec![rtnl::address::nlas::Nla::Address(vec![192, 0, 2, 1])];
681 NetLinkNetInfo::process_message(
682 &ni,
683 &NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::NewAddress(amsg))),
684 )
685 .await;
686 let mut a6msg = AddressMessage::default();
687 a6msg.header.index = IFIDX;
688 a6msg.header.family = AF_INET as u8;
689 a6msg.header.prefix_len = 24;
690 a6msg.nlas = vec![rtnl::address::nlas::Nla::Address(vec![
691 0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
692 ])];
693 NetLinkNetInfo::process_message(
694 &ni,
695 &NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::NewAddress(a6msg))),
696 )
697 .await;
698 assert!(ni.get_interfaces().await.contains(&"test1".into()));
699 assert_eq!(
700 ni.get_ipv4_by_ifidx(IFIDX).await,
701 Some(std::net::Ipv4Addr::new(192, 0, 2, 1))
702 );
703 assert_eq!(ni.get_mtu_by_ifidx(IFIDX).await, Some(1500));
704 assert_eq!(ni.get_name_by_ifidx(IFIDX).await, Some("test1".to_string()));
705 assert_eq!(
706 ni.get_linkaddr_by_ifidx(IFIDX).await,
707 Some(LinkLayer::Ethernet([0x00, 0x53, 0x00, 0x00, 0x00, 0x00]))
708 );
709 hdr.sequence_number = 1;
711 let mut lmsg = LinkMessage::default();
712 lmsg.header.index = IFIDX;
713 lmsg.header.link_layer_type = ARPHRD_ETHER;
714 lmsg.nlas = vec![
715 rtnl::link::nlas::Nla::IfName("test1".into()),
716 rtnl::link::nlas::Nla::Mtu(1501),
717 rtnl::link::nlas::Nla::Address(vec![0x00, 0x53, 0x00, 0x00, 0x00, 0x01]),
718 rtnl::link::nlas::Nla::Broadcast(vec![0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE]),
719 ];
720 NetLinkNetInfo::process_message(
721 &ni,
722 &NetlinkMessage::new(hdr, NetlinkPayload::from(RtnlMessage::NewLink(lmsg))),
723 )
724 .await;
725 assert_eq!(
727 {
728 let mut v = ni.get_interfaces().await;
729 v.sort();
730 v
731 },
732 vec!["eth0".to_string(), "lo".to_string(), "test1".to_string()]
733 );
734 assert_eq!(
735 ni.get_ipv4_by_ifidx(IFIDX).await,
736 Some(std::net::Ipv4Addr::new(192, 0, 2, 1))
737 );
738 assert_eq!(ni.get_mtu_by_ifidx(IFIDX).await, Some(1501));
739 assert_eq!(ni.get_name_by_ifidx(IFIDX).await, Some("test1".to_string()),);
740 assert_eq!(
741 ni.get_linkaddr_by_ifidx(IFIDX).await,
742 Some(LinkLayer::Ethernet([0x00, 0x53, 0x00, 0x00, 0x00, 0x01]))
743 );
744}
745
746#[tokio::test]
747async fn test_netinfo_startup() {
748 println!("about to start");
750 let _ = SharedNetInfo::new().await;
751 println!("new complete");
752}