Skip to content

Commit

Permalink
[API break] link: Reorganize the code base
Browse files Browse the repository at this point in the history
 * This patch is first preparation on stable release 1.0 for submodule
   link. The detailed checklist for developer is stated in
   README.md file.

 * Stored constants into where it been used. Will remove `constants.rs`
   once all components finished.

 * Replace `pub use self::*` to explicit expose.

 * Removed `data` folder, `README.md` file has expanded to hold steps to
   capture netlink packets.

 * Removed `Unspec` as kernel not use it.

 * Removed `benches` folder as never used.

 * Removed dependency on `libc` and `lazy_static`.

 * Added dependency on `log`. Considering `rtnetlink` also has it, no
   burden added to end user.

 * Many member of `InfoVxlan` changed from u8 to bool after confirmed
   with kernel code.

 * Changed API:
    * Rename:
      * `link::Nla` to `link::LinkAttribute` because `Nla` is a trait
      * `link:Info` to `link::LinkInfo`
      * `link::VethInfo` to `link::InfoVeth`
      * `link::InfoXfrmTun` to `link::InfoXfrm`
   * The AfSpec for ipv4 and ipv6 is rework. Please check `AfSpecUnspec`
   * Removed `link::Nla::AltIfName`. Use
     `link::LinkAttribute::PropList<vec![link::Prop::AltIfName]>`
     instead.
   * Changed `InfoVlan::Protocol<u16>` to
     `InfoVlan::Protocol<VlanProtocol>`.
   * `LinkHeader` changed to use enum instead raw integer on flags,
     address family and link layer type.
   * Change `LinkMessage.nlas` to `LinkMessage.attributes`.

 * Added:
    * `link::LinkFlag` and `LinkFlags` for `IFF_UP` and etc
    * `link::LinkLayerType` for `ARPHRD_ETHER` and etc
    * `crate::AddressFamily` for `AF_UNSPEC` and etc

Unit test cases included.

Signed-off-by: Gris Ge <[email protected]>
  • Loading branch information
cathay4t committed Nov 6, 2023
1 parent 37f9c5c commit 2a7df8b
Show file tree
Hide file tree
Showing 86 changed files with 6,260 additions and 5,030 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Build

on:
pull_request:
types: [opened, synchronize, reopened]
push:
branches:
- main

jobs:
build:
name: Build
runs-on: ubuntu-latest
strategy:
fail-fast: true
matrix:
include:
- rust_target: "x86_64-unknown-linux-gnu"
- rust_target: "x86_64-unknown-freebsd"
- rust_target: "x86_64-unknown-fuchsia"
- rust_target: "x86_64-apple-darwin"
- rust_target: "x86_64-linux-android"

steps:
- uses: actions/checkout@v3

- name: Install Rust Stable
run: |
rustup override set stable
rustup update stable
rustup target add ${{ matrix.rust_target }}
- name: Build test for ${{ matrix.rust_target }}
run: cargo build --target ${{ matrix.rust_target }}
13 changes: 2 additions & 11 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,17 @@ rich_nlas = []

[dependencies]
anyhow = "1.0.31"
bitflags = "1.2.1"
byteorder = "1.3.2"
libc = "0.2.66"
log = { version = "0.4.20", features = ["std"] }
netlink-packet-core = { version = "0.7.0" }
netlink-packet-utils = { version = "0.5.2" }
bitflags = "1.2.1"

[[example]]
name = "dump_packet_links"

[dev-dependencies]
criterion = "0.3.0"
pcap-file = "1.1.1"
lazy_static = "1.4.0"
netlink-sys = { version = "0.8.5" }
pretty_assertions = "0.7.2"

[[bench]]
name = "link_message"
harness = false

[[bench]]
name = "rtnetlink_dump"
harness = false
62 changes: 56 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,59 @@
# netlink-packet-route
# Rust crate for Netlink Route Protocol

Rust crate providing netlink message parsing and generating support for the
[netlink route protocol][1].
The `netlink-packet-route` crate is designed to abstract Netlink route
protocol([`rtnetlink`][rtnetlink_man]) packet into Rust data types. The goal of
this crate is saving netlink user from reading Kernel Netlink codes.

Rust crate document could be found at [docs.rs][2].
This crate grouped Netlink route protocol into these modules:
* `link`: NIC interface, similar to to `ip link` command.
* `address`: IP address, similar to `ip address` command.
* `route`: Route, similar to `ip route` command.
* `rule`: Route rule, similar to `ip rule` command.
* `tc`: Traffic control, similar to `tc` command.
* `neighbour`: Neighbour, similar to `ip neighbour` command.
* `neighbour_table`: Neighbour table, similar to `ip ntable` command.
* `nsid`: Namespace, similar to `ip netns` command.

[1]: https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
[2]: https://docs.rs/netlink-packet-route/
Normally, you should use [`rtnetlink`][rtnetlink_url] instead of using this
crate directly.

## Development
* Please use `git commit --signoff` to append Signed-off-by trailer to commit
message.

* For new source file, please append `// SPDX-License-Identifier: MIT` at
the beginning with content of license new code to MIT license.

* No panic is allowed, please use `Result<>` instead of `unwrap()` or
`expect()`.

* Please run `cargo fmt` and `cargo clippy` before creating pull request.

* All struct/enum should be decorated by
[`#[non_exhaustive]`][non_exhaustive_doc] to preserve
API backwards compatibility unless explicit approval from maintainer.

* Unknown netlink attribute should be stored into `Other(DefaultNla)` instead
of breaking decoding.

* Please use unit test case to cover the serialize and deserialize of the
changed netlink attribute. To capture the netlink raw bytes, you may use
tcpdump/wireshark again the `nlmon` interface. For example:

