1use futures::stream::StreamExt;
4use std::{
5 marker::PhantomData,
6 net::{Ipv4Addr, Ipv6Addr},
7};
8
9use netlink_packet_core::{
10 NetlinkMessage, NLM_F_ACK, NLM_F_CREATE, NLM_F_EXCL, NLM_F_REPLACE,
11 NLM_F_REQUEST,
12};
13use netlink_packet_route::{
14 nlas::route::Nla, RouteMessage, RtnlMessage, AF_INET, AF_INET6,
15 RTN_UNICAST, RTPROT_STATIC, RT_SCOPE_UNIVERSE, RT_TABLE_MAIN,
16};
17
18use crate::{try_nl, Error, Handle};
19
20pub struct RouteAddRequest<T = ()> {
23 handle: Handle,
24 message: RouteMessage,
25 replace: bool,
26 _phantom: PhantomData<T>,
27}
28
29impl<T> RouteAddRequest<T> {
30 pub(crate) fn new(handle: Handle) -> Self {
31 let mut message = RouteMessage::default();
32
33 message.header.table = RT_TABLE_MAIN;
34 message.header.protocol = RTPROT_STATIC;
35 message.header.scope = RT_SCOPE_UNIVERSE;
36 message.header.kind = RTN_UNICAST;
37
38 RouteAddRequest {
39 handle,
40 message,
41 replace: false,
42 _phantom: Default::default(),
43 }
44 }
45
46 pub fn input_interface(mut self, index: u32) -> Self {
48 self.message.nlas.push(Nla::Iif(index));
49 self
50 }
51
52 pub fn output_interface(mut self, index: u32) -> Self {
54 self.message.nlas.push(Nla::Oif(index));
55 self
56 }
57
58 #[deprecated(note = "Please use `table_id` instead")]
62 pub fn table(mut self, table: u8) -> Self {
63 self.message.header.table = table;
64 self
65 }
66
67 pub fn table_id(mut self, table: u32) -> Self {
71 if table > 255 {
72 self.message.nlas.push(Nla::Table(table));
73 } else {
74 self.message.header.table = table as u8;
75 }
76 self
77 }
78
79 pub fn protocol(mut self, protocol: u8) -> Self {
83 self.message.header.protocol = protocol;
84 self
85 }
86
87 pub fn scope(mut self, scope: u8) -> Self {
91 self.message.header.scope = scope;
92 self
93 }
94
95 pub fn kind(mut self, kind: u8) -> Self {
99 self.message.header.kind = kind;
100 self
101 }
102
103 pub fn v4(mut self) -> RouteAddRequest<Ipv4Addr> {
105 self.message.header.address_family = AF_INET as u8;
106 RouteAddRequest {
107 handle: self.handle,
108 message: self.message,
109 replace: false,
110 _phantom: Default::default(),
111 }
112 }
113
114 pub fn v6(mut self) -> RouteAddRequest<Ipv6Addr> {
116 self.message.header.address_family = AF_INET6 as u8;
117 RouteAddRequest {
118 handle: self.handle,
119 message: self.message,
120 replace: false,
121 _phantom: Default::default(),
122 }
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 RouteAddRequest {
136 mut handle,
137 message,
138 replace,
139 ..
140 } = self;
141 let mut req = NetlinkMessage::from(RtnlMessage::NewRoute(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 try_nl!(message);
148 }
149 Ok(())
150 }
151
152 pub fn message_mut(&mut self) -> &mut RouteMessage {
154 &mut self.message
155 }
156}
157
158impl RouteAddRequest<Ipv4Addr> {
159 pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
161 self.message.header.source_prefix_length = prefix_length;
162 let src = addr.octets().to_vec();
163 self.message.nlas.push(Nla::Source(src));
164 self
165 }
166
167 pub fn pref_source(mut self, addr: Ipv4Addr) -> Self {
169 let src = addr.octets().to_vec();
170 self.message.nlas.push(Nla::PrefSource(src));
171 self
172 }
173
174 pub fn destination_prefix(
176 mut self,
177 addr: Ipv4Addr,
178 prefix_length: u8,
179 ) -> Self {
180 self.message.header.destination_prefix_length = prefix_length;
181 let dst = addr.octets().to_vec();
182 self.message.nlas.push(Nla::Destination(dst));
183 self
184 }
185
186 pub fn gateway(mut self, addr: Ipv4Addr) -> Self {
188 let gtw = addr.octets().to_vec();
189 self.message.nlas.push(Nla::Gateway(gtw));
190 self
191 }
192}
193
194impl RouteAddRequest<Ipv6Addr> {
195 pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
197 self.message.header.source_prefix_length = prefix_length;
198 let src = addr.octets().to_vec();
199 self.message.nlas.push(Nla::Source(src));
200 self
201 }
202
203 pub fn pref_source(mut self, addr: Ipv6Addr) -> Self {
205 let src = addr.octets().to_vec();
206 self.message.nlas.push(Nla::PrefSource(src));
207 self
208 }
209
210 pub fn destination_prefix(
212 mut self,
213 addr: Ipv6Addr,
214 prefix_length: u8,
215 ) -> Self {
216 self.message.header.destination_prefix_length = prefix_length;
217 let dst = addr.octets().to_vec();
218 self.message.nlas.push(Nla::Destination(dst));
219 self
220 }
221
222 pub fn gateway(mut self, addr: Ipv6Addr) -> Self {
224 let gtw = addr.octets().to_vec();
225 self.message.nlas.push(Nla::Gateway(gtw));
226 self
227 }
228}