1use 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
17pub 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 message.nlas.push(Nla::Local(address_vec.clone()));
60
61 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 pub fn replace(self) -> Self {
87 Self {
88 replace: true,
89 ..self
90 }
91 }
92
93 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 pub fn message_mut(&mut self) -> &mut AddressMessage {
113 &mut self.message
114 }
115}