rtnetlink/route/
add.rs

1// SPDX-License-Identifier: MIT
2
3use 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
19/// A request to create a new route. This is equivalent to the `ip route add` commands.
20pub 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    /// Sets the input interface index.
45    pub fn input_interface(mut self, index: u32) -> Self {
46        self.message.nlas.push(Nla::Iif(index));
47        self
48    }
49
50    /// Sets the output interface index.
51    pub fn output_interface(mut self, index: u32) -> Self {
52        self.message.nlas.push(Nla::Oif(index));
53        self
54    }
55
56    /// Sets the route table.
57    ///
58    /// Default is main route table.
59    pub fn table(mut self, table: u8) -> Self {
60        self.message.header.table = table;
61        self
62    }
63
64    /// Sets the route protocol.
65    ///
66    /// Default is static route protocol.
67    pub fn protocol(mut self, protocol: u8) -> Self {
68        self.message.header.protocol = protocol;
69        self
70    }
71
72    /// Sets the route scope.
73    ///
74    /// Default is universe route scope.
75    pub fn scope(mut self, scope: u8) -> Self {
76        self.message.header.scope = scope;
77        self
78    }
79
80    /// Sets the route kind.
81    ///
82    /// Default is unicast route kind.
83    pub fn kind(mut self, kind: u8) -> Self {
84        self.message.header.kind = kind;
85        self
86    }
87
88    /// Build an IP v4 route request
89    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    /// Build an IP v6 route request
100    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    /// Replace existing matching route.
111    pub fn replace(self) -> Self {
112        Self {
113            replace: true,
114            ..self
115        }
116    }
117
118    /// Execute the request.
119    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    /// Return a mutable reference to the request message.
138    pub fn message_mut(&mut self) -> &mut RouteMessage {
139        &mut self.message
140    }
141}
142
143impl RouteAddRequest<Ipv4Addr> {
144    /// Sets the source address prefix.
145    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    /// Sets the preferred source address.
153    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    /// Sets the destination address prefix.
160    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    /// Sets the gateway (via) address.
168    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    /// Sets the source address prefix.
177    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    /// Sets the preferred source address.
185    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    /// Sets the destination address prefix.
192    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    /// Sets the gateway (via) address.
200    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}