rtnetlink/neighbour/
add.rs1use futures::stream::StreamExt;
4
5use netlink_packet_core::{
6 NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL,
7 NLM_F_REPLACE, NLM_F_REQUEST,
8};
9use netlink_packet_route::{
10 constants::*,
11 neighbour::{NeighbourMessage, Nla},
12 RtnlMessage,
13};
14
15use crate::{Error, Handle};
16use std::net::IpAddr;
17
18pub struct NeighbourAddRequest {
19 handle: Handle,
20 message: NeighbourMessage,
21 replace: bool,
22}
23
24impl NeighbourAddRequest {
25 pub(crate) fn new(handle: Handle, index: u32, destination: IpAddr) -> Self {
26 let mut message = NeighbourMessage::default();
27
28 message.header.family = match destination {
29 IpAddr::V4(_) => AF_INET as u8,
30 IpAddr::V6(_) => AF_INET6 as u8,
31 };
32
33 message.header.ifindex = index;
34 message.header.state = IFA_F_PERMANENT as u16;
35 message.header.ntype = NDA_UNSPEC as u8;
36
37 message.nlas.push(Nla::Destination(match destination {
38 IpAddr::V4(v4) => v4.octets().to_vec(),
39 IpAddr::V6(v6) => v6.octets().to_vec(),
40 }));
41
42 NeighbourAddRequest {
43 handle,
44 message,
45 replace: false,
46 }
47 }
48
49 pub(crate) fn new_bridge(handle: Handle, index: u32, lla: &[u8]) -> Self {
50 let mut message = NeighbourMessage::default();
51
52 message.header.family = AF_BRIDGE as u8;
53 message.header.ifindex = index;
54 message.header.state = NUD_PERMANENT;
55 message.header.ntype = NDA_UNSPEC as u8;
56
57 message.nlas.push(Nla::LinkLocalAddress(lla.to_vec()));
58
59 NeighbourAddRequest {
60 handle,
61 message,
62 replace: false,
63 }
64 }
65
66 pub fn state(mut self, state: u16) -> Self {
69 self.message.header.state = state;
70 self
71 }
72
73 pub fn flags(mut self, flags: u8) -> Self {
76 self.message.header.flags = flags;
77 self
78 }
79
80 pub fn ntype(mut self, ntype: u8) -> Self {
83 self.message.header.ntype = ntype;
84 self
85 }
86
87 pub fn link_local_address(mut self, addr: &[u8]) -> Self {
89 let lla = self.message.nlas.iter_mut().find_map(|nla| match nla {
90 Nla::LinkLocalAddress(lla) => Some(lla),
91 _ => None,
92 });
93
94 if let Some(lla) = lla {
95 *lla = addr.to_vec();
96 } else {
97 self.message.nlas.push(Nla::LinkLocalAddress(addr.to_vec()));
98 }
99
100 self
101 }
102
103 pub fn destination(mut self, addr: IpAddr) -> Self {
106 let dst = self.message.nlas.iter_mut().find_map(|nla| match nla {
107 Nla::Destination(dst) => Some(dst),
108 _ => None,
109 });
110
111 let addr = match addr {
112 IpAddr::V4(v4) => v4.octets().to_vec(),
113 IpAddr::V6(v6) => v6.octets().to_vec(),
114 };
115
116 if let Some(dst) = dst {
117 *dst = addr;
118 } else {
119 self.message.nlas.push(Nla::Destination(addr));
120 }
121
122 self
123 }
124
125 pub fn replace(self) -> Self {
127 Self {
128 replace: true,
129 ..self
130 }
131 }
132
133 pub async fn execute(self) -> Result<(), Error> {
135 let NeighbourAddRequest {
136 mut handle,
137 message,
138 replace,
139 } = self;
140
141 let mut req = NetlinkMessage::from(RtnlMessage::NewNeighbour(message));
142 let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
143 req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
144
145 let mut response = handle.request(req)?;
146 while let Some(message) = response.next().await {
147 if let NetlinkPayload::Error(err) = message.payload {
148 return Err(Error::NetlinkError(err));
149 }
150 }
151
152 Ok(())
153 }
154
155 pub fn message_mut(&mut self) -> &mut NeighbourMessage {
157 &mut self.message
158 }
159}