Skip to content

Commit

Permalink
ipsec: Add support of ipsec-interface, authby and DPD options
Browse files Browse the repository at this point in the history
Add support of these libreswan Ipsec options:
 * `ipsec-interface: yes|no|u32`
 * `authby: String`
 * `dpddelay: u64`
 * `dpdtimeout: u64`
 * `dpdaction: String`

Integration test case included but marked as OK to fail as
NetworkManager-libreswan supporting these options is not released yet.

Signed-off-by: Gris Ge <fge@redhat.com>
  • Loading branch information
cathay4t committed Dec 8, 2023
1 parent 1e76eeb commit 04d85f2
Show file tree
Hide file tree
Showing 11 changed files with 341 additions and 110 deletions.
20 changes: 19 additions & 1 deletion rust/src/lib/iface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
InfiniBandInterface, IpsecInterface, LinuxBridgeInterface,
LoopbackInterface, MacSecInterface, MacVlanInterface, MacVtapInterface,
NmstateError, OvsBridgeInterface, OvsInterface, VlanInterface,
VrfInterface, VxlanInterface,
VrfInterface, VxlanInterface, XfrmInterface,
};

use crate::state::merge_json_value;
Expand Down Expand Up @@ -69,6 +69,8 @@ pub enum InterfaceType {
MacSec,
/// Ipsec connection.
Ipsec,
/// Linux Xfrm kernel interface
Xfrm,
/// Unknown interface.
Unknown,
/// Reserved for future use.
Expand Down Expand Up @@ -102,6 +104,7 @@ impl From<&str> for InterfaceType {
"macsec" => InterfaceType::MacSec,
"ipsec" => InterfaceType::Ipsec,
"unknown" => InterfaceType::Unknown,
"xfrm" => InterfaceType::Xfrm,
_ => InterfaceType::Other(s.to_string()),
}
}
Expand Down Expand Up @@ -131,6 +134,7 @@ impl std::fmt::Display for InterfaceType {
InterfaceType::Tun => "tun",
InterfaceType::MacSec => "macsec",
InterfaceType::Ipsec => "ipsec",
InterfaceType::Xfrm => "xfrm",
InterfaceType::Other(ref s) => s,
}
)
Expand Down Expand Up @@ -309,6 +313,8 @@ pub enum Interface {
MacSec(MacSecInterface),
/// Ipsec connection
Ipsec(IpsecInterface),
/// Linux xfrm interface
Xfrm(XfrmInterface),
}

impl<'de> Deserialize<'de> for Interface {
Expand Down Expand Up @@ -420,6 +426,11 @@ impl<'de> Deserialize<'de> for Interface {
.map_err(serde::de::Error::custom)?;
Ok(Interface::Ipsec(inner))
}
Some(InterfaceType::Xfrm) => {
let inner = XfrmInterface::deserialize(v)
.map_err(serde::de::Error::custom)?;
Ok(Interface::Xfrm(inner))
}
Some(iface_type) => {
log::warn!("Unsupported interface type {}", iface_type);
let inner = UnknownInterface::deserialize(v)
Expand Down Expand Up @@ -535,6 +546,11 @@ impl Interface {
new_iface.base = iface.base.clone_name_type_only();
Self::Ipsec(new_iface)
}
Self::Xfrm(iface) => {
let mut new_iface = XfrmInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Self::Xfrm(new_iface)
}
Self::Unknown(iface) => {
let mut new_iface = UnknownInterface::new();
new_iface.base = iface.base.clone_name_type_only();
Expand Down Expand Up @@ -631,6 +647,7 @@ impl Interface {
Self::Loopback(iface) => &iface.base,
Self::MacSec(iface) => &iface.base,
Self::Ipsec(iface) => &iface.base,
Self::Xfrm(iface) => &iface.base,
Self::Unknown(iface) => &iface.base,
}
}
Expand All @@ -652,6 +669,7 @@ impl Interface {
Self::Loopback(iface) => &mut iface.base,
Self::MacSec(iface) => &mut iface.base,
Self::Ipsec(iface) => &mut iface.base,
Self::Xfrm(iface) => &mut iface.base,
Self::Unknown(iface) => &mut iface.base,
}
}
Expand Down
71 changes: 70 additions & 1 deletion rust/src/lib/ifaces/ipsec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0

use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};

use crate::{BaseInterface, InterfaceType, NetworkState};

Expand Down Expand Up @@ -89,10 +89,79 @@ pub struct LibreswanConfig {
pub ike: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub esp: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
default,
deserialize_with = "crate::deserializer::option_u64_or_string"
)]
pub dpddelay: Option<u64>,
#[serde(
skip_serializing_if = "Option::is_none",
default,
deserialize_with = "crate::deserializer::option_u64_or_string"
)]
pub dpdtimeout: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dpdaction: Option<String>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "ipsec-interface",
default,
deserialize_with = "parse_ipsec_iface"
)]
pub ipsec_interface: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub authby: Option<String>,
}

impl LibreswanConfig {
pub fn new() -> Self {
Self::default()
}
}