* The integration test(play with linux kernel netlink interface) should be
placed into `rtnetlink` crate. Current(netlink-packet-route) crate should
only unit test case only.

```bash
modprobe nlmon
ip link add nl0 type nlmon
ip link set nl0 up
tcpdump -i nl0 -w netlink_capture_file.cap
```

* For certain netlink message which cannot captured by nlmon, please use
Rust Debug and explain every bits in comment.

[rtnetlink_man]: https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
[rtnetlink_url]: https://docs.rs/rtnetlink
[non_exhaustive_doc]: https://doc.rust-lang.org/stable/reference/attributes/type_system.html#the-non_exhaustive-attribute
66 changes: 0 additions & 66 deletions benches/link_message.rs

This file was deleted.

29 changes: 0 additions & 29 deletions benches/rtnetlink_dump.rs

This file was deleted.

23 changes: 0 additions & 23 deletions data/README.md

This file was deleted.

Binary file removed data/rtnetlink.pcap
Binary file not shown.
7 changes: 5 additions & 2 deletions examples/dump_neighbours.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use netlink_packet_route::{
NUD_PERMANENT, NUD_PROBE, NUD_REACHABLE, NUD_STALE,
},
nlas::neighbour::Nla,
NeighbourMessage, RtnlMessage, AF_INET, AF_INET6,
AddressFamily, NeighbourMessage, RtnlMessage,
};
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};

Expand Down Expand Up @@ -58,7 +58,10 @@ fn main() {
entry,
)) => {
let address_family = entry.header.family as u16;
if address_family == AF_INET || address_family == AF_INET6 {
if address_family == u8::from(AddressFamily::Inet) as u16
|| address_family
== u8::from(AddressFamily::Inet6) as u16
{
print_entry(entry);
}
}
Expand Down
10 changes: 5 additions & 5 deletions examples/dump_packet_link_bridge_vlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use netlink_packet_core::{
NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST,
};
use netlink_packet_route::{
nlas::link::Nla, LinkMessage, RtnlMessage, AF_BRIDGE,
RTEXT_FILTER_BRVLAN_COMPRESSED,
link::{LinkAttribute, LinkMessage},
AddressFamily, RtnlMessage, RTEXT_FILTER_BRVLAN_COMPRESSED,
};
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};

Expand All @@ -15,10 +15,10 @@ fn main() {
socket.connect(&SocketAddr::new(0, 0)).unwrap();

let mut message = LinkMessage::default();
message.header.interface_family = AF_BRIDGE as u8;
message.header.interface_family = AddressFamily::Bridge;
message
.nlas
.push(Nla::ExtMask(RTEXT_FILTER_BRVLAN_COMPRESSED));
.attributes
.push(LinkAttribute::ExtMask(RTEXT_FILTER_BRVLAN_COMPRESSED));
let mut packet = NetlinkMessage::new(
NetlinkHeader::default(),
NetlinkPayload::from(RtnlMessage::GetLink(message)),
Expand Down
2 changes: 1 addition & 1 deletion examples/dump_packet_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use netlink_packet_core::{
NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_DUMP, NLM_F_REQUEST,
};
use netlink_packet_route::{LinkMessage, RtnlMessage};
use netlink_packet_route::{link::LinkMessage, RtnlMessage};
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};

fn main() {
Expand Down
6 changes: 3 additions & 3 deletions examples/new_rule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use netlink_packet_core::{
NLM_F_EXCL, NLM_F_REQUEST,
};
use netlink_packet_route::{
constants::{AF_INET, FR_ACT_TO_TBL, RT_TABLE_DEFAULT},
rule, RtnlMessage, RuleHeader, RuleMessage,
constants::{FR_ACT_TO_TBL, RT_TABLE_DEFAULT},
rule, AddressFamily, RtnlMessage, RuleHeader, RuleMessage,
};
use netlink_sys::{protocols::NETLINK_ROUTE, Socket, SocketAddr};

Expand All @@ -16,7 +16,7 @@ fn main() {
socket.connect(&SocketAddr::new(0, 0)).unwrap();

let rule_msg_hdr = RuleHeader {
family: AF_INET as u8,
family: u8::from(AddressFamily::Inet),
table: RT_TABLE_DEFAULT,
action: FR_ACT_TO_TBL,
..Default::default()
Expand Down
41 changes: 41 additions & 0 deletions src/address_family_fallback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: MIT

#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
#[non_exhaustive]
// We are using not using #[repr(u8)] here as we have duplicate(e.g. AF_ROUTE vs
// AF_NETLINK) here
pub enum AddressFamily {
#[default]
Unspec,
Local,
Unix,
Inet,
Inet6,
Other(u8),
}

impl From<u8> for AddressFamily {
fn from(d: u8) -> Self {
match d {
d if d == libc::AF_UNSPEC as u8 => Self::Unspec,
d if d == libc::AF_LOCAL as u8 => Self::Local,
d if d == libc::AF_UNIX as u8 => Self::Unix,
d if d == libc::AF_INET as u8 => Self::Inet,
d if d == libc::AF_INET6 as u8 => Self::Inet6,
_ => Self::Other(d),
}
}
}

impl From<AddressFamily> for u8 {
fn from(v: AddressFamily) -> u8 {
match v {
AddressFamily::Unspec => libc::AF_UNSPEC as u8,
AddressFamily::Local => libc::AF_LOCAL as u8,
AddressFamily::Unix => libc::AF_UNIX as u8,
AddressFamily::Inet => libc::AF_INET as u8,
AddressFamily::Inet6 => libc::AF_INET6 as u8,
AddressFamily::Other(d) => d,
}
}
}
Loading

0 comments on commit 2a7df8b

Please sign in to comment.