Skip to content

Commit 8185326

Browse files
ojedakloenk
authored andcommitted
Merge pull request #360 from Rust-for-Linux/alex-patch-1
ci: retry add-apt-repository to deal with network issues
2 parents bfe9ec6 + a8a369c commit 8185326

File tree

18 files changed

+2377
-3
lines changed

18 files changed

+2377
-3
lines changed

Diff for: .github/workflows/ci.yaml

+5-1
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,11 @@ jobs:
137137
138138
# Setup: LLVM
139139
- run: curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
140-
- run: sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main'
140+
# Retry to be resilient to intermittent network issues
141+
- run: |
142+
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' ||
143+
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main' ||
144+
sudo add-apt-repository 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main'
141145
- run: sudo apt-get update -y
142146
- run: sudo apt-get install -y llvm-12 clang-12 lld-12
143147
- run: echo $(llvm-config-12 --bindir) >> $GITHUB_PATH

Diff for: drivers/net/Kconfig

+16
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,22 @@ config DUMMY
7272
To compile this driver as a module, choose M here: the module
7373
will be called dummy.
7474

75+
config DUMMY_RS
76+
tristate "Dummy net driver support"
77+
depends on RUST
78+
help
79+
This is essentially a bit-bucket device (i.e. traffic you send to
80+
this device is consigned into oblivion) with a configurable IP
81+
address. It is most commonly used in order to make your currently
82+
inactive SLIP address seem like a real address for local programs.
83+
If you use SLIP or PPP, you might want to say Y here. It won't
84+
enlarge your kernel. What a deal. Read about it in the Network
85+
Administrator's Guide, available from
86+
<http://www.tldp.org/docs.html#guide>.
87+
88+
To compile this driver as a module, choose M here: the module
89+
will be called dummy_rs.
90+
7591
config WIREGUARD
7692
tristate "WireGuard secure network tunnel"
7793
depends on NET && INET

Diff for: drivers/net/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ obj-$(CONFIG_BONDING) += bonding/
1010
obj-$(CONFIG_IPVLAN) += ipvlan/
1111
obj-$(CONFIG_IPVTAP) += ipvlan/
1212
obj-$(CONFIG_DUMMY) += dummy.o
13+
obj-$(CONFIG_DUMMY_RS) += dummy_rs.o
1314
obj-$(CONFIG_WIREGUARD) += wireguard/
1415
obj-$(CONFIG_EQUALIZER) += eql.o
1516
obj-$(CONFIG_IFB) += ifb.o

Diff for: drivers/net/dummy_rs.rs