fn parse_ipsec_iface<'de, D>(
deserializer: D,
) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let v = serde_json::Value::deserialize(deserializer)?;

match v {
serde_json::Value::Bool(b) => {
if b {
Ok(Some("yes".to_string()))
} else {
Ok(Some("no".to_string()))
}
}
serde_json::Value::Number(d) => {
if let Some(d) = d.as_u64() {
Ok(Some(d.to_string()))
} else {
Err(serde::de::Error::custom(
"Invalid ipsec-interface value, should be \
unsigned integer or yes or no",
))
}
}
serde_json::Value::String(s) => match s.as_str() {
"yes" | "no" => Ok(Some(s)),
_ => {
if s.parse::<u32>().is_ok() {
Ok(Some(s))
} else {
Err(serde::de::Error::custom(
"Invalid ipsec-interface value, should be \
unsigned integer or yes or no",
))
}
}
},
_ => Err(serde::de::Error::custom(
"Invalid ipsec-interface value, should be \
unsigned integer or yes or no",
)),
}
}
44 changes: 24 additions & 20 deletions rust/src/lib/ifaces/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod ipsec;
mod loopback;
mod vrf;
mod vxlan;
mod xfrm;
// The pub(crate) is only for unit test
mod infiniband;
pub(crate) mod inter_ifaces_controller;
Expand All @@ -20,42 +21,45 @@ mod ovs;
mod sriov;
mod vlan;

