devices: support VTI tunnels
A VTI tunnel is similar to a IPIP one, but it allows adding a fwmark to packets and supports IPsec encapsulation.
This commit is contained in:
@@ -88,6 +88,14 @@
|
|||||||
-->
|
-->
|
||||||
<property name="FlowLabel" type="u" access="read"/>
|
<property name="FlowLabel" type="u" access="read"/>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
FwMark:
|
||||||
|
|
||||||
|
The fwmark value to assign to tunnel packets. This property applies only to
|
||||||
|
VTI tunnels.
|
||||||
|
-->
|
||||||
|
<property name="FwMark" type="u" access="read"/>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Flags:
|
Flags:
|
||||||
|
|
||||||
|
@@ -39,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMDeviceIPTunnel,
|
|||||||
PROP_OUTPUT_KEY,
|
PROP_OUTPUT_KEY,
|
||||||
PROP_ENCAPSULATION_LIMIT,
|
PROP_ENCAPSULATION_LIMIT,
|
||||||
PROP_FLOW_LABEL,
|
PROP_FLOW_LABEL,
|
||||||
|
PROP_FWMARK,
|
||||||
PROP_FLAGS, );
|
PROP_FLAGS, );
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -53,6 +54,7 @@ typedef struct {
|
|||||||
char *output_key;
|
char *output_key;
|
||||||
guint8 encap_limit;
|
guint8 encap_limit;
|
||||||
guint32 flow_label;
|
guint32 flow_label;
|
||||||
|
guint32 fwmark;
|
||||||
NMIPTunnelFlags flags;
|
NMIPTunnelFlags flags;
|
||||||
} NMDeviceIPTunnelPrivate;
|
} NMDeviceIPTunnelPrivate;
|
||||||
|
|
||||||
@@ -162,6 +164,7 @@ update_properties_from_ifindex(NMDevice *device, int ifindex)
|
|||||||
guint8 encap_limit = 0;
|
guint8 encap_limit = 0;
|
||||||
gboolean pmtud = FALSE;
|
gboolean pmtud = FALSE;
|
||||||
guint32 flow_label = 0;
|
guint32 flow_label = 0;
|
||||||
|
guint32 fwmark = 0;
|
||||||
NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE;
|
NMIPTunnelFlags flags = NM_IP_TUNNEL_FLAG_NONE;
|
||||||
gs_free char *input_key = NULL;
|
gs_free char *input_key = NULL;
|
||||||
gs_free char *output_key = NULL;
|
gs_free char *output_key = NULL;
|
||||||
@@ -277,6 +280,23 @@ clear:
|
|||||||
if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY))
|
if (NM_FLAGS_HAS(lnk->output_flags, NM_GRE_KEY))
|
||||||
output_key = g_strdup_printf("%u", lnk->output_key);
|
output_key = g_strdup_printf("%u", lnk->output_key);
|
||||||
}
|
}
|
||||||
|
} else if (priv->mode == NM_IP_TUNNEL_MODE_VTI) {
|
||||||
|
const NMPlatformLnkVti *lnk;
|
||||||
|
|
||||||
|
lnk = nm_platform_link_get_lnk_vti(nm_device_get_platform(device), ifindex, NULL);
|
||||||
|
if (!lnk) {
|
||||||
|
_LOGW(LOGD_PLATFORM, "could not read %s properties", "vti");
|
||||||
|
goto clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent_ifindex = lnk->parent_ifindex;
|
||||||
|
local.addr4 = lnk->local;
|
||||||
|
remote.addr4 = lnk->remote;
|
||||||
|
fwmark = lnk->fwmark;
|
||||||
|
if (lnk->ikey)
|
||||||
|
input_key = g_strdup_printf("%u", lnk->ikey);
|
||||||
|
if (lnk->okey)
|
||||||
|
input_key = g_strdup_printf("%u", lnk->okey);
|
||||||
} else
|
} else
|
||||||
g_return_if_reached();
|
g_return_if_reached();
|
||||||
|
|
||||||
@@ -325,6 +345,11 @@ out:
|
|||||||
_notify(self, PROP_OUTPUT_KEY);
|
_notify(self, PROP_OUTPUT_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->fwmark != fwmark) {
|
||||||
|
priv->fwmark = fwmark;
|
||||||
|
_notify(self, PROP_FWMARK);
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->flags != flags) {
|
if (priv->flags != flags) {
|
||||||
priv->flags = flags;
|
priv->flags = flags;
|
||||||
_notify(self, PROP_FLAGS);
|
_notify(self, PROP_FLAGS);
|
||||||
@@ -429,11 +454,16 @@ update_connection(NMDevice *device, NMConnection *connection)
|
|||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel) != priv->fwmark) {
|
||||||
|
g_object_set(G_OBJECT(s_ip_tunnel), NM_SETTING_IP_TUNNEL_FWMARK, priv->fwmark, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (NM_IN_SET(priv->mode,
|
if (NM_IN_SET(priv->mode,
|
||||||
NM_IP_TUNNEL_MODE_GRE,
|
NM_IP_TUNNEL_MODE_GRE,
|
||||||
NM_IP_TUNNEL_MODE_GRETAP,
|
NM_IP_TUNNEL_MODE_GRETAP,
|
||||||
NM_IP_TUNNEL_MODE_IP6GRE,
|
NM_IP_TUNNEL_MODE_IP6GRE,
|
||||||
NM_IP_TUNNEL_MODE_IP6GRETAP)) {
|
NM_IP_TUNNEL_MODE_IP6GRETAP,
|
||||||
|
NM_IP_TUNNEL_MODE_VTI)) {
|
||||||
if (g_strcmp0(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), priv->input_key)) {
|
if (g_strcmp0(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel), priv->input_key)) {
|
||||||
g_object_set(G_OBJECT(s_ip_tunnel),
|
g_object_set(G_OBJECT(s_ip_tunnel),
|
||||||
NM_SETTING_IP_TUNNEL_INPUT_KEY,
|
NM_SETTING_IP_TUNNEL_INPUT_KEY,
|
||||||
@@ -455,6 +485,7 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
|
|||||||
NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL(device);
|
NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL(device);
|
||||||
NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self);
|
NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE(self);
|
||||||
NMSettingIPTunnel *s_ip_tunnel;
|
NMSettingIPTunnel *s_ip_tunnel;
|
||||||
|
NMIPTunnelMode mode;
|
||||||
const char *parent;
|
const char *parent;
|
||||||
|
|
||||||
if (!NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class)
|
if (!NM_DEVICE_CLASS(nm_device_ip_tunnel_parent_class)
|
||||||
@@ -462,8 +493,9 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection);
|
s_ip_tunnel = nm_connection_get_setting_ip_tunnel(connection);
|
||||||
|
mode = nm_setting_ip_tunnel_get_mode(s_ip_tunnel);
|
||||||
|
|
||||||
if (nm_setting_ip_tunnel_get_mode(s_ip_tunnel) != priv->mode) {
|
if (mode != priv->mode) {
|
||||||
nm_utils_error_set_literal(error,
|
nm_utils_error_set_literal(error,
|
||||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||||
"incompatible IP tunnel mode");
|
"incompatible IP tunnel mode");
|
||||||
@@ -498,14 +530,16 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) {
|
if (mode != NM_IP_TUNNEL_MODE_VTI
|
||||||
|
&& nm_setting_ip_tunnel_get_ttl(s_ip_tunnel) != priv->ttl) {
|
||||||
nm_utils_error_set_literal(error,
|
nm_utils_error_set_literal(error,
|
||||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||||
"TTL of IP tunnel mismatches");
|
"TTL of IP tunnel mismatches");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) {
|
if (mode != NM_IP_TUNNEL_MODE_VTI
|
||||||
|
&& nm_setting_ip_tunnel_get_tos(s_ip_tunnel) != priv->tos) {
|
||||||
nm_utils_error_set_literal(error,
|
nm_utils_error_set_literal(error,
|
||||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||||
"TOS of IP tunnel mismatches");
|
"TOS of IP tunnel mismatches");
|
||||||
@@ -513,11 +547,14 @@ check_connection_compatible(NMDevice *device, NMConnection *connection, GError *
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (priv->addr_family == AF_INET) {
|
if (priv->addr_family == AF_INET) {
|
||||||
if (nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel)
|
if (mode != NM_IP_TUNNEL_MODE_VTI
|
||||||
|
&& nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel)
|
||||||
!= priv->path_mtu_discovery) {
|
!= priv->path_mtu_discovery) {
|
||||||
nm_utils_error_set_literal(error,
|
nm_utils_error_set(error,
|
||||||
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY,
|
||||||
"MTU discovery setting of IP tunnel mismatches");
|
"MTU discovery setting of IP tunnel mismatches: %d vs %d",
|
||||||
|
nm_setting_ip_tunnel_get_path_mtu_discovery(s_ip_tunnel),
|
||||||
|
priv->path_mtu_discovery);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -567,6 +604,8 @@ platform_link_to_tunnel_mode(const NMPlatformLink *link)
|
|||||||
return NM_IP_TUNNEL_MODE_IPIP;
|
return NM_IP_TUNNEL_MODE_IPIP;
|
||||||
case NM_LINK_TYPE_SIT:
|
case NM_LINK_TYPE_SIT:
|
||||||
return NM_IP_TUNNEL_MODE_SIT;
|
return NM_IP_TUNNEL_MODE_SIT;
|
||||||
|
case NM_LINK_TYPE_VTI:
|
||||||
|
return NM_IP_TUNNEL_MODE_VTI;
|
||||||
default:
|
default:
|
||||||
g_return_val_if_reached(NM_IP_TUNNEL_MODE_UNKNOWN);
|
g_return_val_if_reached(NM_IP_TUNNEL_MODE_UNKNOWN);
|
||||||
}
|
}
|
||||||
@@ -592,6 +631,7 @@ tunnel_mode_to_link_type(NMIPTunnelMode tunnel_mode)
|
|||||||
case NM_IP_TUNNEL_MODE_SIT:
|
case NM_IP_TUNNEL_MODE_SIT:
|
||||||
return NM_LINK_TYPE_SIT;
|
return NM_LINK_TYPE_SIT;
|
||||||
case NM_IP_TUNNEL_MODE_VTI:
|
case NM_IP_TUNNEL_MODE_VTI:
|
||||||
|
return NM_LINK_TYPE_VTI;
|
||||||
case NM_IP_TUNNEL_MODE_VTI6:
|
case NM_IP_TUNNEL_MODE_VTI6:
|
||||||
case NM_IP_TUNNEL_MODE_ISATAP:
|
case NM_IP_TUNNEL_MODE_ISATAP:
|
||||||
return NM_LINK_TYPE_UNKNOWN;
|
return NM_LINK_TYPE_UNKNOWN;
|
||||||
@@ -616,6 +656,7 @@ create_and_realize(NMDevice *device,
|
|||||||
NMPlatformLnkSit lnk_sit = {};
|
NMPlatformLnkSit lnk_sit = {};
|
||||||
NMPlatformLnkIpIp lnk_ipip = {};
|
NMPlatformLnkIpIp lnk_ipip = {};
|
||||||
NMPlatformLnkIp6Tnl lnk_ip6tnl = {};
|
NMPlatformLnkIp6Tnl lnk_ip6tnl = {};
|
||||||
|
NMPlatformLnkVti lnk_vti = {};
|
||||||
const char *str;
|
const char *str;
|
||||||
gint64 val;
|
gint64 val;
|
||||||
NMIPTunnelMode mode;
|
NMIPTunnelMode mode;
|
||||||
@@ -833,6 +874,43 @@ create_and_realize(NMDevice *device,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NM_IP_TUNNEL_MODE_VTI:
|
||||||
|
if (parent)
|
||||||
|
lnk_vti.parent_ifindex = nm_device_get_ifindex(parent);
|
||||||
|
|
||||||
|
str = nm_setting_ip_tunnel_get_local(s_ip_tunnel);
|
||||||
|
if (str)
|
||||||
|
inet_pton(AF_INET, str, &lnk_vti.local);
|
||||||
|
|
||||||
|
str = nm_setting_ip_tunnel_get_remote(s_ip_tunnel);
|
||||||
|
nm_assert(str);
|
||||||
|
inet_pton(AF_INET, str, &lnk_vti.remote);
|
||||||
|
|
||||||
|
lnk_vti.ikey = _nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_input_key(s_ip_tunnel),
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
G_MAXUINT32,
|
||||||
|
0);
|
||||||
|
lnk_vti.okey =
|
||||||
|
_nm_utils_ascii_str_to_int64(nm_setting_ip_tunnel_get_output_key(s_ip_tunnel),
|
||||||
|
10,
|
||||||
|
0,
|
||||||
|
G_MAXUINT32,
|
||||||
|
0);
|
||||||
|
lnk_vti.fwmark = nm_setting_ip_tunnel_get_fwmark(s_ip_tunnel);
|
||||||
|
|
||||||
|
r = nm_platform_link_vti_add(nm_device_get_platform(device), iface, &lnk_vti, out_plink);
|
||||||
|
if (r < 0) {
|
||||||
|
g_set_error(error,
|
||||||
|
NM_DEVICE_ERROR,
|
||||||
|
NM_DEVICE_ERROR_CREATION_FAILED,
|
||||||
|
"Failed to create VTI interface '%s' for '%s': %s",
|
||||||
|
iface,
|
||||||
|
nm_connection_get_id(connection),
|
||||||
|
nm_strerror(r));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_set_error(error,
|
g_set_error(error,
|
||||||
NM_DEVICE_ERROR,
|
NM_DEVICE_ERROR,
|
||||||
@@ -948,6 +1026,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||||||
case PROP_FLAGS:
|
case PROP_FLAGS:
|
||||||
g_value_set_uint(value, priv->flags);
|
g_value_set_uint(value, priv->flags);
|
||||||
break;
|
break;
|
||||||
|
case PROP_FWMARK:
|
||||||
|
g_value_set_uint(value, priv->fwmark);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -1032,6 +1113,9 @@ static const NMDBusInterfaceInfoExtended interface_info_device_ip_tunnel = {
|
|||||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FlowLabel",
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FlowLabel",
|
||||||
"u",
|
"u",
|
||||||
NM_DEVICE_IP_TUNNEL_FLOW_LABEL),
|
NM_DEVICE_IP_TUNNEL_FLOW_LABEL),
|
||||||
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("FwMark",
|
||||||
|
"u",
|
||||||
|
NM_DEVICE_IP_TUNNEL_FWMARK),
|
||||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags",
|
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Flags",
|
||||||
"u",
|
"u",
|
||||||
NM_DEVICE_IP_TUNNEL_FLAGS), ), ),
|
NM_DEVICE_IP_TUNNEL_FLAGS), ), ),
|
||||||
@@ -1059,7 +1143,8 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass)
|
|||||||
NM_LINK_TYPE_IP6GRE,
|
NM_LINK_TYPE_IP6GRE,
|
||||||
NM_LINK_TYPE_IP6GRETAP,
|
NM_LINK_TYPE_IP6GRETAP,
|
||||||
NM_LINK_TYPE_IPIP,
|
NM_LINK_TYPE_IPIP,
|
||||||
NM_LINK_TYPE_SIT);
|
NM_LINK_TYPE_SIT,
|
||||||
|
NM_LINK_TYPE_VTI);
|
||||||
|
|
||||||
device_class->act_stage1_prepare = act_stage1_prepare;
|
device_class->act_stage1_prepare = act_stage1_prepare;
|
||||||
device_class->link_changed = link_changed;
|
device_class->link_changed = link_changed;
|
||||||
@@ -1154,6 +1239,14 @@ nm_device_ip_tunnel_class_init(NMDeviceIPTunnelClass *klass)
|
|||||||
0,
|
0,
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
obj_properties[PROP_FWMARK] = g_param_spec_uint(NM_DEVICE_IP_TUNNEL_FWMARK,
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
G_MAXUINT32,
|
||||||
|
0,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1246,7 +1339,8 @@ NM_DEVICE_FACTORY_DEFINE_INTERNAL(
|
|||||||
NM_LINK_TYPE_IPIP,
|
NM_LINK_TYPE_IPIP,
|
||||||
NM_LINK_TYPE_IP6TNL,
|
NM_LINK_TYPE_IP6TNL,
|
||||||
NM_LINK_TYPE_IP6GRE,
|
NM_LINK_TYPE_IP6GRE,
|
||||||
NM_LINK_TYPE_IP6GRETAP)
|
NM_LINK_TYPE_IP6GRETAP,
|
||||||
|
NM_LINK_TYPE_VTI)
|
||||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME),
|
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(NM_SETTING_IP_TUNNEL_SETTING_NAME),
|
||||||
factory_class->create_device = create_device;
|
factory_class->create_device = create_device;
|
||||||
factory_class->get_connection_parent = get_connection_parent;
|
factory_class->get_connection_parent = get_connection_parent;
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
|
#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
|
||||||
#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label"
|
#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label"
|
||||||
#define NM_DEVICE_IP_TUNNEL_FLAGS "flags"
|
#define NM_DEVICE_IP_TUNNEL_FLAGS "flags"
|
||||||
|
#define NM_DEVICE_IP_TUNNEL_FWMARK "fwmark"
|
||||||
|
|
||||||
typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
|
typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel;
|
||||||
typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass;
|
typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass;
|
||||||
|
Reference in New Issue
Block a user