1use futures::stream::StreamExt;
4use std::{
5 marker::PhantomData,
6 net::{Ipv4Addr, Ipv6Addr},
7};
8
9use netlink_packet_route::{
10 constants::*,
11 nlas::route::Nla,
12 NetlinkMessage,
13 RouteMessage,
14 RtnlMessage,
15};
16
17use crate::{try_nl, Error, Handle};
18
19pub struct RouteAddRequest<T = ()> {
21 handle: Handle,
22 message: RouteMessage,
23 replace: bool,
24 _phantom: PhantomData<T>,
25}
26
27impl<T> RouteAddRequest<T> {
28 pub(crate) fn new(handle: Handle) -> Self {
29 let mut message = RouteMessage::default();
30
31 message.header.table = RT_TABLE_MAIN;
32 message.header.protocol = RTPROT_STATIC;
33 message.header.scope = RT_SCOPE_UNIVERSE;
34 message.header.kind = RTN_UNICAST;
35
36 RouteAddRequest {
37 handle,
38 message,
39 replace: false,
40 _phantom: Default::default(),
41 }
42 }
43
44 pub fn input_interface(mut self, index: u32) -> Self {
46 self.message.nlas.push(Nla::Iif(index));
47 self
48 }
49
50 pub fn output_interface(mut self, index: u32) -> Self {
52 self.message.nlas.push(Nla::Oif(index));
53 self
54 }
55
56 pub fn table(mut self, table: u8) -> Self {
60 self.message.header.table = table;
61 self
62 }
63
64 pub fn protocol(mut self, protocol: u8) -> Self {
68 self.message.header.protocol = protocol;
69 self
70 }
71
72 pub fn scope(mut self, scope: u8) -> Self {
76 self.message.header.scope = scope;
77 self
78 }
79
80 pub fn kind(mut self, kind: u8) -> Self {
84 self.message.header.kind = kind;
85 self
86 }
87
88 pub fn v4(mut self) -> RouteAddRequest<Ipv4Addr> {
90 self.message.header.address_family = AF_INET as u8;
91 RouteAddRequest {
92 handle: self.handle,
93 message: self.message,
94 replace: false,
95 _phantom: Default::default(),
96 }
97 }
98
99 pub fn v6(mut self) -> RouteAddRequest<Ipv6Addr> {
101 self.message.header.address_family = AF_INET6 as u8;
102 RouteAddRequest {
103 handle: self.handle,
104 message: self.message,
105 replace: false,
106 _phantom: Default::default(),
107 }
108 }
109
110 pub fn replace(self) -> Self {
112 Self {
113 replace: true,
114 ..self
115 }
116 }
117
118 pub async fn execute(self) -> Result<(), Error> {
120 let RouteAddRequest {
121 mut handle,
122 message,
123 replace,
124 ..
125 } = self;
126 let mut req = NetlinkMessage::from(RtnlMessage::NewRoute(message));
127 let replace = if replace { NLM_F_REPLACE } else { NLM_F_EXCL };
128 req.header.flags = NLM_F_REQUEST | NLM_F_ACK | replace | NLM_F_CREATE;
129
130 let mut response = handle.request(req)?;
131 while let Some(message) = response.next().await {
132 try_nl!(message);
133 }
134 Ok(())
135 }
136
137 pub fn message_mut(&mut self) -> &mut RouteMessage {
139 &mut self.message
140 }
141}
142
143impl RouteAddRequest<Ipv4Addr> {
144 pub fn source_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
146 self.message.header.source_prefix_length = prefix_length;
147 let src = addr.octets().to_vec();
148 self.message.nlas.push(Nla::Source(src));
149 self
150 }
151
152 pub fn pref_source(mut self, addr: Ipv4Addr) -> Self {
154 let src = addr.octets().to_vec();
155 self.message.nlas.push(Nla::PrefSource(src));
156 self
157 }
158
159 pub fn destination_prefix(mut self, addr: Ipv4Addr, prefix_length: u8) -> Self {
161 self.message.header.destination_prefix_length = prefix_length;
162 let dst = addr.octets().to_vec();
163 self.message.nlas.push(Nla::Destination(dst));
164 self
165 }
166
167 pub fn gateway(mut self, addr: Ipv4Addr) -> Self {
169 let gtw = addr.octets().to_vec();
170 self.message.nlas.push(Nla::Gateway(gtw));
171 self
172 }
173}
174
175impl RouteAddRequest<Ipv6Addr> {
176 pub fn source_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
178 self.message.header.source_prefix_length = prefix_length;
179 let src = addr.octets().to_vec();
180 self.message.nlas.push(Nla::Source(src));
181 self
182 }
183
184 pub fn pref_source(mut self, addr: Ipv6Addr) -> Self {
186 let src = addr.octets().to_vec();
187 self.message.nlas.push(Nla::PrefSource(src));
188 self
189 }
190
191 pub fn destination_prefix(mut self, addr: Ipv6Addr, prefix_length: u8) -> Self {
193 self.message.header.destination_prefix_length = prefix_length;
194 let dst = addr.octets().to_vec();
195 self.message.nlas.push(Nla::Destination(dst));
196 self
197 }
198
199 pub fn gateway(mut self, addr: Ipv6Addr) -> Self {
201 let gtw = addr.octets().to_vec();
202 self.message.nlas.push(Nla::Gateway(gtw));
203 self
204 }
205}