pub use base::*;
pub use bond::{
pub use self::base::*;
pub use self::bond::{
BondAdSelect, BondAllPortsActive, BondArpAllTargets, BondArpValidate,
BondConfig, BondFailOverMac, BondInterface, BondLacpRate, BondMode,
BondOptions, BondPortConfig, BondPrimaryReselect, BondXmitHashPolicy,
};
pub use bridge_vlan::{
pub use self::bridge_vlan::{
BridgePortTrunkTag, BridgePortVlanConfig, BridgePortVlanMode,
BridgePortVlanRange,
};
pub use dummy::DummyInterface;
pub use ethernet::{
pub use self::dummy::DummyInterface;
pub use self::ethernet::{
EthernetConfig, EthernetDuplex, EthernetInterface, VethConfig,
};
pub use ethtool::{
pub use self::ethtool::{
EthtoolCoalesceConfig, EthtoolConfig, EthtoolFeatureConfig,
EthtoolPauseConfig, EthtoolRingConfig,
};
pub use infiniband::{InfiniBandConfig, InfiniBandInterface, InfiniBandMode};
pub(crate) use inter_ifaces::MergedInterfaces;
pub use inter_ifaces::*;
pub use ipsec::{IpsecInterface, LibreswanConfig};
pub use linux_bridge::{
pub use self::infiniband::{
InfiniBandConfig, InfiniBandInterface, InfiniBandMode,
};
pub(crate) use self::inter_ifaces::MergedInterfaces;
pub use self::inter_ifaces::*;
pub use self::ipsec::{IpsecInterface, LibreswanConfig};
pub use self::linux_bridge::{
LinuxBridgeConfig, LinuxBridgeInterface, LinuxBridgeMulticastRouterType,
LinuxBridgeOptions, LinuxBridgePortConfig, LinuxBridgeStpOptions,
};
pub use loopback::LoopbackInterface;
pub use mac_vlan::{MacVlanConfig, MacVlanInterface, MacVlanMode};
pub use mac_vtap::{MacVtapConfig, MacVtapInterface, MacVtapMode};
pub use macsec::{MacSecConfig, MacSecInterface, MacSecValidate};
pub use ovs::{
pub use self::loopback::LoopbackInterface;
pub use self::mac_vlan::{MacVlanConfig, MacVlanInterface, MacVlanMode};
pub use self::mac_vtap::{MacVtapConfig, MacVtapInterface, MacVtapMode};
pub use self::macsec::{MacSecConfig, MacSecInterface, MacSecValidate};
pub use self::ovs::{
OvsBridgeBondConfig, OvsBridgeBondMode, OvsBridgeBondPortConfig,
OvsBridgeConfig, OvsBridgeInterface, OvsBridgeOptions, OvsBridgePortConfig,
OvsBridgeStpOptions, OvsDpdkConfig, OvsInterface, OvsPatchConfig,
};
pub use sriov::{SrIovConfig, SrIovVfConfig};
pub use vlan::{VlanConfig, VlanInterface, VlanProtocol};
pub use vrf::{VrfConfig, VrfInterface};
pub use vxlan::{VxlanConfig, VxlanInterface};
pub use self::sriov::{SrIovConfig, SrIovVfConfig};
pub use self::vlan::{VlanConfig, VlanInterface, VlanProtocol};
pub use self::vrf::{VrfConfig, VrfInterface};
pub use self::vxlan::{VxlanConfig, VxlanInterface};
pub use self::xfrm::XfrmInterface;
26 changes: 26 additions & 0 deletions rust/src/lib/ifaces/xfrm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0

use serde::{Deserialize, Serialize};

use crate::{BaseInterface, InterfaceType};

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct XfrmInterface {
#[serde(flatten)]
pub base: BaseInterface,
}

impl Default for XfrmInterface {
fn default() -> Self {
let mut base = BaseInterface::new();
base.iface_type = InterfaceType::Xfrm;
Self { base }
}
}

impl XfrmInterface {
pub fn new() -> Self {
Self::default()
}
}
1 change: 1 addition & 0 deletions rust/src/lib/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ pub use crate::ifaces::{
OvsBridgeStpOptions, OvsDpdkConfig, OvsInterface, OvsPatchConfig,
SrIovConfig, SrIovVfConfig, VethConfig, VlanConfig, VlanInterface,
VlanProtocol, VrfConfig, VrfInterface, VxlanConfig, VxlanInterface,
XfrmInterface,
};
pub use crate::ip::{
AddressFamily, Dhcpv4ClientId, Dhcpv6Duid, InterfaceIpAddr, InterfaceIpv4,
Expand Down
1 change: 1 addition & 0 deletions rust/src/lib/nispor/base_iface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ fn np_iface_type_to_nmstate(
nispor::IfaceType::Vxlan => InterfaceType::Vxlan,
nispor::IfaceType::Ipoib => InterfaceType::InfiniBand,
nispor::IfaceType::Tun => InterfaceType::Tun,
nispor::IfaceType::Other(v) if v == "xfrm" => InterfaceType::Xfrm,
_ => InterfaceType::Other(format!("{np_iface_type:?}")),
}
}
Expand Down
7 changes: 6 additions & 1 deletion rust/src/lib/nispor/show.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
vxlan::np_vxlan_to_nmstate,
},
DummyInterface, Interface, InterfaceType, Interfaces, LoopbackInterface,
NetworkState, NmstateError, OvsInterface, UnknownInterface,
NetworkState, NmstateError, OvsInterface, UnknownInterface, XfrmInterface,
};

pub(crate) fn nispor_retrieve(
Expand Down Expand Up @@ -130,6 +130,11 @@ pub(crate) fn nispor_retrieve(
InterfaceType::MacSec => {
Interface::MacSec(np_macsec_to_nmstate(np_iface, base_iface))
}
InterfaceType::Xfrm => {
let mut iface = XfrmInterface::new();
iface.base = base_iface;
Interface::Xfrm(iface)
}
_ => {
log::info!(
"Got unsupported interface {} type {:?}",
Expand Down
7 changes: 7 additions & 0 deletions rust/src/lib/nm/query_apply/vpn.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0

use std::collections::HashMap;
use std::str::FromStr;

use crate::{
Interface, InterfaceType, IpsecInterface, LibreswanConfig, NmstateError,
Expand Down Expand Up @@ -59,6 +60,12 @@ fn get_libreswan_conf(nm_set_vpn: &NmSettingVpn) -> LibreswanConfig {
ret.salifetime = data.get("salifetime").cloned();
ret.ike = data.get("ike").cloned();
ret.esp = data.get("esp").cloned();
ret.dpddelay = data.get("dpddelay").and_then(|d| u64::from_str(d).ok());
ret.dpdtimeout =
data.get("dpdtimeout").and_then(|d| u64::from_str(d).ok());
ret.dpdaction = data.get("dpdaction").cloned();
ret.ipsec_interface = data.get("ipsec-interface").cloned();
ret.authby = data.get("authby").cloned();
}
if let Some(secrets) = nm_set_vpn.secrets.as_ref() {
ret.psk = secrets.get("pskvalue").cloned();
Expand Down
15 changes: 15 additions & 0 deletions rust/src/lib/nm/settings/vpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ pub(crate) fn gen_nm_ipsec_vpn_setting(
if let Some(v) = conf.esp.as_deref() {
vpn_data.insert("esp".into(), v.to_string());
}
if let Some(v) = conf.dpddelay {
vpn_data.insert("dpddelay".into(), v.to_string());
}
if let Some(v) = conf.dpdtimeout {
vpn_data.insert("dpdtimeout".into(), v.to_string());
}
if let Some(v) = conf.dpdaction.as_deref() {
vpn_data.insert("dpdaction".into(), v.to_string());
}
if let Some(v) = conf.ipsec_interface.as_deref() {
vpn_data.insert("ipsec-interface".into(), v.to_string());
}
if let Some(v) = conf.authby.as_deref() {
vpn_data.insert("authby".into(), v.to_string());
}

let mut nm_vpn_set = NmSettingVpn::default();
nm_vpn_set.data = Some(vpn_data);
Expand Down
3 changes: 2 additions & 1 deletion rust/src/lib/query_apply/iface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ impl Interface {
}

impl InterfaceType {
pub(crate) const SUPPORTED_LIST: [InterfaceType; 16] = [
pub(crate) const SUPPORTED_LIST: [InterfaceType; 17] = [
InterfaceType::Bond,
InterfaceType::LinuxBridge,
InterfaceType::Dummy,
Expand All @@ -251,5 +251,6 @@ impl InterfaceType {
InterfaceType::MacSec,
InterfaceType::Vrf,
InterfaceType::Ipsec,
InterfaceType::Xfrm,
];
}

0 comments on commit 04d85f2

Please sign in to comment.