diff --git a/src/nm-types.h b/src/nm-types.h index e84341bbe..517316cdb 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -132,6 +132,7 @@ typedef enum { NMP_OBJECT_TYPE_IP6_ROUTE, NMP_OBJECT_TYPE_LNK_GRE, + NMP_OBJECT_TYPE_LNK_INFINIBAND, NMP_OBJECT_TYPE_LNK_MACVLAN, NMP_OBJECT_TYPE_LNK_VLAN, NMP_OBJECT_TYPE_LNK_VXLAN, diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 1616af46e..d77c21775 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -75,7 +75,7 @@ typedef struct { char *udi; NMPlatformLnkVlan lnk_vlan; - int ib_p_key; + NMPlatformLnkInfiniband lnk_infiniband; struct in6_addr ip6_lladdr; } NMFakePlatformLink; @@ -271,6 +271,8 @@ link_get_lnk (NMPlatform *platform, switch (link_type) { case NM_LINK_TYPE_VLAN: return &device->lnk_vlan; + case NM_LINK_TYPE_INFINIBAND: + return &device->lnk_infiniband; default: return NULL; } @@ -692,31 +694,13 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor device = link_get (platform, nm_platform_link_get_ifindex (platform, name)); g_return_val_if_fail (device, FALSE); - device->ib_p_key = p_key; + device->lnk_infiniband.p_key = p_key; + device->lnk_infiniband.mode = "datagram"; device->link.parent = parent; return TRUE; } -static gboolean -infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode) -{ - NMFakePlatformLink *device; - - device = link_get (platform, ifindex); - g_return_val_if_fail (device, FALSE); - g_return_val_if_fail (device->link.type == NM_LINK_TYPE_INFINIBAND, FALSE); - - if (parent) - *parent = device->link.parent; - if (p_key) - *p_key = device->ib_p_key; - if (mode) - *mode = "datagram"; - - return TRUE; -} - static gboolean veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props) { @@ -1453,7 +1437,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->vlan_set_egress_map = vlan_set_egress_map; platform_class->infiniband_partition_add = infiniband_partition_add; - platform_class->infiniband_get_info = infiniband_get_info; platform_class->veth_get_properties = veth_get_properties; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6d7577877..4f8c0f47e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -935,6 +935,66 @@ _parse_lnk_gre (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers + * we're building against might not have those properties even though the + * running kernel might. + */ +#define IFLA_IPOIB_UNSPEC 0 +#define IFLA_IPOIB_PKEY 1 +#define IFLA_IPOIB_MODE 2 +#define IFLA_IPOIB_UMCAST 3 +#undef IFLA_IPOIB_MAX +#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST + +#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */ +#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */ + +static NMPObject * +_parse_lnk_infiniband (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPOIB_MAX + 1] = { + [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, + [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, + [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, + }; + struct nlattr *tb[IFLA_IPOIB_MAX + 1]; + NMPlatformLnkInfiniband *info; + NMPObject *obj; + int err; + const char *mode; + + if (!info_data || g_strcmp0 (kind, "ipoib")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy); + if (err < 0) + return NULL; + + if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) + return NULL; + + switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { + case IPOIB_MODE_DATAGRAM: + mode = "datagram"; + break; + case IPOIB_MODE_CONNECTED: + mode = "connected"; + break; + default: + return NULL; + } + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL); + info = &obj->lnk_infiniband; + + info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]); + info->mode = mode; + + return obj; +} + +/*****************************************************************************/ + static NMPObject * _parse_lnk_macvlan (const char *kind, struct nlattr *info_data) { @@ -1284,6 +1344,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_GRE: lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_INFINIBAND: + lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_MACVLAN: lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data); break; @@ -1668,90 +1731,6 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m /******************************************************************/ -/* _nl_link_parse_info_data(): Re-fetches a link from the kernel - * and parses its IFLA_INFO_DATA using a caller-provided parser. - * - * Code is stolen from rtnl_link_get_kernel(), nl_pickup(), and link_msg_parser(). - */ - -typedef int (*NMNLInfoDataParser) (struct nlattr *info_data, gpointer parser_data); - -typedef struct { - NMNLInfoDataParser parser; - gpointer parser_data; -} NMNLInfoDataClosure; - -static struct nla_policy info_data_link_policy[IFLA_MAX + 1] = { - [IFLA_LINKINFO] = { .type = NLA_NESTED }, -}; - -static struct nla_policy info_data_link_info_policy[IFLA_INFO_MAX + 1] = { - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, -}; - -static int -_nl_link_parse_info_data_cb (struct nl_msg *msg, void *arg) -{ - NMNLInfoDataClosure *closure = arg; - struct nlmsghdr *n = nlmsg_hdr (msg); - struct nlattr *tb[IFLA_MAX + 1]; - struct nlattr *li[IFLA_INFO_MAX + 1]; - int err; - - if (!nlmsg_valid_hdr (n, sizeof (struct ifinfomsg))) - return -NLE_MSG_TOOSHORT; - - err = nlmsg_parse (n, sizeof (struct ifinfomsg), tb, IFLA_MAX, info_data_link_policy); - if (err < 0) - return err; - - if (!tb[IFLA_LINKINFO]) - return -NLE_MISSING_ATTR; - - err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], info_data_link_info_policy); - if (err < 0) - return err; - - if (!li[IFLA_INFO_DATA]) - return -NLE_MISSING_ATTR; - - return closure->parser (li[IFLA_INFO_DATA], closure->parser_data); -} - -static int -_nl_link_parse_info_data (struct nl_sock *sk, int ifindex, - NMNLInfoDataParser parser, gpointer parser_data) -{ - NMNLInfoDataClosure data = { .parser = parser, .parser_data = parser_data }; - struct nl_msg *msg = NULL; - struct nl_cb *cb; - int err; - - err = rtnl_link_build_get_request (ifindex, NULL, &msg); - if (err < 0) - return err; - - err = nl_send_auto (sk, msg); - nlmsg_free (msg); - if (err < 0) - return err; - - cb = nl_cb_clone (nl_socket_get_cb (sk)); - if (cb == NULL) - return -NLE_NOMEM; - nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, _nl_link_parse_info_data_cb, &data); - - err = nl_recvmsgs (sk, cb); - nl_cb_put (cb); - if (err < 0) - return err; - - nl_wait_for_ack (sk); - return 0; -} - -/******************************************************************/ - static int _nl_sock_flush_data (struct nl_sock *sk) { @@ -3277,6 +3256,10 @@ link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMP if (NMP_OBJECT_GET_TYPE (obj->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_GRE) return &obj->_link.netlink.lnk->lnk_gre; break; + case NM_LINK_TYPE_INFINIBAND: + if (NMP_OBJECT_GET_TYPE (obj->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_INFINIBAND) + return &obj->_link.netlink.lnk->lnk_infiniband; + break; case NM_LINK_TYPE_MACVLAN: if (NMP_OBJECT_GET_TYPE (obj->_link.netlink.lnk) == NMP_OBJECT_TYPE_LNK_MACVLAN) return &obj->_link.netlink.lnk->lnk_macvlan; @@ -3978,115 +3961,6 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor return !!obj; } -typedef struct { - int p_key; - const char *mode; -} IpoibInfo; - -/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers - * we're building against might not have those properties even though the - * running kernel might. - */ -#define IFLA_IPOIB_UNSPEC 0 -#define IFLA_IPOIB_PKEY 1 -#define IFLA_IPOIB_MODE 2 -#define IFLA_IPOIB_UMCAST 3 -#undef IFLA_IPOIB_MAX -#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST - -#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */ -#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */ - -static const struct nla_policy infiniband_info_policy[IFLA_IPOIB_MAX + 1] = { - [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, - [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, - [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, -}; - -static int -infiniband_info_data_parser (struct nlattr *info_data, gpointer parser_data) -{ - IpoibInfo *info = parser_data; - struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; - int err; - - err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, - (struct nla_policy *) infiniband_info_policy); - if (err < 0) - return err; - if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) - return -EINVAL; - - info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]); - - switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { - case IPOIB_MODE_DATAGRAM: - info->mode = "datagram"; - break; - case IPOIB_MODE_CONNECTED: - info->mode = "connected"; - break; - default: - return -NLE_PARSE_ERR; - } - - return 0; -} - -static gboolean -infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const NMPObject *obj; - IpoibInfo info = { -1, NULL }; - - obj = cache_lookup_link (platform, ifindex); - if (!obj) - return FALSE; - - if (parent) - *parent = obj->link.parent; - - if (_nl_link_parse_info_data (priv->nlh, - ifindex, - infiniband_info_data_parser, - &info) != 0) { - const char *iface = obj->link.name; - char *path, *contents = NULL; - - /* Fall back to reading sysfs */ - path = g_strdup_printf ("/sys/class/net/%s/mode", ASSERT_VALID_PATH_COMPONENT (iface)); - contents = nm_platform_sysctl_get (platform, path); - g_free (path); - if (!contents) - return FALSE; - - if (strstr (contents, "datagram")) - info.mode = "datagram"; - else if (strstr (contents, "connected")) - info.mode = "connected"; - g_free (contents); - - path = g_strdup_printf ("/sys/class/net/%s/pkey", ASSERT_VALID_PATH_COMPONENT (iface)); - contents = nm_platform_sysctl_get (platform, path); - g_free (path); - if (!contents) - return FALSE; - - info.p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1); - g_free (contents); - - if (info.p_key < 0) - return FALSE; - } - - if (p_key) - *p_key = info.p_key; - if (mode) - *mode = info.mode; - return TRUE; -} - /******************************************************************/ static gboolean @@ -5335,7 +5209,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->vlan_set_egress_map = vlan_set_egress_map; platform_class->infiniband_partition_add = infiniband_partition_add; - platform_class->infiniband_get_info = infiniband_get_info; platform_class->veth_get_properties = veth_get_properties; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 20695cbd3..fae0e2e70 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1406,6 +1406,12 @@ nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLin return nm_platform_link_get_lnk (self, ifindex, NM_LINK_TYPE_GRE, out_link); } +const NMPlatformLnkInfiniband * +nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return nm_platform_link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link); +} + const NMPlatformLnkMacvlan * nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -1617,16 +1623,68 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, N gboolean nm_platform_infiniband_get_info (NMPlatform *self, int ifindex, - int *parent, - int *p_key, - const char **mode) + int *out_parent, + int *out_p_key, + const char **out_mode) { + const NMPlatformLnkInfiniband *plnk; + const NMPlatformLink *plink; + const char *iface; + char *path, *contents; + const char *mode; + int p_key = 0; + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (klass->infiniband_get_info, FALSE); - return klass->infiniband_get_info (self, ifindex, parent, p_key, mode); + plnk = nm_platform_link_get_lnk_infiniband (self, ifindex, &plink); + + if ( !plink + || plink->type != NM_LINK_TYPE_INFINIBAND) + return FALSE; + + if (plnk) { + NM_SET_OUT (out_parent, plink->parent); + NM_SET_OUT (out_p_key, plnk->p_key); + NM_SET_OUT (out_mode, plnk->mode); + return TRUE; + } + + /* Could not get the link information via netlink. To support older kernels, + * fallback to reading sysfs. */ + + iface = ASSERT_VALID_PATH_COMPONENT (plink->name); + + /* Fall back to reading sysfs */ + path = g_strdup_printf ("/sys/class/net/%s/mode", iface); + contents = nm_platform_sysctl_get (self, path); + g_free (path); + if (!contents) + return FALSE; + + if (strstr (contents, "datagram")) + mode = "datagram"; + else if (strstr (contents, "connected")) + mode = "connected"; + else + mode = NULL; + g_free (contents); + + path = g_strdup_printf ("/sys/class/net/%s/pkey", iface); + contents = nm_platform_sysctl_get (self, path); + g_free (path); + if (!contents) + return FALSE; + p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1); + g_free (contents); + if (p_key < 0) + return FALSE; + + NM_SET_OUT (out_parent, plink->parent); + NM_SET_OUT (out_p_key, p_key); + NM_SET_OUT (out_mode, mode); + return TRUE; } gboolean @@ -2595,6 +2653,25 @@ nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len return buf; } +const char * +nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len) +{ + char str_p_key[64]; + + if (!_to_string_buffer_init (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "infiniband" + "%s" /* p_key */ + "%s%s" /* mode */ + "", + lnk->p_key ? nm_sprintf_buf (str_p_key, " pkey %d", lnk->p_key) : "", + lnk->mode ? " mode " : "", + lnk->mode ?: ""); + return buf; +} + const char * nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len) { @@ -3087,6 +3164,15 @@ nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) return 0; } +int +nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, p_key); + _CMP_FIELD_STR_INTERNED (a, b, mode); + return 0; +} + int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index d85382997..64e7d2b59 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -340,6 +340,11 @@ typedef struct { extern const NMPlatformVTableRoute nm_platform_vtable_route_v4; extern const NMPlatformVTableRoute nm_platform_vtable_route_v6; +typedef struct { + int p_key; + const char *mode; +} NMPlatformLnkInfiniband; + typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; @@ -498,11 +503,6 @@ typedef struct { gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link); - gboolean (*infiniband_get_info) (NMPlatform *, - int ifindex, - int *parent, - int *p_key, - const char **mode); gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties); @@ -689,6 +689,7 @@ char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *o gconstpointer 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 NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -768,6 +769,7 @@ extern char _nm_platform_to_string_buffer[1024]; 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_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); @@ -778,6 +780,7 @@ const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, ch 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_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 97b9b8cfa..0f9a4fbf6 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1905,6 +1905,14 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp, }, + [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND, + .sizeof_data = sizeof (NMPObjectLnkInfiniband), + .sizeof_public = sizeof (NMPlatformLnkInfiniband), + .obj_type_name = "infiniband", + .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_MACVLAN - 1] = { .obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN, .sizeof_data = sizeof (NMPObjectLnkMacvlan), diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index de7eea318..f5e64fa10 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -161,6 +161,10 @@ typedef struct { NMPlatformLnkGre _public; } NMPObjectLnkGre; +typedef struct { + NMPlatformLnkInfiniband _public; +} NMPObjectLnkInfiniband; + typedef struct { NMPlatformLnkMacvlan _public; } NMPObjectLnkMacvlan; @@ -202,6 +206,9 @@ struct _NMPObject { NMPlatformLnkGre lnk_gre; NMPObjectLnkGre _lnk_gre; + NMPlatformLnkInfiniband lnk_infiniband; + NMPObjectLnkInfiniband _lnk_infiniband; + NMPlatformLnkMacvlan lnk_macvlan; NMPObjectLnkMacvlan _lnk_macvlan;