|
1 | 1 | // SPDX-License-Identifier: MIT
|
2 |
| - |
3 | 2 | use futures::{
|
4 | 3 | future::{self, Either},
|
5 | 4 | stream::{StreamExt, TryStream},
|
6 | 5 | FutureExt,
|
7 | 6 | };
|
8 | 7 | use netlink_packet_core::{NetlinkMessage, NLM_F_DUMP, NLM_F_REQUEST};
|
| 8 | +use netlink_packet_route::tc::{ |
| 9 | + TcAction, TcActionAttribute, TcActionMessage, TcActionMessageAttribute, |
| 10 | + TcActionMessageFlags, TcActionMessageFlagsWithSelector, |
| 11 | +}; |
9 | 12 | use netlink_packet_route::{
|
10 | 13 | tc::{TcHandle, TcMessage},
|
11 |
| - RouteNetlinkMessage, |
| 14 | + AddressFamily, RouteNetlinkMessage, |
12 | 15 | };
|
13 | 16 |
|
14 | 17 | use crate::{try_rtnl, Error, Handle};
|
@@ -168,3 +171,101 @@ impl TrafficChainGetRequest {
|
168 | 171 | }
|
169 | 172 | }
|
170 | 173 | }
|
| 174 | + |
| 175 | +/// Request to retrieve traffic actions from the kernel. |
| 176 | +/// Equivalent to |
| 177 | +/// |
| 178 | +/// ```bash |
| 179 | +/// tc actions list action $action_type |
| 180 | +/// ``` |
| 181 | +#[derive(Debug, Clone)] |
| 182 | +#[must_use] |
| 183 | +pub struct TrafficActionGetRequest { |
| 184 | + handle: Handle, |
| 185 | + message: TcActionMessage, |
| 186 | +} |
| 187 | + |
| 188 | +/// The kind of traffic action. |
| 189 | +/// |
| 190 | +/// This is a list of known traffic actions. |
| 191 | +/// If the kernel returns an unknown action, it will be represented as |
| 192 | +/// `Other(String)`. |
| 193 | +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] |
| 194 | +pub enum TrafficActionKind { |
| 195 | + /// Used for mirroring and redirecting packets. |
| 196 | + Mirror, |
| 197 | + /// Used for network address translation. |
| 198 | + Nat, |
| 199 | + /// Other action type not yet directly supported by this library. |
| 200 | + Other(String), |
| 201 | +} |
| 202 | + |
| 203 | +impl<T: AsRef<str>> From<T> for TrafficActionKind { |
| 204 | + fn from(kind: T) -> Self { |
| 205 | + match kind.as_ref() { |
| 206 | + "mirred" => TrafficActionKind::Mirror, |
| 207 | + "nat" => TrafficActionKind::Nat, |
| 208 | + _ => TrafficActionKind::Other(kind.as_ref().into()), |
| 209 | + } |
| 210 | + } |
| 211 | +} |
| 212 | + |
| 213 | +impl From<TrafficActionKind> for String { |
| 214 | + fn from(kind: TrafficActionKind) -> Self { |
| 215 | + match kind { |
| 216 | + TrafficActionKind::Mirror => "mirred".into(), |
| 217 | + TrafficActionKind::Nat => "nat".into(), |
| 218 | + TrafficActionKind::Other(kind) => kind, |
| 219 | + } |
| 220 | + } |
| 221 | +} |
| 222 | + |
| 223 | +impl TrafficActionGetRequest { |
| 224 | + pub(crate) fn new(handle: Handle) -> Self { |
| 225 | + let mut message = TcActionMessage::default(); |
| 226 | + message.header.family = AddressFamily::Unspec; |
| 227 | + let flags = TcActionMessageAttribute::Flags( |
| 228 | + TcActionMessageFlagsWithSelector::new( |
| 229 | + TcActionMessageFlags::LargeDump, |
| 230 | + ), |
| 231 | + ); |
| 232 | + message.attributes.push(flags); |
| 233 | + Self { handle, message } |
| 234 | + } |
| 235 | + |
| 236 | + /// Specify the kind of the action to retrieve. |
| 237 | + pub fn kind<T: Into<TrafficActionKind>>(mut self, kind: T) -> Self { |
| 238 | + let mut tc_action = TcAction::default(); |
| 239 | + tc_action |
| 240 | + .attributes |
| 241 | + .push(TcActionAttribute::Kind(String::from(kind.into()))); |
| 242 | + let acts = TcActionMessageAttribute::Actions(vec![tc_action]); |
| 243 | + self.message.attributes.push(acts); |
| 244 | + self |
| 245 | + } |
| 246 | + |
| 247 | + /// Execute the request |
| 248 | + #[must_use] |
| 249 | + pub fn execute( |
| 250 | + self, |
| 251 | + ) -> impl TryStream<Ok = TcActionMessage, Error = Error> { |
| 252 | + let Self { |
| 253 | + mut handle, |
| 254 | + message, |
| 255 | + } = self; |
| 256 | + |
| 257 | + let mut req = NetlinkMessage::from( |
| 258 | + RouteNetlinkMessage::GetTrafficAction(message), |
| 259 | + ); |
| 260 | + req.header.flags = NLM_F_REQUEST | NLM_F_DUMP; |
| 261 | + |
| 262 | + match handle.request(req) { |
| 263 | + Ok(response) => Either::Left(response.map(move |msg| { |
| 264 | + Ok(try_rtnl!(msg, RouteNetlinkMessage::GetTrafficAction)) |
| 265 | + })), |
| 266 | + Err(e) => Either::Right( |
| 267 | + future::err::<TcActionMessage, Error>(e).into_stream(), |
| 268 | + ), |
| 269 | + } |
| 270 | + } |
| 271 | +} |
0 commit comments