Skip to content

Commit 6650f7f

Browse files
author
Erich Heine
committed
Re #19 - Add the nat action to tc
1 parent 75ce74c commit 6650f7f

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

src/rtnl/tc/constants.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,12 @@ pub const TCA_EGRESS_REDIR: i32 = 1; /* packet redirect to EGRESS */
9393
pub const TCA_EGRESS_MIRROR: i32 = 2; /* mirror packet to EGRESS */
9494
pub const TCA_INGRESS_REDIR: i32 = 3; /* packet redirect to INGRESS */
9595
pub const TCA_INGRESS_MIRROR: i32 = 4; /* mirror packet to INGRESS */
96+
97+
/// NAT action attr
98+
pub const TCA_NAT_UNSPEC: u16 = 0;
99+
pub const TCA_NAT_PARMS: u16 = 1;
100+
pub const TCA_NAT_TM: u16 = 2;
101+
pub const TCA_NAT_PAD: u16 = 3;
102+
pub const TCA_NAT_MAX: u16 = TCA_NAT_PAD;
103+
104+
pub const TCA_NAT_FLAG_EGRESS: u32 = 1;

src/rtnl/tc/nlas/action/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// SPDX-License-Identifier: MIT
22

33
pub mod mirred;
4+
pub mod nat;
45