+235
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Rust dummy network driver
4+
//!
5+
//! This is a demonstration of what a small driver looks like in Rust, based on drivers/net/dummy.c.
6+
//! This code is provided as a demonstration only, not as a proposal to mass-rewrite existing drivers in Rust
7+
//!
8+
//! The purpose of this driver is to provide a device to point a
9+
//! route through, but not to actually transmit packets.
10+
//!
11+
//! Why? If you have a machine whose only connection is an occasional
12+
//! PPP/SLIP/PLIP link, you can only connect to your own hostname
13+
//! when the link is up. Otherwise you have to use localhost.
14+
//! This isn't very consistent.
15+
//!
16+
//! One solution is to set up a dummy link using PPP/SLIP/PLIP,
17+
//! but this seems (to me) too much overhead for too little gain.
18+
//! This driver provides a small alternative. Thus you can do
19+
//!
20+
//! [when not running slip]
21+
//! ifconfig dummy slip.addr.ess.here up
22+
//! [to go to slip]
23+
//! ifconfig dummy down
24+
//! dip whatever
25+
//!
26+
//! This was written by looking at the dummy network driver from Nick
27+
//! Holloway, which was written by looking at Donald Becker's skeleton driver
28+
//! and the loopback driver.
29+
//!
30+
//! Finn Behrens, 30th April 2021
31+
//!
32+
//! rust rewrite of the C version from Nick Holloway, 27th May 1994
33+
//! see [dummy.c](./dummy.c)
34+
35+
#![no_std]
36+
#![feature(allocator_api, global_asm)]
37+
38+
use kernel::net::device;
39+
use kernel::net::prelude::*;
40+
use kernel::net::rtnl;
41+
use kernel::Error;
42+
use kernel::{
43+
net::netlink::{NlAttrVec, NlExtAck},
44+
prelude::*,
45+
};
46+
47+
module! {
48+
type: RustNetDummy,
49+
name: b"dummy_rs",
50+
author: b"Rust for Linux Contributors",
51+
description: b"Rust dummy network driver",
52+
license: b"GPL v2",
53+
alias_rtnl_link: b"dummy_rs",
54+
params: {
55+
numdummies: usize {
56+
default: 0,
57+
permissions: 0,
58+
description: b"Number of dummy_rs pseudo devices",
59+
},
60+
},
61+
}
62+
63+
fn setup(dev: &mut NetDevice<DummyRsDev>) {
64+
dev.ether_setup();
65+
66+
dev.set_ops();
67+
68+
// Fill in device structure with ethernet-generic values.
69+
dev.add_flag(device::Iff::NOARP);
70+
dev.remove_flag(device::Iff::MULTICAST);
71+
72+
dev.add_private_flag(device::IffPriv::LIVE_ADDR_CHANGE);
73+
dev.add_private_flag(device::IffPriv::NO_QUEUE);
74+
75+
let mut feature = device::feature::NetIF::new();
76+
77+
feature += device::feature::NETIF_F_SG;
78+
feature += device::feature::NETIF_F_FRAGLIST;
79+
feature += device::feature::NETIF_F_GSO_SOFTWARE;
80+
feature += device::feature::NETIF_F_HW_CSUM;
81+
feature += device::feature::NETIF_F_HIGHDMA;
82+
feature += device::feature::NETIF_F_LLTX;
83+
feature += device::feature::NETIF_F_GSO_ENCAP_ALL;
84+
85+
dev.set_features(feature);
86+
dev.set_hw_features(feature);
87+
dev.set_hw_enc_features(feature);
88+
89+
dev.hw_addr_random();
90+
dev.set_mtu(0, 0);
91+
}
92+
93+
fn validate(tb: &NlAttrVec, _data: &NlAttrVec, _ext_ack: &NlExtAck) -> Result {
94+
if let Some(addr) = tb.get(kernel::bindings::IFLA_ADDRESS) {
95+
if Some(kernel::net::netlink::ETH_ALEN) != addr.nla_len() {
96+
return Err(Error::EINVAL);
97+
}
98+
if !addr.is_valid_ether_addr() {
99+
return Err(Error::EADDRNOTAVAIL);
100+
}
101+
}
102+
Ok(())
103+
}
104+
105+
rtnl_link_ops! {
106+
kind: b"dummy_rs",
107+
type: DummyRsDev,
108+
setup: setup,
109+
validate: validate,
110+
}
111+
112+
struct RustNetDummy {
113+
//dev: NetDevice<DummyRsDev>,
114+
}
115+
116+
impl KernelModule for RustNetDummy {
117+
fn init() -> Result<Self> {
118+
let num = *numdummies.read();
119+
120+
unsafe { dummy_rs_link_ops.register() }?;
121+
122+
for _ in 0..(num) {
123+
let dev = NetDevice::new(
124+
DummyRsDev,
125+
kernel::c_str!("dummyrs%d"),
126+
kernel::net::device::NetNameAssingType::Enum,
127+
1,
128+
1,
129+
)?;
130+
dev.set_rtnl_ops(unsafe { &dummy_rs_link_ops });
131+
132+
if let Err(e) = dev.register() {
133+
pr_warn!("could not register: {}", e.to_kernel_errno());
134+
return Err(e);
135+
}
136+
}
137+
138+
Ok(RustNetDummy {
139+
//dev,
140+
})
141+
}
142+
}
143+
144+
impl Drop for RustNetDummy {
145+
fn drop(&mut self) {
146+
// TODO: remove unsafe somehow
147+
unsafe { dummy_rs_link_ops.unregister() };
148+
}
149+
}
150+
151+
struct DummyRsDev;
152+
153+
impl NetDeviceOps<Self> for DummyRsDev {
154+
kernel::declare_net_device_ops!(
155+
get_stats64,
156+
change_carrier,
157+
validate_addr,
158+
set_mac_addr,
159+
set_rx_mode
160+
);
161+
162+
fn init(dev: &mut NetDevice<Self>) -> Result {
163+
dev.set_new_pcpu_lstats()?;
164+
Ok(())
165+
}
166+
167+
fn uninit(dev: &mut NetDevice<Self>) {
168+
unsafe { dev.free_lstats() };
169+
}
170+
171+
fn start_xmit(skb: SkBuff, dev: &mut NetDevice<Self>) -> kernel::net::device::NetdevTX {
172+
let mut skb = skb;
173+
174+
dev.lstats_add(skb.len());
175+
176+
skb.tx_timestamp();
177+
drop(skb);
178+
179+
kernel::net::device::NetdevTX::TX_OK
180+
}
181+
182+
fn get_stats64(dev: &NetDevice<Self>, stats: &mut rtnl::RtnlLinkStats64) {
183+
stats.dev_read(dev);
184+
}
185+
186+
fn change_carrier(dev: &mut NetDevice<Self>, new_carrier: bool) -> Result {
187+
dev.carrier_set(new_carrier);
188+
189+
Ok(())
190+
}
191+
192+
fn validate_addr(dev: &NetDevice<Self>) -> Result {
193+
device::helpers::eth_validate_addr(dev)
194+
}
195+
196+
fn set_mac_addr(dev: &mut NetDevice<Self>, p: *mut kernel::c_types::c_void) -> Result {
197+
device::helpers::eth_mac_addr(dev, p)
198+
}
199+
200+
// [Someting about faking multicast](https://elixir.bootlin.com/linux/v5.12-rc4/source/drivers/net/dummy.c#L48).
201+
fn set_rx_mode(_dev: &mut NetDevice<Self>) {}
202+
}
203+
204+
impl NetDeviceAdapter for DummyRsDev {
205+
type Inner = Self;
206+
207+
type Ops = Self;
208+
209+
type EthOps = Self;
210+
211+
fn setup(dev: &mut NetDevice<Self>) {
212+
setup(dev);
213+
}
214+
}
215+
216+
impl EthToolOps<Self> for DummyRsDev {
217+
kernel::declare_eth_tool_ops!(get_drvinfo, get_ts_info);
218+
219+
fn get_drvinfo(_dev: &NetDevice<Self>, info: &mut ethtool::EthtoolDrvinfo) {
220+
// TODO: how to do this more efficient without unsafe?
221+
// FIXME: !!
222+
let info: &kernel::bindings::ethtool_drvinfo = info.get_internal();
223+
unsafe {
224+
kernel::bindings::strlcpy(
225+
&(info.driver) as *const _ as *mut i8,
226+
b"dummy_rs\0" as *const _ as *mut i8,
227+
32,
228+
);
229+
}
230+
}
231+
232+
fn get_ts_info(dev: &NetDevice<Self>, info: &mut ethtool::EthToolTsInfo) -> Result {
233+
kernel::net::ethtool::helpers::ethtool_op_get_ts_info(dev, info)
234+
}
235+
}

