Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable network config generation via netdog #2066

Merged
merged 2 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/os/generate-network-config.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[Unit]
Description=Generate network configuration
# Block manual interactions with this service, since it could leave the system in an
# unexpected state
RefuseManualStart=true
RefuseManualStop=true

[Service]
Type=oneshot
ExecStart=/usr/bin/netdog generate-net-config
RemainAfterExit=true
StandardError=journal+console

[Install]
RequiredBy=network-pre.target
4 changes: 3 additions & 1 deletion packages/os/os.spec
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ Source114: [email protected]
Source115: link-kernel-modules.service
Source116: load-kernel-modules.service
Source117: cfsignal.service
Source118: generate-network-config.service

# 2xx sources: tmpfilesd configs
Source200: migration-tmpfiles.conf
Expand Down Expand Up @@ -444,7 +445,7 @@ install -d %{buildroot}%{_cross_unitdir}
install -p -m 0644 \
%{S:100} %{S:101} %{S:102} %{S:103} %{S:105} \
%{S:106} %{S:107} %{S:110} %{S:111} %{S:112} \
%{S:113} %{S:114} \
%{S:113} %{S:114} %{S:118} \
%if %{_is_vendor_variant}
%{S:115} %{S:116} \
%endif
Expand Down Expand Up @@ -487,6 +488,7 @@ install -p -m 0644 %{S:300} %{buildroot}%{_cross_udevrulesdir}/80-ephemeral-stor
%files -n %{_cross_os}netdog
%{_cross_bindir}/netdog
%{_cross_tmpfilesdir}/netdog.conf
%{_cross_unitdir}/generate-network-config.service

%files -n %{_cross_os}corndog
%{_cross_bindir}/corndog
Expand Down
28 changes: 0 additions & 28 deletions packages/release/eth0.xml

This file was deleted.

1 change: 0 additions & 1 deletion packages/release/release-tmpfiles.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
C /etc/nsswitch.conf - - - -
C /etc/wicked/ifconfig/eth0.xml - - - -
d /var/log/kdump 0700 root root -
d /sys/fs/cgroup/cpuset/runtime.slice 0755 root root -
d /sys/fs/cgroup/hugetlb/runtime.slice 0755 root root -
Expand Down
5 changes: 0 additions & 5 deletions packages/release/release.spec
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ Source201: proxy-env
Source202: hostname-env
Source203: hosts.template

Source1000: eth0.xml
Source1001: multi-user.target
Source1002: configured.target
Source1003: preconfigured.target
Expand Down Expand Up @@ -106,9 +105,6 @@ Requires: %{_cross_os}wicked
install -d %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}
install -p -m 0644 %{S:11} %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}

install -d %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig
install -p -m 0644 %{S:1000} %{buildroot}%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig

install -d %{buildroot}%{_cross_libdir}/repart.d
install -p -m 0644 %{S:96} %{buildroot}%{_cross_libdir}/repart.d/80-local.conf

Expand Down Expand Up @@ -172,7 +168,6 @@ ln -s preconfigured.target %{buildroot}%{_cross_unitdir}/default.target

%files
%{_cross_factorydir}%{_cross_sysconfdir}/nsswitch.conf
%{_cross_factorydir}%{_cross_sysconfdir}/wicked/ifconfig/eth0.xml
%{_cross_sysctldir}/80-release.conf
%{_cross_tmpfilesdir}/release.conf
%{_cross_libdir}/os-release
Expand Down
1 change: 1 addition & 0 deletions packages/wicked/wicked-tmpfiles.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ C /etc/wicked/client.xml - - - -
C /etc/wicked/common.xml - - - -
C /etc/wicked/nanny.xml - - - -
C /etc/wicked/server.xml - - - -
d /etc/wicked/ifconfig 0700 root root -

d /var/lib/wicked 0700 root root -
Z /var/lib/wicked 0700 root root -
5 changes: 5 additions & 0 deletions sources/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions sources/api/netdog/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ exclude = ["README.md"]
argh = "0.1.4"
dns-lookup = "1.0"
ipnet = { version = "2.0", features = ["serde"] }
indexmap = { version = "1.8", features = ["serde"]}
envy = "0.4"
lazy_static = "1.2"
rand = { version = "0.8", default-features = false, features = ["std", "std_rng"] }
regex = "1.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1"
serde_plain = "1.0"
serde-xml-rs = "0.5"
snafu = "0.7"
toml = { version = "0.5", features = ["preserve_order"] }

[build-dependencies]
cargo-readme = "3.1"
10 changes: 10 additions & 0 deletions sources/api/netdog/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ It contains two subcommands meant for use as settings generators:

