erbium_net/
netinfo.rs

1/*   Copyright 2023 Perry Lorier
2 *
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 *  Unless required by applicable law or agreed to in writing, software
10 *  distributed under the License is distributed on an "AS IS" BASIS,
11 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 *  See the License for the specific language governing permissions and
13 *  limitations under the License.
14 *
15 *  SPDX-License-Identifier: Apache-2.0
16 *
17 *  API for finding out information about interfaces.
18 *  Currently uses netlink, but ideally should eventually be generalised for other platforms.
19 */
20use 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    //operstate: netlink_packet_route::rtnl::link::nlas::link_state::State, // Is private
72    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, // Actually this is a IpAddr, but we don't do DHCP over it, so...
146            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(); // TODO: Error?
171        if !ii.addresses.contains(&ifaddr) {
172            /* It's common to renew IPv6 addresses, don't treat them as new if
173             * the address already exists.
174             */
175            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(); // TODO: Error?
193        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        /* This might be an update to an existing interface.
226         * (eg the interface might be changing it's oper state from down/up etc.
227         * So preserve some information.
228         */
229        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, /* Skip routes that are not in the "main" table */
284                _ => (),                 /* Ignore unknown nlas */
285            }
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            /* We basically assume there will only ever be one route for each prefix.
310             * We'd have to be a lot more careful if we were to support multiple routes to a
311             * particular prefix
312             */
313            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        // Before calling serialize, it is important to check that the buffer in which we're emitting is big
332        // enough for the packet, other `serialize()` panics.
333
334        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        // Before calling serialize, it is important to check that the buffer in which we're emitting is big
361        // enough for the packet, other `serialize()` panics.
362
363        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        // Before calling serialize, it is important to check that the buffer in which we're emitting is big
402        // enough for the packet, other `serialize()` panics.
403
404        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        // we set the NLM_F_DUMP flag so we expect a multipart rx_packet in response.
467        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                        // Try and inform anyone listening that we have completed.
489                        // But if it fails, don't worry, we'll send another one soonish.
490                        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        // We want to block and wait until all the data is loaded, otherwise we'll cause confusion.
509        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    /* It's common to get a second NewLink, make sure we preserve the addresses */
710    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    /* Did this disturb the data that was already there? */
726    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    // Initialise netinfo and make sure it doesn't block indefinately on startup.
749    println!("about to start");
750    let _ = SharedNetInfo::new().await;
751    println!("new complete");
752}