Skip to content

Commit

Permalink
Introduce LinkMessageBuilder
Browse files Browse the repository at this point in the history
**API BREAK**

To remove the duplicate error of `LinkAddRequest` and `LinkSetRequest`,
this patch introduce `LinkMessageBuilder` to generate `LinkMessage` for
link handlers to use.

The `impl LinkMessageBuilder<T>` holds the common functions available for all
interface types.
The `impl LinkMessageBuilder<LinkVlan>` holds VLAN specific functions.

The LinkMessageBuilder is designed for advanced user, wrapper functions
are created for common use cases. For example, to create a VLAN
interface:

```rus
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
    .link()
    .add(
        LinkVlan::new("vlan100", 10, 100)
            .up()
            .build()
    )
    .execute()
    .await
    .map_err(|e| format!("{e}"))
```

These patches included these new structures to generate matching
LinkMessageBuilder:

 * `LinkUnspec` (for matching existing interface)
 * `LinkDummy`
 * `LinkVeth`
 * `LinkVlan`
 * `LinkVxlan`
 * `LinkMacVlan`
 * `LinkMacVtap`
 * `LinkWireguard`
 * `LinkBondPort`

Special note:

 * Due to confliction, the previous VxLAN `link()` function changed to
   `dev()`. The `link()` is the share function for all interface types. The
   API is matching with `ip link` command line option for vxlan.
   Please check `examples/create_vxlan.rs` for usage.

 * The `LinkHandler::set_bond_port()` changed to
   `LinkHandler::set_port()`, please check `examples/set_bond_port.rs`
   for usage.

 * The `message_mut()` function is removed from `LinkSetRequest` and
   `LinkAddRequest`, user should modify the LinkMessage before sent to
   handler.

Signed-off-by: Gris Ge <[email protected]>
  • Loading branch information
cathay4t committed Jul 9, 2024
1 parent d6e8b4c commit aa1820a
Show file tree
Hide file tree
Showing 34 changed files with 1,705 additions and 1,139 deletions.
15 changes: 9 additions & 6 deletions examples/create_bond.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
// SPDX-License-Identifier: MIT

use netlink_packet_route::link::BondMode;
use rtnetlink::new_connection;
use std::net::{Ipv4Addr, Ipv6Addr};

use rtnetlink::{new_connection, packet_route::link::BondMode, LinkBond};

#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);
handle
.link()
.add()
.bond("my-bond".into())

let message = LinkBond::new("my-bond")
.mode(BondMode::ActiveBackup)
.miimon(100)
.updelay(100)
Expand All @@ -26,6 +24,11 @@ async fn main() -> Result<(), String> {
Ipv6Addr::new(0xfd02, 0, 0, 0, 0, 0, 0, 2),
])
.up()
.build();

handle
.link()
.add(message)
.execute()
.await
.map_err(|e| format!("{e}"))
Expand Down
6 changes: 3 additions & 3 deletions examples/create_bridge.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// SPDX-License-Identifier: MIT

use rtnetlink::new_connection;
use rtnetlink::{new_connection, LinkBridge};

#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
.link()
.add()
.bridge("my-bridge-1".into())
.add(LinkBridge::new("my-bridge").build())
.execute()
.await
.map_err(|e| format!("{e}"))
Expand Down
16 changes: 16 additions & 0 deletions examples/create_dummy.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

use rtnetlink::{new_connection, LinkDummy};

#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
.link()
.add(LinkDummy::new("dummy0").build())
.execute()
.await
.map_err(|e| format!("{e}"))
}
28 changes: 15 additions & 13 deletions examples/create_macvlan.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use macaddr::MacAddr;
use rtnetlink::{new_connection, Error, Handle};
use std::{env, str::FromStr};

use netlink_packet_route::link::{LinkAttribute, MacVlanMode};
use futures::stream::TryStreamExt;
use macaddr::MacAddr;
use rtnetlink::{
new_connection, packet_route::link::MacVlanMode, Error, Handle, LinkMacVlan,
};

