diff --git a/src/nm-types.h b/src/nm-types.h index 9926e813e..16ae6fa7b 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -108,6 +108,7 @@ typedef enum { NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, + NM_LINK_TYPE_IP6TNL, NM_LINK_TYPE_IPIP, NM_LINK_TYPE_LOOPBACK, NM_LINK_TYPE_MACVLAN, @@ -137,6 +138,7 @@ typedef enum { NMP_OBJECT_TYPE_LNK_GRE, NMP_OBJECT_TYPE_LNK_INFINIBAND, + NMP_OBJECT_TYPE_LNK_IP6TNL, NMP_OBJECT_TYPE_LNK_IPIP, NMP_OBJECT_TYPE_LNK_MACVLAN, NMP_OBJECT_TYPE_LNK_SIT, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 9fcfb4618..354641fee 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -91,6 +91,8 @@ #define IFLA_IPTUN_REMOTE 3 #define IFLA_IPTUN_TTL 4 #define IFLA_IPTUN_TOS 5 +#define IFLA_IPTUN_ENCAP_LIMIT 6 +#define IFLA_IPTUN_FLOWINFO 7 #define IFLA_IPTUN_FLAGS 8 #define IFLA_IPTUN_PROTO 9 #define IFLA_IPTUN_PMTUDISC 10 @@ -103,6 +105,10 @@ #define MACVLAN_FLAG_NOPROMISC 1 #endif +#define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000 +#define IP6_FLOWINFO_TCLASS_SHIFT 20 +#define IP6_FLOWINFO_FLOWLABEL_MASK 0x000FFFFF + /*********************************************************************************************/ #define _NMLOG_PREFIX_NAME "platform-linux" @@ -329,6 +335,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, + { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, @@ -630,6 +637,8 @@ _linktype_get_type (NMPlatform *platform, return NM_LINK_TYPE_INFINIBAND; else if (arptype == ARPHRD_SIT) return NM_LINK_TYPE_SIT; + else if (arptype == ARPHRD_TUNNEL6) + return NM_LINK_TYPE_IP6TNL; if (ifname) { gs_free char *driver = NULL; @@ -915,6 +924,59 @@ _parse_lnk_infiniband (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static NMPObject * +_parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIp6Tnl *props; + guint32 flowinfo; + + if (!info_data || g_strcmp0 (kind, "ip6tnl")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); + props = &obj->lnk_ip6tnl; + + if (tb[IFLA_IPTUN_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); + if (tb[IFLA_IPTUN_LOCAL]) + memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + if (tb[IFLA_IPTUN_REMOTE]) + memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + if (tb[IFLA_IPTUN_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); + if (tb[IFLA_IPTUN_ENCAP_LIMIT]) + props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]); + if (tb[IFLA_IPTUN_FLOWINFO]) { + flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO])); + props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; + props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; + } + if (tb[IFLA_IPTUN_PROTO]) + props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]); + + return obj; +} + +/*****************************************************************************/ + static NMPObject * _parse_lnk_ipip (const char *kind, struct nlattr *info_data) { @@ -1424,6 +1486,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_INFINIBAND: lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_IP6TNL: + lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_IPIP: lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data); break; @@ -2839,6 +2904,7 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */ switch (new->link.type) { case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_IP6TNL: case NM_LINK_TYPE_INFINIBAND: case NM_LINK_TYPE_MACVLAN: case NM_LINK_TYPE_SIT: @@ -4195,6 +4261,67 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static int +link_ip6tnl_add (NMPlatform *platform, + const char *name, + NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + guint32 flowinfo; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; + + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; + + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + + if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local); + if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); + + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static int link_ipip_add (NMPlatform *platform, const char *name, @@ -5751,6 +5878,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->mesh_set_ssid = mesh_set_ssid; platform_class->link_gre_add = link_gre_add; + platform_class->link_ip6tnl_add = link_ip6tnl_add; platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 0b86e0838..959f6dfae 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1429,6 +1429,12 @@ nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlat return _link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link); } +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link); +} + const NMPlatformLnkIpIp * nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -1859,6 +1865,45 @@ nm_platform_infiniband_get_properties (NMPlatform *self, return TRUE; } +/** + * nm_platform_ip6tnl_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPv6 tunnel. + */ +NMPlatformError +nm_platform_link_ip6tnl_add (NMPlatform *self, + const char *name, + NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link) +{ + NMPlatformError plerr; + char buffer[INET6_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + if (!klass->link_ip6tnl_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + /** * nm_platform_ipip_add: * @self: platform instance @@ -2936,6 +2981,45 @@ nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char * return buf; } +const char * +nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tclass[30]; + char str_flow[30]; + char str_encap[30]; + char str_proto[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "ip6tnl" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tclass */ + "%s" /* encap limit */ + "%s" /* flow label */ + "%s" /* proto */ + "", + nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), + nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), + nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit), + nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label), + nm_sprintf_buf (str_proto, " proto %u", lnk->proto)); + return buf; +} + const char * nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len) { @@ -3561,6 +3645,21 @@ nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatfo return 0; } +int +nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD_MEMCMP (a, b, local); + _CMP_FIELD_MEMCMP (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tclass); + _CMP_FIELD (a, b, encap_limit); + _CMP_FIELD (a, b, flow_label); + _CMP_FIELD (a, b, proto); + return 0; +} + int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 60f050057..5eb042cf7 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -378,6 +378,17 @@ typedef struct { const char *mode; } NMPlatformLnkInfiniband; +typedef struct { + int parent_ifindex; + struct in6_addr local; + struct in6_addr remote; + guint8 ttl; + guint8 tclass; + guint8 encap_limit; + guint flow_label; + guint8 proto; +} NMPlatformLnkIp6Tnl; + typedef struct { int parent_ifindex; in_addr_t local; @@ -549,6 +560,8 @@ typedef struct { gboolean (*link_gre_add) (NMPlatform *, const char *name, NMPlatformLnkGre *props, NMPlatformLink *out_link); + gboolean (*link_ip6tnl_add) (NMPlatform *, const char *name, NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link); gboolean (*link_ipip_add) (NMPlatform *, const char *name, NMPlatformLnkIpIp *props, NMPlatformLink *out_link); gboolean (*link_sit_add) (NMPlatform *, const char *name, NMPlatformLnkSit *props, @@ -742,6 +755,8 @@ char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *o const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -797,6 +812,8 @@ const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int i NMPlatformError nm_platform_link_gre_add (NMPlatform *self, const char *name, NMPlatformLnkGre *props, NMPlatformLink *out_link); +NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name, NMPlatformLnkIp6Tnl *props, + NMPlatformLink *out_link); NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, NMPlatformLnkIpIp *props, NMPlatformLink *out_link); NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, NMPlatformLnkSit *props, @@ -843,6 +860,7 @@ gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6 const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); +const char *nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len); const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len); const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); @@ -862,6 +880,7 @@ const char *nm_platform_vlan_qos_mapping_to_string (const char *name, int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); +int nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b); int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b); int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index da40c8b6a..cb605c28f 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -2045,6 +2045,15 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp, }, + [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6tnl", + .lnk_link_type = NM_LINK_TYPE_IP6TNL, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { .obj_type = NMP_OBJECT_TYPE_LNK_IPIP, .sizeof_data = sizeof (NMPObjectLnkIpIp), diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 07bd7e5e8..38224acd3 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -169,6 +169,10 @@ typedef struct { NMPlatformLnkInfiniband _public; } NMPObjectLnkInfiniband; +typedef struct { + NMPlatformLnkIp6Tnl _public; +} NMPObjectLnkIp6Tnl; + typedef struct { NMPlatformLnkIpIp _public; } NMPObjectLnkIpIp; @@ -229,6 +233,9 @@ struct _NMPObject { NMPlatformLnkIpIp lnk_ipip; NMPObjectLnkIpIp _lnk_ipip; + NMPlatformLnkIp6Tnl lnk_ip6tnl; + NMPObjectLnkIp6Tnl _lnk_ip6tnl; + NMPlatformLnkMacvlan lnk_macvlan; NMPObjectLnkMacvlan _lnk_macvlan;