The subcommand `set-hostname` sets the hostname for the system.

The subcommand `generate-net-config` generates the network interface configuration for the host. If
a `net.toml` file exists in `/var/lib/bottlerocket`, it is used to generate the configuration. If
`net.toml` doesn't exist, the kernel command line `/proc/cmdline` is checked for the prefix
`netdog.default-interface`. If an interface is defined with that prefix, it is used to generate an
interface configuration. A single default interface may be defined on the kernel command line with
the format: `netdog.default-interface=interface-name:option1,option2`. "interface-name" is the
name of the interface, and valid options are "dhcp4" and "dhcp6". A "?" may be added to the option
to signify that the lease for the protocol is optional and the system shouldn't wait for it. A
valid example: `netdog.default-interface=eno1:dhcp4,dhcp6?`.

## Colophon

This text was generated using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/main.rs`.
148 changes: 148 additions & 0 deletions sources/api/netdog/src/interface_name.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//! The interface_name module contains the definition of a valid network interface name and the
//! code to support creation of the structure from string.
//!
//! A valid network interface name is defined by the criteria in the linux kernel:
//! https://elixir.bootlin.com/linux/v5.10.102/source/net/core/dev.c#L1138
use serde::{Deserialize, Serialize, Serializer};
use snafu::ensure;
use std::convert::TryFrom;
use std::ops::Deref;

/// InterfaceName can only be created from a string that contains a valid network interface name.
/// Validation is handled in the `TryFrom` implementation below.
#[derive(Debug, Eq, PartialEq, Hash, Deserialize)]
#[serde(try_from = "&str")]
pub(crate) struct InterfaceName {
inner: String,
}

impl TryFrom<&str> for InterfaceName {
type Error = error::Error;

fn try_from(input: &str) -> Result<Self> {
// Rust does not treat all Unicode line terminators as starting a new line, so we check for
// specific characters here, rather than just counting from lines().
// https://en.wikipedia.org/wiki/Newline#Unicode
let line_terminators = [
'\n', // newline (0A)
'\r', // carriage return (0D)
'\u{000B}', // vertical tab
'\u{000C}', // form feed
'\u{0085}', // next line
'\u{2028}', // line separator
'\u{2029}', // paragraph separator
];

ensure!(
!input.contains(&line_terminators[..]),
error::InvalidNetworkDeviceNameSnafu {
input,
msg: "contains line terminators"
}
);

// The length for an interface name is defined here:
// https://elixir.bootlin.com/linux/v5.10.102/source/include/uapi/linux/if.h#L33
// The constant definition (16) is a little misleading as the check for it ensures that the
// name is NOT equal to 16. A name must be 1-15 characters.
ensure!(
!input.is_empty() && input.len() <= 15,
error::InvalidNetworkDeviceNameSnafu {
input,
msg: "invalid length, must be 1 to 15 characters long"
}
);

ensure!(
!input.contains('.') && !input.contains('/') && !input.contains(char::is_whitespace),
error::InvalidNetworkDeviceNameSnafu {
input,
msg: "contains invalid characters"
}
);

Ok(Self {
inner: input.to_string(),
})
}
}

impl TryFrom<String> for InterfaceName {
type Error = error::Error;

fn try_from(input: String) -> Result<Self> {
Self::try_from(input.as_ref())
}
}

impl Deref for InterfaceName {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.inner
}
}

impl Serialize for InterfaceName {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.inner)
}
}

mod error {
use snafu::Snafu;

#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub(crate) enum Error {
#[snafu(display("Invalid network device name '{}': {}", input, msg))]
InvalidNetworkDeviceName { input: String, msg: String },
}
}

pub(crate) use error::Error;
type Result<T> = std::result::Result<T, error::Error>;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn invalid_interface_name() {
let bad_str = [
&std::iter::repeat("a").take(16).collect::<String>(),
"",
".",
"..",
"f/eno1",
"eno 1",
"eno\n1",
"\n",
"\r",
"\u{000B}",
"\u{000C}",
"\u{0085}",
"\u{2028}",
"\u{2029}",
];
for bad in bad_str {
assert!(InterfaceName::try_from(bad).is_err())
}
}

#[test]
fn valid_interface_name() {
let ok_str = [
&std::iter::repeat("a").take(15).collect::<String>(),
"eno1",
"eth0",
"enp5s0",
"enx0eb36944b633",
];
for ok in ok_str {
assert!(InterfaceName::try_from(ok).is_ok())
}
}
}
Loading