#[tokio::main]
async fn main() -> Result<(), String> {
Expand Down Expand Up @@ -37,19 +38,20 @@ async fn create_macvlan(
link_name: String,
mac_address: Option<Vec<u8>>,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(link_name.clone()).execute();
if let Some(link) = links.try_next().await? {
let mut request = handle.link().add().macvlan(
"test_macvlan".into(),
link.header.index,
let mut parent_links =
handle.link().get().match_name(link_name.clone()).execute();
if let Some(parent) = parent_links.try_next().await? {
let mut builder = LinkMacVlan::new(
"my-macvlan",
parent.header.index,
MacVlanMode::Bridge,
);
if let Some(mac) = mac_address {
request
.message_mut()
.attributes
.push(LinkAttribute::Address(mac));
builder = builder.address(mac);
}
let message = builder.build();
let request = handle.link().add(message);

request.execute().await?
} else {
println!("no link {link_name} found");
Expand Down
28 changes: 17 additions & 11 deletions examples/create_macvtap.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use netlink_packet_route::link::MacVtapMode;
use rtnetlink::{new_connection, Error, Handle};
use std::env;

use futures::stream::TryStreamExt;
use rtnetlink::{
new_connection, packet_route::link::MacVtapMode, Error, Handle, LinkMacVtap,
};

#[tokio::main]
async fn main() -> Result<(), String> {
let args: Vec<String> = env::args().collect();
Expand All @@ -24,18 +26,22 @@ async fn main() -> Result<(), String> {

async fn create_macvtap(
handle: Handle,
veth_name: String,
link_name: String,
) -> Result<(), Error> {
let mut links = handle.link().get().match_name(veth_name.clone()).execute();
if let Some(link) = links.try_next().await? {
let request = handle.link().add().macvtap(
"test_macvtap".into(),
link.header.index,
let mut parent_links =
handle.link().get().match_name(link_name.clone()).execute();
if let Some(parent) = parent_links.try_next().await? {
let message = LinkMacVtap::new(
"test_macvtap",
parent.header.index,
MacVtapMode::Bridge,
);
)
.build();

let request = handle.link().add(message);
request.execute().await?
} else {
println!("no link link {veth_name} found");
println!("no link link {link_name} found");
}
Ok(())
}
Expand Down
7 changes: 3 additions & 4 deletions examples/create_veth.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// SPDX-License-Identifier: MIT

use rtnetlink::new_connection;

use rtnetlink::{new_connection, LinkVeth};
#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
.link()
.add()
.veth("veth-rs-1".into(), "veth-rs-2".into())
.add(LinkVeth::new("veth1", "veth1-peer").build())
.execute()
.await
.map_err(|e| format!("{e}"))
Expand Down
10 changes: 7 additions & 3 deletions examples/create_vlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::{env, error::Error as StdError, str::FromStr};

use rtnetlink::{new_connection, QosMapping};
use rtnetlink::{new_connection, LinkVlan, QosMapping};

fn parse_mapping(parameter: &str) -> Result<QosMapping, Box<dyn StdError>> {
let (from, to) = parameter
Expand Down Expand Up @@ -109,10 +109,14 @@ async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

let message = LinkVlan::new(&name, base, id)
.up()
.qos(ingress, egress)
.build();

handle
.link()
.add()
.vlan_with_qos(name, base, id, ingress, egress)
.add(message)
.execute()
.await
.map_err(|err| format!("Netlink request failed: {err}"))
Expand Down
16 changes: 16 additions & 0 deletions examples/create_vrf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

use rtnetlink::{new_connection, LinkVrf};

#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
.link()
.add(LinkVrf::new("my-vrf", 101).build())
.execute()
.await
.map_err(|e| format!("{e}"))
}
16 changes: 7 additions & 9 deletions examples/create_vxlan.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle};
use rtnetlink::{new_connection, Error, Handle, LinkVxlan};
use std::env;

#[tokio::main]
Expand All @@ -24,15 +24,13 @@ async fn main() -> Result<(), String> {
async fn create_vxlan(handle: Handle, name: String) -> Result<(), Error> {
let mut links = handle.link().get().match_name(name.clone()).execute();
if let Some(link) = links.try_next().await? {
handle
.link()
.add()
.vxlan("vxlan0".into(), 10u32)
.link(link.header.index)
.port(4789)
let message = LinkVxlan::new("vxlan0", 10)
.dev(link.header.index)
.up()
.execute()
.await?
.port(4789)
.build();

handle.link().add(message).execute().await?
} else {
println!("no link link {name} found");
}
Expand Down
16 changes: 16 additions & 0 deletions examples/create_wireguard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: MIT

use rtnetlink::{new_connection, LinkWireguard};

#[tokio::main]
async fn main() -> Result<(), String> {
let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

handle
.link()
.add(LinkWireguard::new("my-wg").build())
.execute()
.await
.map_err(|e| format!("{e}"))
}
52 changes: 52 additions & 0 deletions examples/create_xfrm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle, LinkXfrm};

#[tokio::main]
async fn main() -> Result<(), String> {
let args: Vec<String> = std::env::args().collect();
if args.len() != 2 {
usage();
return Ok(());
}
let link_name = &args[1];

let (connection, handle, _) = new_connection().unwrap();
tokio::spawn(connection);

create_xfrm(handle, link_name.to_string())
.await
.map_err(|e| format!("{e}"))
}

async fn create_xfrm(handle: Handle, link_name: String) -> Result<(), Error> {
let mut parent_links =
handle.link().get().match_name(link_name.clone()).execute();
if let Some(parent) = parent_links.try_next().await? {
let request = handle
.link()
.add(LinkXfrm::new("my-xfrm", parent.header.index, 0x08).build());

request.execute().await?
} else {
println!("no link {link_name} found");
}
Ok(())
}

fn usage() {
eprintln!(
"usage:
cargo run --example create_xfrm -- <link name>
Note that you need to run this program as root. Instead of running cargo as
root, build the example normally:
cargo build --example create_xfrm
Then find the binary in the target directory:
cd target/debug/examples ; sudo ./create_xfrm <link_name>"
);
}
10 changes: 8 additions & 2 deletions examples/get_bond_port_settings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: MIT

use futures::stream::TryStreamExt;
use rtnetlink::{new_connection, Error, Handle};
use rtnetlink::{
new_connection, packet_route::link::LinkAttribute, Error, Handle,
};
use std::env;

#[tokio::main]
Expand Down Expand Up @@ -35,7 +37,11 @@ async fn dump_bond_port_settings(
let mut link_messgage =
handle.link().get().match_name(linkname).execute();
while let Some(msg) = link_messgage.try_next().await? {
println!("{msg:?}");
for nla in msg.attributes {
if let LinkAttribute::LinkInfo(i) = &nla {
println!("{:?}", i);
}
}
}
Ok(())
} else {
Expand Down
Loading

0 comments on commit aa1820a

Please sign in to comment.