Skip to content

Commit bf6c71e

Browse files
committed
Support creating multicast netlink connection
Introduced `new_multicast_connection()` and `new_multicast_connection_with_socket()` taking `&[MulticastGroup]` as argument. Example code: ```rust let (conn, mut _handle, mut messages) = new_multicast_connection(&[ MulticastGroup::Link, ]).unwrap() // Spawn `Connection` to start polling netlink socket. tokio::spawn(conn); // Start receiving events through `messages` channel. while let Some((message, _)) = messages.next().await { let payload = message.payload; println!("{payload:?}"); } ``` Example code updated. Signed-off-by: Gris Ge <[email protected]>
1 parent 171cd72 commit bf6c71e

File tree

4 files changed

+165
-63
lines changed

4 files changed

+165
-63
lines changed

examples/ip_monitor.rs

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

33
use futures::stream::StreamExt;
4-
use netlink_sys::{AsyncSocket, SocketAddr};
5-
use rtnetlink::new_connection;
4+
use rtnetlink::{new_multicast_connection, MulticastGroup};
65

7-
const RTNLGRP_LINK: u32 = 1;
8-
const RTNLGRP_NEIGH: u32 = 3;
9-
const RTNLGRP_IPV4_IFADDR: u32 = 5;
10-
const RTNLGRP_IPV4_MROUTE: u32 = 6;
11-
const RTNLGRP_IPV4_ROUTE: u32 = 7;
12-
const RTNLGRP_IPV4_RULE: u32 = 8;
13-
const RTNLGRP_IPV6_IFADDR: u32 = 9;
14-
const RTNLGRP_IPV6_MROUTE: u32 = 10;
15-
const RTNLGRP_IPV6_ROUTE: u32 = 11;
16-
const RTNLGRP_IPV6_RULE: u32 = 19;
17-
const RTNLGRP_IPV4_NETCONF: u32 = 24;
18-
const RTNLGRP_IPV6_NETCONF: u32 = 25;
19-
const RTNLGRP_MPLS_ROUTE: u32 = 27;
20-
const RTNLGRP_NSID: u32 = 28;
21-
const RTNLGRP_MPLS_NETCONF: u32 = 29;
22-
23-
const fn nl_mgrp(group: u32) -> u32 {
24-
if group > 31 {
25-
panic!("use netlink_sys::Socket::add_membership() for this group");
26-
}
27-
if group == 0 {
28-
0
29-
} else {
30-
1 << (group - 1)
31-
}
32-
}
336
#[tokio::main]
347
async fn main() -> Result<(), String> {
358
// conn - `Connection` that has a netlink socket which is a `Future` that
@@ -39,42 +12,28 @@ async fn main() -> Result<(), String> {
3912
// messages.
4013
//
4114
// messages - A channel receiver.
42-
let (mut conn, mut _handle, mut messages) =
43-
new_connection().map_err(|e| format!("{e}"))?;
44-
45-
// These flags specify what kinds of broadcast messages we want to listen
46-
// for.
47-
let groups = nl_mgrp(RTNLGRP_LINK)
48-
| nl_mgrp(RTNLGRP_IPV4_IFADDR)
49-
| nl_mgrp(RTNLGRP_IPV6_IFADDR)
50-
| nl_mgrp(RTNLGRP_IPV4_ROUTE)
51-
| nl_mgrp(RTNLGRP_IPV6_ROUTE)
52-
| nl_mgrp(RTNLGRP_MPLS_ROUTE)
53-
| nl_mgrp(RTNLGRP_IPV4_MROUTE)
54-
| nl_mgrp(RTNLGRP_IPV6_MROUTE)
55-
| nl_mgrp(RTNLGRP_NEIGH)
56-
| nl_mgrp(RTNLGRP_IPV4_NETCONF)
57-
| nl_mgrp(RTNLGRP_IPV6_NETCONF)
58-
| nl_mgrp(RTNLGRP_IPV4_RULE)
59-
| nl_mgrp(RTNLGRP_IPV6_RULE)
60-
| nl_mgrp(RTNLGRP_NSID)
61-
| nl_mgrp(RTNLGRP_MPLS_NETCONF);
62-
63-
let addr = SocketAddr::new(0, groups);
64-
conn.socket_mut()
65-
.socket_mut()
66-
.bind(&addr)
67-
.expect("Failed to bind");
15+
let (conn, mut _handle, mut messages) = new_multicast_connection(&[
16+
MulticastGroup::Link,
17+
MulticastGroup::Ipv4Ifaddr,
18+
MulticastGroup::Ipv6Ifaddr,
19+
MulticastGroup::Ipv4Route,
20+
MulticastGroup::Ipv6Route,
21+
MulticastGroup::MplsRoute,
22+
MulticastGroup::Ipv4Mroute,
23+
MulticastGroup::Ipv6Mroute,
24+
MulticastGroup::Neigh,
25+
MulticastGroup::Ipv4Netconf,
26+
MulticastGroup::Ipv6Netconf,
27+
MulticastGroup::Ipv4Rule,
28+
MulticastGroup::Ipv6Rule,
29+
MulticastGroup::Nsid,
30+
MulticastGroup::MplsNetconf,
31+
])
32+
.map_err(|e| format!("{e}"))?;
6833

6934
// Spawn `Connection` to start polling netlink socket.
7035
tokio::spawn(conn);
7136

72-
// Use `Handle` to send request to kernel to start multicasting rtnetlink
73-
// events.
74-
tokio::spawn(async move {
75-
// Create message to enable
76-
});
77-
7837
// Start receiving events through `messages` channel.
7938
while let Some((message, _)) = messages.next().await {
8039
let payload = message.payload;

src/connection.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use netlink_packet_route::RouteNetlinkMessage;
88
use netlink_proto::Connection;
99
use netlink_sys::{protocols::NETLINK_ROUTE, AsyncSocket, SocketAddr};
1010

11-
use crate::Handle;
11+
use crate::{Handle, MulticastGroup};
1212

1313
#[cfg(feature = "tokio_socket")]
1414
#[allow(clippy::type_complexity)]
@@ -20,6 +20,19 @@ pub fn new_connection() -> io::Result<(
2020
new_connection_with_socket()
2121
}
2222

23+
/// Equal to `ip monitor` command
24+
#[cfg(feature = "tokio_socket")]
25+
#[allow(clippy::type_complexity)]
26+
pub fn new_multicast_connection(
27+
groups: &[MulticastGroup],
28+
) -> io::Result<(
29+
Connection<RouteNetlinkMessage>,
30+
Handle,
31+
UnboundedReceiver<(NetlinkMessage<RouteNetlinkMessage>, SocketAddr)>,
32+
)> {
33+
new_multicast_connection_with_socket(groups)
34+
}
35+
2336
#[allow(clippy::type_complexity)]
2437
pub fn new_connection_with_socket<S>() -> io::Result<(
2538
Connection<RouteNetlinkMessage, S>,
@@ -34,6 +47,39 @@ where
3447
Ok((conn, Handle::new(handle), messages))
3548
}
3649

50+
/// Equal to `ip monitor` command
51+
#[allow(clippy::type_complexity)]
52+
pub fn new_multicast_connection_with_socket<S>(
53+
groups: &[MulticastGroup],
54+
) -> io::Result<(
55+
Connection<RouteNetlinkMessage, S>,
56+
Handle,
57+
UnboundedReceiver<(NetlinkMessage<RouteNetlinkMessage>, SocketAddr)>,
58+
)>
59+
where
60+
S: AsyncSocket,
61+
{
62+
let (mut conn, handle, messages) =
63+
netlink_proto::new_connection_with_socket::<RouteNetlinkMessage, S>(
64+
NETLINK_ROUTE,
65+
)?;
66+
let mut all_groups: u32 = 0;
67+
for group in groups.iter().filter(|g| !g.need_via_add_membership()) {
68+
all_groups |= 1 << (*group as u32 - 1);
69+
}
70+
71+
let addr = SocketAddr::new(0, all_groups);
72+
conn.socket_mut().socket_mut().bind(&addr)?;
73+
74+
for group in groups.iter().filter(|g| g.need_via_add_membership()) {
75+
conn.socket_mut()
76+
.socket_mut()
77+
.add_membership(*group as u32)?;
78+
}
79+
80+
Ok((conn, Handle::new(handle), messages))
81+
}
82+
3783
#[allow(clippy::type_complexity)]
3884
pub fn from_socket<S>(
3985
socket: S,

src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod errors;
1717
mod handle;
1818
mod link;
1919
mod macros;
20+
mod multicast;
2021
mod neighbour;
2122
#[cfg(not(target_os = "freebsd"))]
2223
mod ns;
@@ -26,7 +27,7 @@ mod rule;
2627
mod traffic_control;
2728

2829
#[cfg(feature = "tokio_socket")]
29-
pub use crate::connection::new_connection;
30+
pub use crate::connection::{new_connection, new_multicast_connection};
3031
#[cfg(not(target_os = "freebsd"))]
3132
pub use crate::ns::{NetworkNamespace, NETNS_PATH, NONE_FS, SELF_NS_PATH};
3233
#[cfg(not(target_os = "freebsd"))]
@@ -41,7 +42,10 @@ pub use crate::{
4142
AddressAddRequest, AddressDelRequest, AddressGetRequest, AddressHandle,
4243
AddressMessageBuilder,
4344
},
44-
connection::{from_socket, new_connection_with_socket},
45+
connection::{
46+
from_socket, new_connection_with_socket,
47+
new_multicast_connection_with_socket,
48+
},
4549
errors::Error,
4650
handle::Handle,
4751
link::{
@@ -51,6 +55,7 @@ pub use crate::{
5155
LinkUnspec, LinkVeth, LinkVlan, LinkVrf, LinkVxlan, LinkWireguard,
5256
LinkXfrm, QosMapping,
5357
},
58+
multicast::MulticastGroup,
5459
neighbour::{
5560
NeighbourAddRequest, NeighbourDelRequest, NeighbourGetRequest,
5661
NeighbourHandle,

src/multicast.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
// const RTNLGRP_NONE: u32 = 0;
4+
const RTNLGRP_LINK: u32 = 1;
5+
const RTNLGRP_NOTIFY: u32 = 2;
6+
const RTNLGRP_NEIGH: u32 = 3;
7+
const RTNLGRP_TC: u32 = 4;
8+
const RTNLGRP_IPV4_IFADDR: u32 = 5;
9+
const RTNLGRP_IPV4_MROUTE: u32 = 6;
10+
const RTNLGRP_IPV4_ROUTE: u32 = 7;
11+
const RTNLGRP_IPV4_RULE: u32 = 8;
12+
const RTNLGRP_IPV6_IFADDR: u32 = 9;
13+
const RTNLGRP_IPV6_MROUTE: u32 = 10;
14+
const RTNLGRP_IPV6_ROUTE: u32 = 11;
15+
const RTNLGRP_IPV6_IFINFO: u32 = 12;
16+
const RTNLGRP_DECNET_IFADDR: u32 = 13;
17+
// const RTNLGRP_NOP2: u32 = 14
18+
const RTNLGRP_DECNET_ROUTE: u32 = 15;
19+
const RTNLGRP_DECNET_RULE: u32 = 16;
20+
// const RTNLGRP_NOP4: u32 = 17;
21+
const RTNLGRP_IPV6_PREFIX: u32 = 18;
22+
const RTNLGRP_IPV6_RULE: u32 = 19;
23+
const RTNLGRP_ND_USEROPT: u32 = 20;
24+
const RTNLGRP_PHONET_IFADDR: u32 = 21;
25+
const RTNLGRP_PHONET_ROUTE: u32 = 22;
26+
const RTNLGRP_DCB: u32 = 23;
27+
const RTNLGRP_IPV4_NETCONF: u32 = 24;
28+
const RTNLGRP_IPV6_NETCONF: u32 = 25;
29+
const RTNLGRP_MDB: u32 = 26;
30+
const RTNLGRP_MPLS_ROUTE: u32 = 27;
31+
const RTNLGRP_NSID: u32 = 28;
32+
const RTNLGRP_MPLS_NETCONF: u32 = 29;
33+
const RTNLGRP_IPV4_MROUTE_R: u32 = 30;
34+
const RTNLGRP_IPV6_MROUTE_R: u32 = 31;
35+
const RTNLGRP_NEXTHOP: u32 = 32;
36+
const RTNLGRP_BRVLAN: u32 = 33;
37+
const RTNLGRP_MCTP_IFADDR: u32 = 34;
38+
const RTNLGRP_TUNNEL: u32 = 35;
39+
const RTNLGRP_STATS: u32 = 36;
40+
const RTNLGRP_IPV4_MCADDR: u32 = 37;
41+
const RTNLGRP_IPV6_MCADDR: u32 = 38;
42+
const RTNLGRP_IPV6_ACADDR: u32 = 39;
43+
44+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
45+
#[repr(u32)]
46+
#[non_exhaustive]
47+
pub enum MulticastGroup {
48+
Link = RTNLGRP_LINK,
49+
Notify = RTNLGRP_NOTIFY,
50+
Neigh = RTNLGRP_NEIGH,
51+
Tc = RTNLGRP_TC,
52+
Ipv4Ifaddr = RTNLGRP_IPV4_IFADDR,
53+
Ipv4Mroute = RTNLGRP_IPV4_MROUTE,
54+
Ipv4Route = RTNLGRP_IPV4_ROUTE,
55+
Ipv4Rule = RTNLGRP_IPV4_RULE,
56+
Ipv6Ifaddr = RTNLGRP_IPV6_IFADDR,
57+
Ipv6Mroute = RTNLGRP_IPV6_MROUTE,
58+
Ipv6Route = RTNLGRP_IPV6_ROUTE,
59+
Ipv6Ifinfo = RTNLGRP_IPV6_IFINFO,
60+
DecnetIfaddr = RTNLGRP_DECNET_IFADDR,
61+
DecnetRoute = RTNLGRP_DECNET_ROUTE,
62+
DecnetRule = RTNLGRP_DECNET_RULE,
63+
Ipv6Prefix = RTNLGRP_IPV6_PREFIX,
64+
Ipv6Rule = RTNLGRP_IPV6_RULE,
65+
NdUseropt = RTNLGRP_ND_USEROPT,
66+
PhonetIfaddr = RTNLGRP_PHONET_IFADDR,
67+
PhonetRoute = RTNLGRP_PHONET_ROUTE,
68+
Dcb = RTNLGRP_DCB,
69+
Ipv4Netconf = RTNLGRP_IPV4_NETCONF,
70+
Ipv6Netconf = RTNLGRP_IPV6_NETCONF,
71+
Mdb = RTNLGRP_MDB,
72+
MplsRoute = RTNLGRP_MPLS_ROUTE,
73+
Nsid = RTNLGRP_NSID,
74+
MplsNetconf = RTNLGRP_MPLS_NETCONF,
75+
Ipv4MrouteR = RTNLGRP_IPV4_MROUTE_R,
76+
Ipv6MrouteR = RTNLGRP_IPV6_MROUTE_R,
77+
Nexthop = RTNLGRP_NEXTHOP,
78+
Brvlan = RTNLGRP_BRVLAN,
79+
MctpIfaddr = RTNLGRP_MCTP_IFADDR,
80+
Tunnel = RTNLGRP_TUNNEL,
81+
Stats = RTNLGRP_STATS,
82+
Ipv4Mcaddr = RTNLGRP_IPV4_MCADDR,
83+
Ipv6Mcaddr = RTNLGRP_IPV6_MCADDR,
84+
Ipv6Acaddr = RTNLGRP_IPV6_ACADDR,
85+
}
86+
87+
impl MulticastGroup {
88+
/// Whether need to use `netlink_sys::Socket::add_membership()`.
89+
pub fn need_via_add_membership(self) -> bool {
90+
self as u32 > 31
91+
}
92+
}

0 commit comments

Comments
 (0)