rtnetlink/addr/
add.rs

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