device/ip-tunnel: add support for IP6TNL tunnels

This commit is contained in:
Beniamino Galvani 2015-11-30 21:22:13 +01:00
parent 8d2aa13534
commit 8361fbf010
3 changed files with 143 additions and 5 deletions

View file

@ -59,6 +59,21 @@
</tp:docstring>
</property>
<property name="EncapsulationLimit" type="y" access="read">
<tp:docstring>
How many additional levels of encapsulation are permitted to
be prepended to packets. This property applies only to IPv6
tunnels.
</tp:docstring>
</property>
<property name="FlowLabel" type="u" access="read">
<tp:docstring>
The flow label to assign to tunnel packets. This property
applies only to IPv6 tunnels.
</tp:docstring>
</property>
<signal name="PropertiesChanged">
<arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
<tp:docstring>

View file

@ -57,6 +57,8 @@ typedef struct {
int addr_family;
char *input_key;
char *output_key;
guint8 encap_limit;
guint32 flow_label;
} NMDeviceIPTunnelPrivate;
enum {
@ -70,6 +72,8 @@ enum {
PROP_PATH_MTU_DISCOVERY,
PROP_INPUT_KEY,
PROP_OUTPUT_KEY,
PROP_ENCAPSULATION_LIMIT,
PROP_FLOW_LABEL,
LAST_PROP
};
@ -118,8 +122,9 @@ update_properties (NMDevice *device)
int parent_ifindex;
in_addr_t local4, remote4;
struct in6_addr local6, remote6;
guint8 ttl, tos;
gboolean pmtud;
guint8 ttl = 0, tos = 0, encap_limit = 0;
gboolean pmtud = FALSE;
guint32 flow_label = 0;
char *key;
if (priv->mode == NM_IP_TUNNEL_MODE_GRE) {
@ -197,6 +202,23 @@ update_properties (NMDevice *device)
ttl = lnk->ttl;
tos = lnk->tos;
pmtud = lnk->path_mtu_discovery;
} else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6
|| priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) {
const NMPlatformLnkIp6Tnl *lnk;
lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
if (!lnk) {
_LOGW (LOGD_HW, "could not read %s properties", "ip6tnl");
return;
}
parent_ifindex = lnk->parent_ifindex;
local6 = lnk->local;
remote6 = lnk->remote;
ttl = lnk->ttl;
tos = lnk->tclass;
encap_limit = lnk->encap_limit;
flow_label = lnk->flow_label;
} else
g_return_if_reached ();
@ -253,6 +275,16 @@ update_properties (NMDevice *device)
priv->path_mtu_discovery = pmtud;
g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY);
}
if (priv->encap_limit != encap_limit) {
priv->encap_limit = encap_limit;
g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT);
}
if (priv->flow_label != flow_label) {
priv->flow_label = flow_label;
g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL);
}
}
static void
@ -352,6 +384,20 @@ update_connection (NMDevice *device, NMConnection *connection)
NULL);
}
if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) {
g_object_set (G_OBJECT (s_ip_tunnel),
NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT,
priv->encap_limit,
NULL);
}
if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) {
g_object_set (G_OBJECT (s_ip_tunnel),
NM_SETTING_IP_TUNNEL_FLOW_LABEL,
priv->flow_label,
NULL);
}
if (priv->mode == NM_IP_TUNNEL_MODE_GRE || priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) {
if (g_strcmp0 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), priv->input_key)) {
g_object_set (G_OBJECT (s_ip_tunnel),
@ -452,8 +498,16 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos)
return FALSE;
if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery)
return FALSE;
if (priv->addr_family == AF_INET) {
if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery)
return FALSE;
} else {
if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit)
return FALSE;
if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label)
return FALSE;
}
return TRUE;
}
@ -461,9 +515,19 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
static NMIPTunnelMode
platform_link_to_tunnel_mode (const NMPlatformLink *link)
{
const NMPlatformLnkIp6Tnl *lnk;
switch (link->type) {
case NM_LINK_TYPE_GRE:
return NM_IP_TUNNEL_MODE_GRE;
case NM_LINK_TYPE_IP6TNL:
lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, link->ifindex, NULL);
if (lnk->proto == IPPROTO_IPIP)
return NM_IP_TUNNEL_MODE_IPIP6;
else if (lnk->proto == IPPROTO_IPV6)
return NM_IP_TUNNEL_MODE_IP6IP6;
else
return NM_IP_TUNNEL_MODE_UKNOWN;
case NM_LINK_TYPE_IPIP:
return NM_IP_TUNNEL_MODE_IPIP;
case NM_LINK_TYPE_SIT:
@ -485,7 +549,11 @@ constructed (GObject *object)
{
NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object);
priv->addr_family = AF_INET; /* at the moment we support only IPv4 tunnels */
if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6
|| priv->mode == NM_IP_TUNNEL_MODE_IP6IP6)
priv->addr_family = AF_INET6;
else
priv->addr_family = AF_INET;
G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->constructed (object);
}
@ -503,6 +571,7 @@ create_and_realize (NMDevice *device,
NMPlatformLnkGre lnk_gre = { };
NMPlatformLnkSit lnk_sit = { };
NMPlatformLnkIpIp lnk_ipip = { };
NMPlatformLnkIp6Tnl lnk_ip6tnl = { };
const char *str;
gint64 val;
@ -609,6 +678,35 @@ create_and_realize (NMDevice *device,
return FALSE;
}
break;
case NM_IP_TUNNEL_MODE_IPIP6:
case NM_IP_TUNNEL_MODE_IP6IP6:
if (parent)
lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent);
str = nm_setting_ip_tunnel_get_local (s_ip_tunnel);
if (str)
inet_pton (AF_INET6, str, &lnk_ip6tnl.local);
str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel);
g_assert (str);
inet_pton (AF_INET6, str, &lnk_ip6tnl.remote);
lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel);
lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel);
lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel);
lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel);
lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6;
plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink);
if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create IPIP interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
return FALSE;
}
break;
default:
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create IP tunnel interface '%s' for '%s': mode %d not supported",
@ -665,6 +763,12 @@ get_property (GObject *object, guint prop_id,
case PROP_OUTPUT_KEY:
g_value_set_string (value, priv->output_key);
break;
case PROP_ENCAPSULATION_LIMIT:
g_value_set_uchar (value, priv->encap_limit);
break;
case PROP_FLOW_LABEL:
g_value_set_uint (value, priv->flow_label);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -774,6 +878,20 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_ENCAPSULATION_LIMIT,
g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "",
0, 255, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
(object_class, PROP_FLOW_LABEL,
g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "",
0, (1 << 20) - 1, 0,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
NMDBUS_TYPE_DEVICE_IPTUNNEL_SKELETON,
NULL);
@ -799,6 +917,9 @@ create_device (NMDeviceFactory *factory,
} else
mode = platform_link_to_tunnel_mode (plink);
if (mode == NM_IP_TUNNEL_MODE_UKNOWN)
return NULL;
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_IP_TUNNEL,
NM_DEVICE_IFACE, iface,
NM_DEVICE_TYPE_DESC, "IPTunnel",

View file

@ -42,6 +42,8 @@ G_BEGIN_DECLS
#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery"
#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key"
#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key"
#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit"
#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label"
typedef struct {
NMDevice parent;