56
use anyhow::Context;
67
use byteorder::{ByteOrder, NativeEndian};
@@ -160,6 +161,7 @@ impl nla::Nla for ActNla {
160161
#[non_exhaustive]
161162
pub enum ActOpt {
162163
Mirred(mirred::Nla),
164+
Nat(nat::Nla),
163165
// Other options
164166
Other(DefaultNla),
165167
}
@@ -169,6 +171,7 @@ impl nla::Nla for ActOpt {
169171
use self::ActOpt::*;
170172
match self {
171173
Mirred(nla) => nla.value_len(),
174+
Nat(nla) => nla.value_len(),
172175
Other(nla) => nla.value_len(),
173176
}
174177
}
@@ -177,6 +180,7 @@ impl nla::Nla for ActOpt {
177180
use self::ActOpt::*;
178181
match self {
179182
Mirred(nla) => nla.emit_value(buffer),
183+
Nat(nla) => nla.emit_value(buffer),
180184
Other(nla) => nla.emit_value(buffer),
181185
}
182186
}
@@ -185,6 +189,7 @@ impl nla::Nla for ActOpt {
185189
use self::ActOpt::*;
186190
match self {
187191
Mirred(nla) => nla.kind(),
192+
Nat(nla) => nla.kind(),
188193
Other(nla) => nla.kind(),
189194
}
190195
}
@@ -204,6 +209,9 @@ where
204209
mirred::Nla::parse(buf)
205210
.context("failed to parse mirred action")?,
206211
),
212+
nat::KIND => Self::Nat(
213+
nat::Nla::parse(buf).context("failed to parse nat action")?,
214+
),
207215
_ => Self::Other(
208216
DefaultNla::parse(buf)
209217
.context("failed to parse action options")?,

src/rtnl/tc/nlas/action/nat.rs

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/// Nat action
4+
///
5+
/// The nat action maps one IP prefix to another
6+
use std::net::Ipv4Addr;
7+
8+
use netlink_packet_utils::{
9+
nla::{self, DefaultNla, NlaBuffer},
10+
traits::{Emitable, Parseable},
11+
DecodeError,
12+
};
13+
14+
use crate::tc::{constants::*, TC_GEN_BUF_LEN};
15+
16+
pub const KIND: &str = "nat";
17+
pub const TC_NAT_BUF_LEN: usize = TC_GEN_BUF_LEN + 16;
18+
19+
#[derive(Debug, PartialEq, Eq, Clone)]
20+
#[non_exhaustive]
21+
pub enum Nla {
22+
Unspec(Vec<u8>),
23+
Tm(Vec<u8>),
24+
Parms(TcNat),
25+
Other(DefaultNla),
26+
}
27+
28+
impl nla::Nla for Nla {
29+
fn value_len(&self) -> usize {
30+
use self::Nla::*;
31+
match self {
32+
Unspec(bytes) | Tm(bytes) => bytes.len(),
33+
Parms(_) => TC_NAT_BUF_LEN,
34+
Other(attr) => attr.value_len(),
35+
}
36+
}
37+
38+
fn emit_value(&self, buffer: &mut [u8]) {
39+
use self::Nla::*;
40+
match self {
41+
Unspec(bytes) | Tm(bytes) => {
42+
buffer.copy_from_slice(bytes.as_slice())
43+
}
44+
Parms(p) => p.emit(buffer),
45+
Other(attr) => attr.emit_value(buffer),
46+
}
47+
}
48+
fn kind(&self) -> u16 {
49+
use self::Nla::*;
50+
match self {
51+
Unspec(_) => TCA_NAT_UNSPEC,
52+
Tm(_) => TCA_NAT_TM,
53+
Parms(_) => TCA_NAT_PARMS,
54+
Other(nla) => nla.kind(),
55+
}
56+
}
57+
}
58+
59+
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
60+
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
61+
use self::Nla::*;
62+
let payload = buf.value();
63+
Ok(match buf.kind() {
64+
TCA_NAT_UNSPEC => Unspec(payload.to_vec()),
65+
TCA_NAT_TM => Tm(payload.to_vec()),
66+
TCA_NAT_PARMS => {
67+
Parms(TcNat::parse(&TcNatBuffer::new_checked(payload)?)?)
68+
}
69+
_ => Other(DefaultNla::parse(buf)?),
70+
})
71+
}
72+
}
73+
74+
#[derive(Debug, PartialEq, Eq, Clone, Default)]
75+
#[non_exhaustive]
76+
pub struct TcNat {
77+
pub index: u32,
78+
pub capab: u32,
79+
pub action: i32,
80+
pub refcnt: i32,
81+
pub bindcnt: i32,
82+
83+
pub old_addr: Vec<u8>,
84+
pub new_addr: Vec<u8>,
85+
pub mask: Vec<u8>,
86+
pub flags: u32,
87+
}
88+
89+
buffer!(TcNatBuffer(TC_NAT_BUF_LEN) {
90+
index: (u32, 0..4),
91+
capab: (u32, 4..8),
92+
action: (i32, 8..12),
93+
refcnt: (i32, 12..16),
94+
bindcnt: (i32, 16..20),
95+
96+
old_addr: (slice, TC_GEN_BUF_LEN..(TC_GEN_BUF_LEN+4)),
97+
new_addr: (slice, (TC_GEN_BUF_LEN +4)..(TC_GEN_BUF_LEN+8)),
98+
mask: (slice, (TC_GEN_BUF_LEN +8)..(TC_GEN_BUF_LEN+12)),
99+
flags: (u32, (TC_GEN_BUF_LEN+12)..TC_NAT_BUF_LEN),
100+
});
101+
102+
impl TcNat {
103+
pub fn set_new_addr(mut self, target: Ipv4Addr) -> Self {
104+
self.new_addr = target.octets().to_vec();
105+
self
106+
}
107+
108+
pub fn set_old_addr(mut self, target: Ipv4Addr) -> Self {
109+
self.old_addr = target.octets().to_vec();
110+
self
111+
}
112+
113+
pub fn set_prefix(mut self, prefix_len: usize) -> Self {
114+
assert!(prefix_len <= 32);
115+
116+
let prefix: u32 = if prefix_len == 0 {
117+
0x0
118+
} else {
119+
!((1 << (32 - prefix_len)) - 1)
120+
};
121+
self.mask = prefix.to_be_bytes().to_vec();
122+
123+
self
124+
}
125+
}
126+
impl Emitable for TcNat {
127+
fn buffer_len(&self) -> usize {
128+
TC_NAT_BUF_LEN
129+
}
130+
131+
fn emit(&self, buffer: &mut [u8]) {
132+
let mut packet = TcNatBuffer::new(buffer);
133+
packet.set_index(self.index);
134+
packet.set_capab(self.capab);
135+
packet.set_action(self.action);
136+
packet.set_refcnt(self.refcnt);
137+
packet.set_bindcnt(self.bindcnt);
138+
139+
packet.old_addr_mut().copy_from_slice(&self.old_addr[0..4]);
140+
packet.new_addr_mut().copy_from_slice(&self.new_addr[0..4]);
141+
packet.mask_mut().copy_from_slice(&self.mask[0..4]);
142+
packet.set_flags(self.flags);
143+
}
144+
}
145+
146+
impl<'buf, T: AsRef<[u8]> + ?Sized> Parseable<TcNatBuffer<&'buf T>> for TcNat {
147+
fn parse(buf: &TcNatBuffer<&'buf T>) -> Result<Self, DecodeError> {
148+
Ok(Self {
149+
index: buf.index(),
150+
capab: buf.capab(),
151+
action: buf.action(),
152+
refcnt: buf.refcnt(),
153+
bindcnt: buf.bindcnt(),
154+
old_addr: buf.old_addr().to_vec(),
155+
new_addr: buf.new_addr().to_vec(),
156+
mask: buf.mask().to_vec(),
157+
flags: buf.flags(),
158+
})
159+
}
160+
}

0 commit comments

Comments
 (0)