rtnetlink/addr/
add.rs

1// SPDX-License-Identifier: MIT
2
3use futures::stream::StreamExt;
4use std::net::{IpAddr, Ipv4Addr};
5
6use netlink_packet_core::{
7    NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
8    NLM_F_REQUEST,
9};
10
11use netlink_packet_route::{
12    nlas::address::Nla, AddressMessage, RtnlMessage, AF_INET, AF_INET6,
13};
14
15use crate::{try_nl, Error, Handle};
16
17/// A request to create a new address. This is equivalent to the `ip address
18/// add` commands.
19pub struct AddressAddRequest {
20    handle: Handle,
21    message: AddressMessage,
22    replace: bool,
23}
24
25impl AddressAddRequest {
26    pub(crate) fn new(
27        handle: Handle,
28        index: u32,
29        address: IpAddr,
30        prefix_len: u8,
31    ) -> Self {
32        let mut message = AddressMessage::default();
33
34        message.header.prefix_len = prefix_len;
35        message.header.index = index;
36
37        let address_vec = match address {
38            IpAddr::V4(ipv4) => {
39                message.header.family = AF_INET as u8;
40                ipv4.octets().to_vec()
41            }
42            IpAddr::V6(ipv6) => {
43                message.header.family = AF_INET6 as u8;
44                ipv6.octets().to_vec()
45            }
46        };
47
48        if address.is_multicast() {
49            message.nlas.push(Nla::Multicast(address_vec));
50        } else if address.is_unspecified() {
51            message.nlas.push(Nla::Unspec(address_vec));
52        } else if address.is_ipv6() {
53            message.nlas.push(Nla::Address(address_vec));
54        } else {
55            message.nlas.push(Nla::Address(address_vec.clone()));
56
57            // for IPv4 the IFA_LOCAL address can be set to the same value as
58            // IFA_ADDRESS
59            message.nlas.push(Nla::Local(address_vec.clone()));
60
61            // set the IFA_BROADCAST address as well (IPv6 does not support
62            // broadcast)
63            if prefix_len == 32 {
64                message.nlas.push(Nla::Broadcast(address_vec));
65            } else {
66                let ip_addr: u32 = u32::from(Ipv4Addr::new(
67                    address_vec[0],
68                    address_vec[1],
69                    address_vec[2],
70                    address_vec[3],
71                ));
72                let brd = Ipv4Addr::from(
73                    (0xffff_ffff_u32) >> u32::from(prefix_len) | ip_addr,
74                );
75                message.nlas.push(Nla::Broadcast(brd.octets().to_vec()));
76            };
77        }
78        AddressAddRequest {
79            handle,
80            message,
81            replace: false,
82        }
83    }
84
85    /// Replace existing matching address.
86    pub fn replace(self) -> Self {
87        Self {
88            replace: true,
89            ..self
90        }
91    }
92
93    /// Execute the request.
94    pub async fn execute(self) -> Result<(), Error> {
95        let AddressAddRequest {
96            mut handle,
97            message,
98            replace,
99        } = self;
100        let mut req = NetlinkMessage::from(RtnlMessage::NewAddress(message));
101        let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
102        req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
103
104        let mut response = handle.request(req)?;
105        while let Some(message) = response.next().await {
106            try_nl!(message);
107        }
108        Ok(())
109    }
110
111    /// Return a mutable reference to the request message.
112    pub fn message_mut(&mut self) -> &mut AddressMessage {
113        &mut self.message
114    }
115}