Diff for: rust/helpers.c

+32-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include <linux/highmem.h>
99
#include <linux/uio.h>
1010
#include <linux/errname.h>
11+
#include <linux/netdevice.h>
12+
#include <linux/etherdevice.h>
13+
#include <linux/rtnetlink.h>
1114

1215
void rust_helper_BUG(void)
1316
{
@@ -123,6 +126,34 @@ const char *rust_helper_errname(int err)
123126
return errname(err);
124127
}
125128

129+
void *rust_helper_netdev_priv(struct net_device *dev)
130+
{
131+
return netdev_priv(dev);
132+
}
133+
EXPORT_SYMBOL_GPL(rust_helper_netdev_priv);
134+
135+
void rust_helper_eth_hw_addr_random(struct net_device *dev)
136+
{
137+
eth_hw_addr_random(dev);
138+
}
139+
EXPORT_SYMBOL_GPL(rust_helper_eth_hw_addr_random);
140+
141+
int rust_helper_net_device_set_new_lstats(struct net_device *dev)
142+
{
143+
dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats);
144+
if (!dev->lstats)
145+
return -ENOMEM;
146+
147+
return 0;
148+
}
149+
EXPORT_SYMBOL_GPL(rust_helper_net_device_set_new_lstats);
150+
151+
void rust_helper_dev_lstats_add(struct net_device *dev, unsigned int len)
152+
{
153+
dev_lstats_add(dev, len);
154+
}
155+
EXPORT_SYMBOL_GPL(rust_helper_dev_lstats_add);
156+
126157
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
127158
* as the Rust usize type, so we can use it in contexts where Rust
128159
* expects a usize like slice (array) indices. usize is defined to be
@@ -143,4 +174,4 @@ static_assert(
143174
sizeof(size_t) == sizeof(uintptr_t) &&
144175
__alignof__(size_t) == __alignof__(uintptr_t),
145176
"Rust code expects C size_t to match Rust usize"
146-
);
177+
);

