diff --git a/src/nm-types.h b/src/nm-types.h index e84e4826b..efdce5911 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -160,6 +160,8 @@ typedef enum { NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_IPIP, NM_LINK_TYPE_LOOPBACK, NM_LINK_TYPE_MACSEC, @@ -197,6 +199,8 @@ typedef enum { NMP_OBJECT_TYPE_LNK_GRETAP, NMP_OBJECT_TYPE_LNK_INFINIBAND, NMP_OBJECT_TYPE_LNK_IP6TNL, + NMP_OBJECT_TYPE_LNK_IP6GRE, + NMP_OBJECT_TYPE_LNK_IP6GRETAP, NMP_OBJECT_TYPE_LNK_IPIP, NMP_OBJECT_TYPE_LNK_MACSEC, NMP_OBJECT_TYPE_LNK_MACVLAN, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 81712a451..9acd7ac52 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -549,6 +549,8 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, + { NM_LINK_TYPE_IP6GRE, "ip6gre", "ip6gre", NULL }, + { NM_LINK_TYPE_IP6GRETAP, "ip6gretap", "ip6gretap", NULL }, { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, { NM_LINK_TYPE_MACSEC, "macsec", "macsec", NULL }, @@ -1222,6 +1224,79 @@ _parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) return obj; } +static NMPObject * +_parse_lnk_ip6gre (const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[IFLA_GRE_MAX + 1] = { + [IFLA_GRE_LINK] = { .type = NLA_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_IKEY] = { .type = NLA_U32 }, + [IFLA_GRE_OKEY] = { .type = NLA_U32 }, + [IFLA_GRE_LOCAL] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_GRE_REMOTE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_GRE_TTL] = { .type = NLA_U8 }, + [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, + }; + struct nlattr *tb[IFLA_GRE_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIp6Tnl *props; + guint32 flowinfo; + gboolean is_tap; + + if (!info_data || !kind) + return NULL; + + if (nm_streq (kind, "ip6gre")) + is_tap = FALSE; + else if (nm_streq (kind, "ip6gretap")) + is_tap = TRUE; + else + return NULL; + + err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (is_tap ? NMP_OBJECT_TYPE_LNK_IP6GRETAP : NMP_OBJECT_TYPE_LNK_IP6GRE, NULL); + props = &obj->lnk_ip6tnl; + props->is_gre = TRUE; + props->is_tap = is_tap; + + if (tb[IFLA_GRE_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_GRE_LINK]); + if (tb[IFLA_GRE_IFLAGS]) + props->input_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])); + if (tb[IFLA_GRE_OFLAGS]) + props->output_flags = ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])); + if (tb[IFLA_GRE_IKEY]) + props->input_key = ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])); + if (tb[IFLA_GRE_OKEY]) + props->output_key = ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])); + if (tb[IFLA_GRE_LOCAL]) + memcpy (&props->local, nla_data (tb[IFLA_GRE_LOCAL]), sizeof (props->local)); + if (tb[IFLA_GRE_REMOTE]) + memcpy (&props->remote, nla_data (tb[IFLA_GRE_REMOTE]), sizeof (props->remote)); + if (tb[IFLA_GRE_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]); + if (tb[IFLA_GRE_ENCAP_LIMIT]) + props->encap_limit = nla_get_u8 (tb[IFLA_GRE_ENCAP_LIMIT]); + if (tb[IFLA_GRE_FLOWINFO]) { + flowinfo = ntohl (nla_get_u32 (tb[IFLA_GRE_FLOWINFO])); + props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; + props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; + } + if (tb[IFLA_GRE_FLAGS]) + props->flags = nla_get_u32 (tb[IFLA_GRE_FLAGS]); + + return obj; +} + /*****************************************************************************/ static NMPObject * @@ -1870,6 +1945,10 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_IP6TNL: lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_IP6GRE: + case NM_LINK_TYPE_IP6GRETAP: + lnk_data = _parse_lnk_ip6gre (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_IPIP: lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data); break; @@ -4007,6 +4086,8 @@ cache_on_change (NMPlatform *platform, && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IP6GRE, + NM_LINK_TYPE_IP6GRETAP, NM_LINK_TYPE_INFINIBAND, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVLAN, @@ -5379,6 +5460,8 @@ link_ip6tnl_add (NMPlatform *platform, struct nlattr *data; guint32 flowinfo; + g_return_val_if_fail (!props->is_gre, FALSE); + nlmsg = _nl_msg_new_link (RTM_NEWLINK, NLM_F_CREATE | NLM_F_EXCL, 0, @@ -5422,6 +5505,68 @@ nla_put_failure: g_return_val_if_reached (FALSE); } +static gboolean +link_ip6gre_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + guint32 flowinfo; + + g_return_val_if_fail (props->is_gre, FALSE); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE | NLM_F_EXCL, + 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, props->is_tap ? "ip6gretap" : "ip6gre"); + + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; + + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); + + NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U16 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); + + if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_GRE_LOCAL, sizeof (props->local), &props->local); + if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_GRE_REMOTE, sizeof (props->remote), &props->remote); + + NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_GRE_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_GRE_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_FLAGS, props->flags); + + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, + props->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, + name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + static gboolean link_ipip_add (NMPlatform *platform, const char *name, @@ -7314,6 +7459,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_gre_add = link_gre_add; platform_class->link_ip6tnl_add = link_ip6tnl_add; + platform_class->link_ip6gre_add = link_ip6gre_add; platform_class->link_macsec_add = link_macsec_add; platform_class->link_macvlan_add = link_macvlan_add; platform_class->link_ipip_add = link_ipip_add; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 8fec85d94..99dd8490d 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1872,6 +1872,18 @@ nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatform return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link); } +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRE, out_link); +} + +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6gretap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6GRETAP, out_link); +} + const NMPlatformLnkIpIp * nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -2550,6 +2562,7 @@ nm_platform_link_ip6tnl_add (NMPlatform *self, g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (!props->is_gre, NM_PLATFORM_ERROR_BUG); plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) @@ -2563,6 +2576,46 @@ nm_platform_link_ip6tnl_add (NMPlatform *self, return NM_PLATFORM_ERROR_SUCCESS; } +/** + * nm_platform_ip6gre_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPv6 GRE/GRETAP tunnel. + */ +NMPlatformError +nm_platform_link_ip6gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + + _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); + g_return_val_if_fail (props->is_gre, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, + name, + props->is_tap + ? NM_LINK_TYPE_IP6GRETAP + : NM_LINK_TYPE_IP6GRE, + out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("adding link '%s': %s", + name, nm_platform_lnk_ip6tnl_to_string (props, NULL, 0)); + + if (!klass->link_ip6gre_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + /** * nm_platform_ipip_add: * @self: platform instance @@ -5118,12 +5171,18 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi char str_encap[30]; char str_proto[30]; char str_parent_ifindex[30]; + char *str_type; if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) return buf; + if (lnk->is_gre) + str_type = lnk->is_tap ? "ip6gretap" : "ip6gre"; + else + str_type = "ip6tnl"; + g_snprintf (buf, len, - "ip6tnl" + "%s" /* type */ "%s" /* remote */ "%s" /* local */ "%s" /* parent_ifindex */ @@ -5134,6 +5193,7 @@ nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsi "%s" /* proto */ " flags 0x%x" "", + str_type, 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) : "", @@ -5998,7 +6058,13 @@ nm_platform_lnk_ip6tnl_hash_update (const NMPlatformLnkIp6Tnl *obj, NMHashState obj->encap_limit, obj->proto, obj->flow_label, - obj->flags); + obj->flags, + obj->input_flags, + obj->output_flags, + obj->input_key, + obj->output_key, + (bool) obj->is_gre, + (bool) obj->is_tap); } int @@ -6014,6 +6080,12 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6 NM_CMP_FIELD (a, b, flow_label); NM_CMP_FIELD (a, b, proto); NM_CMP_FIELD (a, b, flags); + NM_CMP_FIELD (a, b, input_flags); + NM_CMP_FIELD (a, b, output_flags); + NM_CMP_FIELD (a, b, input_key); + NM_CMP_FIELD (a, b, output_key); + NM_CMP_FIELD_BOOL (a, b, is_gre); + NM_CMP_FIELD_BOOL (a, b, is_tap); return 0; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index fcb561996..567c93ef3 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -636,6 +636,14 @@ typedef struct { guint8 proto; guint flow_label; guint32 flags; + + /* IP6GRE only */ + guint32 input_key; + guint32 output_key; + guint16 input_flags; + guint16 output_flags; + bool is_tap:1; + bool is_gre:1; } NMPlatformLnkIp6Tnl; typedef struct { @@ -830,6 +838,10 @@ typedef struct { const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); + gboolean (*link_ip6gre_add) (NMPlatform *, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); gboolean (*link_ipip_add) (NMPlatform *, const char *name, const NMPlatformLnkIpIp *props, @@ -1201,6 +1213,8 @@ const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLink const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkGre *nm_platform_link_get_lnk_gretap (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 NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6gretap (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); @@ -1285,6 +1299,10 @@ NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, const char *name, const NMPlatformLnkIp6Tnl *props, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_ip6gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, const char *name, const NMPlatformLnkIpIp *props, diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 8e07923a7..666a1d1dd 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -2745,6 +2745,28 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, }, + [NMP_OBJECT_TYPE_LNK_IP6GRE - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRE, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6gre", + .lnk_link_type = NM_LINK_TYPE_IP6GRE, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, + [NMP_OBJECT_TYPE_LNK_IP6GRETAP - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_IP6GRETAP, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6gretap", + .lnk_link_type = NM_LINK_TYPE_IP6GRETAP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_ip6tnl_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_IPIP, diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 4e708f208..3dedbd103 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -1297,6 +1297,7 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, gboolean tclass_inherit; g_assert (nm_utils_is_valid_iface_name (name, NULL)); + g_assert (!lnk->is_gre); external_command = nmtstp_run_command_check_external (external_command); @@ -1343,6 +1344,56 @@ nmtstp_link_ip6tnl_add (NMPlatform *platform, return pllink; } +const NMPlatformLink * +nmtstp_link_ip6gre_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET6_ADDRSTRLEN]; + char tclass[20]; + gboolean tclass_inherit; + + g_assert (nm_utils_is_valid_iface_name (name, NULL)); + g_assert (lnk->is_gre); + + external_command = nmtstp_run_command_check_external (external_command); + + _init_platform (&platform, external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (platform, lnk->parent_ifindex)); + + tclass_inherit = NM_FLAGS_HAS (lnk->flags, IP6_TNL_F_USE_ORIG_TCLASS); + + success = !nmtstp_run_command ("ip link add %s type %s %s local %s remote %s ttl %u tclass %s flowlabel %x", + name, + lnk->is_tap ? "ip6gretap" : "ip6gre", + dev, + nm_utils_inet6_ntop (&lnk->local, NULL), + nm_utils_inet6_ntop (&lnk->remote, buffer), + lnk->ttl, + tclass_inherit ? "inherit" : nm_sprintf_buf (tclass, "%02x", lnk->tclass), + lnk->flow_label); + if (success) { + pllink = nmtstp_assert_wait_for_link (platform, + name, + lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE, + 100); + } + } else + success = nm_platform_link_ip6gre_add (platform, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (platform, success, pllink, name, lnk->is_tap ? NM_LINK_TYPE_IP6GRETAP : NM_LINK_TYPE_IP6GRE); + + return pllink; +} + const NMPlatformLink * nmtstp_link_ipip_add (NMPlatform *platform, gboolean external_command, diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index bd02b0d7d..ed6e5791a 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -297,6 +297,10 @@ const NMPlatformLink *nmtstp_link_ip6tnl_add (NMPlatform *platform, gboolean external_command, const char *name, const NMPlatformLnkIp6Tnl *lnk); +const NMPlatformLink *nmtstp_link_ip6gre_add (NMPlatform *platform, + gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk); const NMPlatformLink *nmtstp_link_ipip_add (NMPlatform *platform, gboolean external_command, const char *name, diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index e99d5d1fe..ce0bb49e4 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -819,6 +819,58 @@ test_software_detect (gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRE: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) { + /* Seems that the ip6_tunnel module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0; + } + + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::42"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::aaaa"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 21; + lnk_ip6tnl.flow_label = 1338; + lnk_ip6tnl.is_gre = TRUE; + + if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ip6gre tunnel because of missing ip6_gre module (modprobe ip6_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding IP6GRE tunnel"); + } + break; + } + case NM_LINK_TYPE_IP6GRETAP: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6gre0")) { + /* Seems that the ip6_tunnel module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_gre", NULL) != 0; + } + + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fe80::abcd"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fc01::bbbb"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.ttl = 10; + lnk_ip6tnl.tclass = 22; + lnk_ip6tnl.flow_label = 1339; + lnk_ip6tnl.is_gre = TRUE; + lnk_ip6tnl.is_tap = TRUE; + + if (!nmtstp_link_ip6gre_add (NULL, ext, DEVICE_NAME, &lnk_ip6tnl)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ip6gretap tunnel because of missing ip6_gre module (modprobe ip6_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding IP6GRETAP tunnel"); + } + break; + } case NM_LINK_TYPE_MACVLAN: { NMPlatformLnkMacvlan lnk_macvlan = { }; const NMPlatformLink *dummy; @@ -1036,6 +1088,33 @@ test_software_detect (gconstpointer user_data) } break; } + case NM_LINK_TYPE_IP6GRE: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6gre (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::42"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::aaaa"); + g_assert_cmpint (plnk->tclass, ==, 21); + g_assert_cmpint (plnk->flow_label, ==, 1338); + g_assert_cmpint (plnk->is_gre, ==, TRUE); + g_assert_cmpint (plnk->is_tap, ==, FALSE); + break; + } + case NM_LINK_TYPE_IP6GRETAP: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6gretap (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fe80::abcd"); + nmtst_assert_ip6_address (&plnk->remote, "fc01::bbbb"); + g_assert_cmpint (plnk->ttl, ==, 10); + g_assert_cmpint (plnk->tclass, ==, 22); + g_assert_cmpint (plnk->flow_label, ==, 1339); + g_assert_cmpint (plnk->is_gre, ==, TRUE); + g_assert_cmpint (plnk->is_tap, ==, TRUE); + break; + } case NM_LINK_TYPE_IPIP: { const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip; @@ -2668,6 +2747,8 @@ _nmtstp_setup_tests (void) test_software_detect_add ("/link/software/detect/gretap", NM_LINK_TYPE_GRETAP, 0); test_software_detect_add ("/link/software/detect/ip6tnl/0", NM_LINK_TYPE_IP6TNL, 0); test_software_detect_add ("/link/software/detect/ip6tnl/1", NM_LINK_TYPE_IP6TNL, 1); + test_software_detect_add ("/link/software/detect/ip6gre", NM_LINK_TYPE_IP6GRE, 0); + test_software_detect_add ("/link/software/detect/ip6gretap", NM_LINK_TYPE_IP6GRETAP, 0); test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);