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