Diff for: rust/kernel/bindings_helper.h

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
#include <linux/cdev.h>
44
#include <linux/errname.h>
55
#include <linux/fs.h>
6+
#include <linux/netdevice.h>
7+
#include <linux/ethtool.h>
8+
#include <linux/etherdevice.h>
9+
#include <linux/netdev_features.h>
10+
#include <linux/rtnetlink.h>
11+
#include <net/rtnetlink.h>
612
#include <linux/module.h>
713
#include <linux/random.h>
814
#include <linux/slab.h>
@@ -21,3 +27,5 @@
2127
// `bindgen` gets confused at certain things
2228
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
2329
const gfp_t BINDINGS___GFP_ZERO = __GFP_ZERO;
30+
31+
const int BINDINGS_NLA_HDRLEN = NLA_HDRLEN;

Diff for: rust/kernel/error.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ impl Error {
6060
/// Bad file number.
6161
pub const EBADF: Self = Error(-(bindings::EBADF as i32));
6262

63+
/// Cannot assign requested address
64+
pub const EADDRNOTAVAIL: Self = Error(-(bindings::EADDRNOTAVAIL as i32));
65+
6366
/// Creates an [`Error`] from a kernel error code.
6467
///
6568
/// It is a bug to pass an out-of-range `errno`. `EINVAL` would
@@ -204,7 +207,7 @@ where
204207
#[macro_export]
205208
macro_rules! from_kernel_result {
206209
($($tt:tt)*) => {{
207-
$crate::error::from_kernel_result_helper((|| {
210+
$crate::from_kernel_result_helper((|| {
208211
$($tt)*
209212
})())
210213
}};

Diff for: rust/kernel/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mod error;
4646
pub mod file;
4747
pub mod file_operations;
4848
pub mod miscdev;
49+
pub mod net;
4950
pub mod pages;
5051
pub mod str;
5152
pub mod traits;
@@ -76,6 +77,9 @@ pub mod user_ptr;
7677
#[doc(hidden)]
7778
pub use build_error::build_error;
7879

80+
#[doc(hidden)]
81+
pub use crate::error::from_kernel_result_helper;
82+
7983
pub use crate::error::{Error, Result};
8084
pub use crate::types::{Mode, ScopeGuard};
8185

0 commit comments

Comments
 (0)