3a71879df9f75f13cc0400062a598fa89088a68a
[NetworkManager.git] / libnm-core / nm-setting-infiniband.c
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3 /*
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301 USA.
18  *
19  * Copyright 2011 - 2013 Red Hat, Inc.
20  */
21
22 #include "nm-default.h"
23
24 #include <stdlib.h>
25
26 #include "nm-setting-infiniband.h"
27 #include "nm-utils.h"
28 #include "nm-utils-private.h"
29 #include "nm-setting-private.h"
30 #include "nm-setting-connection.h"
31
32 /**
33  * SECTION:nm-setting-infiniband
34  * @short_description: Describes connection properties for IP-over-InfiniBand networks
35  *
36  * The #NMSettingInfiniband object is a #NMSetting subclass that describes properties
37  * necessary for connection to IP-over-InfiniBand networks.
38  **/
39
40 G_DEFINE_TYPE_WITH_CODE (NMSettingInfiniband, nm_setting_infiniband, NM_TYPE_SETTING,
41                          _nm_register_setting (INFINIBAND, 1))
42 NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_INFINIBAND)
43
44 #define NM_SETTING_INFINIBAND_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_INFINIBAND, NMSettingInfinibandPrivate))
45
46 typedef struct {
47         char *mac_address;
48         char *transport_mode;
49         guint32 mtu;
50         int p_key;
51         char *parent, *virtual_iface_name;
52 } NMSettingInfinibandPrivate;
53
54 enum {
55         PROP_0,
56         PROP_MAC_ADDRESS,
57         PROP_MTU,
58         PROP_TRANSPORT_MODE,
59         PROP_P_KEY,
60         PROP_PARENT,
61
62         LAST_PROP
63 };
64
65 /**
66  * nm_setting_infiniband_new:
67  *
68  * Creates a new #NMSettingInfiniband object with default values.
69  *
70  * Returns: (transfer full): the new empty #NMSettingInfiniband object
71  **/
72 NMSetting *
73 nm_setting_infiniband_new (void)
74 {
75         return (NMSetting *) g_object_new (NM_TYPE_SETTING_INFINIBAND, NULL);
76 }
77
78 /**
79  * nm_setting_infiniband_get_mac_address:
80  * @setting: the #NMSettingInfiniband
81  *
82  * Returns: the #NMSettingInfiniband:mac-address property of the setting
83  **/
84 const char *
85 nm_setting_infiniband_get_mac_address (NMSettingInfiniband *setting)
86 {
87         g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (setting), NULL);
88
89         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->mac_address;
90 }
91
92 /**
93  * nm_setting_infiniband_get_mtu:
94  * @setting: the #NMSettingInfiniband
95  *
96  * Returns: the #NMSettingInfiniband:mtu property of the setting
97  **/
98 guint32
99 nm_setting_infiniband_get_mtu (NMSettingInfiniband *setting)
100 {
101         g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (setting), 0);
102
103         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->mtu;
104 }
105
106 /**
107  * nm_setting_infiniband_get_transport_mode:
108  * @setting: the #NMSettingInfiniband
109  *
110  * Returns the transport mode for this device. Either 'datagram' or
111  * 'connected'.
112  *
113  * Returns: the IPoIB transport mode
114  **/
115 const char *
116 nm_setting_infiniband_get_transport_mode (NMSettingInfiniband *setting)
117 {
118         g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (setting), NULL);
119
120         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->transport_mode;
121 }
122
123 /**
124  * nm_setting_infiniband_get_p_key:
125  * @setting: the #NMSettingInfiniband
126  *
127  * Returns the P_Key to use for this device. A value of -1 means to
128  * use the default P_Key (aka "the P_Key at index 0"). Otherwise it is
129  * a 16-bit unsigned integer.
130  *
131  * Returns: the IPoIB P_Key
132  **/
133 int
134 nm_setting_infiniband_get_p_key (NMSettingInfiniband *setting)
135 {
136         g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (setting), -1);
137
138         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->p_key;
139 }
140
141 /**
142  * nm_setting_infiniband_get_parent:
143  * @setting: the #NMSettingInfiniband
144  *
145  * Returns the parent interface name for this device, if set.
146  *
147  * Returns: the parent interface name
148  **/
149 const char *
150 nm_setting_infiniband_get_parent (NMSettingInfiniband *setting)
151 {
152         g_return_val_if_fail (NM_IS_SETTING_INFINIBAND (setting), NULL);
153
154         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->parent;
155 }
156
157 /**
158  * nm_setting_infiniband_get_virtual_interface_name:
159  * @setting: the #NMSettingInfiniband
160  *
161  * Returns the interface name created by combining #NMSettingInfiniband:parent
162  * and #NMSettingInfiniband:p-key. (If either property is unset, this will
163  * return %NULL.)
164  *
165  * Returns: the interface name, or %NULL
166  **/
167 const char *
168 nm_setting_infiniband_get_virtual_interface_name (NMSettingInfiniband *setting)
169 {
170         NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (setting);
171
172         if (priv->p_key == -1 || !priv->parent)
173                 return NULL;
174
175         if (!priv->virtual_iface_name)
176                 priv->virtual_iface_name = g_strdup_printf ("%s.%04x", priv->parent, priv->p_key);
177
178         return NM_SETTING_INFINIBAND_GET_PRIVATE (setting)->virtual_iface_name;
179 }
180
181 static gboolean
182 verify (NMSetting *setting, NMConnection *connection, GError **error)
183 {
184         NMSettingConnection *s_con;
185         NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (setting);
186         guint32 normerr_max_mtu = 0;
187
188         if (priv->mac_address && !nm_utils_hwaddr_valid (priv->mac_address, INFINIBAND_ALEN)) {
189                 g_set_error_literal (error,
190                                      NM_CONNECTION_ERROR,
191                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
192                                      _("property is invalid"));
193                 g_prefix_error (error, "%s.%s: ", NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MAC_ADDRESS);
194                 return FALSE;
195         }
196
197         if (!g_strcmp0 (priv->transport_mode, "datagram")) {
198                 if (priv->mtu > 2044)
199                         normerr_max_mtu = 2044;
200         } else if (!g_strcmp0 (priv->transport_mode, "connected")) {
201                 if (priv->mtu > 65520)
202                         normerr_max_mtu = 65520;
203         } else {
204                 g_set_error_literal (error,
205                                      NM_CONNECTION_ERROR,
206                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
207                                      _("property is invalid"));
208                 g_prefix_error (error, "%s.%s: ", NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_TRANSPORT_MODE);
209                 return FALSE;
210         }
211
212         if (priv->parent) {
213                 if (!nm_utils_iface_valid_name (priv->parent)) {
214                         g_set_error_literal (error,
215                                              NM_CONNECTION_ERROR,
216                                              NM_CONNECTION_ERROR_INVALID_PROPERTY,
217                                              _("not a valid interface name"));
218                         g_prefix_error (error, "%s: ", NM_SETTING_INFINIBAND_PARENT);
219                         return FALSE;
220                 }
221                 if (priv->p_key == -1) {
222                         g_set_error_literal (error,
223                                              NM_CONNECTION_ERROR,
224                                              NM_CONNECTION_ERROR_INVALID_PROPERTY,
225                                              _("Must specify a P_Key if specifying parent"));
226                         g_prefix_error (error, "%s: ", NM_SETTING_INFINIBAND_PARENT);
227                 }
228         }
229
230         if (priv->p_key != -1) {
231                 if (!priv->mac_address && !priv->parent) {
232                         g_set_error_literal (error,
233                                              NM_CONNECTION_ERROR,
234                                              NM_CONNECTION_ERROR_MISSING_PROPERTY,
235                                              _("InfiniBand P_Key connection did not specify parent interface name"));
236                         g_prefix_error (error, "%s: ", NM_SETTING_INFINIBAND_PARENT);
237                         return FALSE;
238                 }
239         }
240
241         s_con = nm_connection_get_setting_connection (connection);
242         if (s_con) {
243                 const char *interface_name = nm_setting_connection_get_interface_name (s_con);
244
245                 if (!interface_name)
246                         ;
247                 else if (!nm_utils_iface_valid_name (interface_name)) {
248                         /* report the error for NMSettingConnection:interface-name, because
249                          * it's that property that is invalid -- although we currently verify()
250                          * NMSettingInfiniband.
251                          **/
252                         g_set_error (error,
253                                      NM_CONNECTION_ERROR,
254                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
255                                      _("'%s' is not a valid interface name"),
256                                      interface_name);
257                         g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME);
258                         return FALSE;
259                 } else {
260                         if (priv->p_key != -1) {
261                                 if (!priv->virtual_iface_name)
262                                         priv->virtual_iface_name = g_strdup_printf ("%s.%04x", priv->parent, priv->p_key);
263
264                                 if (strcmp (interface_name, priv->virtual_iface_name) != 0) {
265                                         /* We don't support renaming software infiniband devices. Later we might, but
266                                          * for now just reject such connections.
267                                          **/
268                                         g_set_error (error,
269                                                      NM_CONNECTION_ERROR,
270                                                      NM_CONNECTION_ERROR_INVALID_PROPERTY,
271                                                      _("interface name of software infiniband device must be '%s' or unset (instead it is '%s')"),
272                                                      priv->virtual_iface_name, interface_name);
273                                         g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_INTERFACE_NAME);
274                                         return FALSE;
275                                 }
276                         }
277                 }
278         }
279
280         /* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
281
282         if (normerr_max_mtu > 0) {
283                 g_set_error (error,
284                              NM_CONNECTION_ERROR,
285                              NM_CONNECTION_ERROR_INVALID_PROPERTY,
286                              _("mtu for transport mode '%s' can be at most %d but it is %d"),
287                              priv->transport_mode, normerr_max_mtu, priv->mtu);
288                 g_prefix_error (error, "%s.%s: ", NM_SETTING_INFINIBAND_SETTING_NAME, NM_SETTING_INFINIBAND_MTU);
289                 return NM_SETTING_VERIFY_NORMALIZABLE_ERROR;
290         }
291
292         return TRUE;
293 }
294
295 static void
296 nm_setting_infiniband_init (NMSettingInfiniband *setting)
297 {
298 }
299
300 static void
301 finalize (GObject *object)
302 {
303         NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (object);
304
305         g_free (priv->transport_mode);
306         g_free (priv->mac_address);
307         g_free (priv->parent);
308         g_free (priv->virtual_iface_name);
309
310         G_OBJECT_CLASS (nm_setting_infiniband_parent_class)->finalize (object);
311 }
312
313 static void
314 set_property (GObject *object, guint prop_id,
315               const GValue *value, GParamSpec *pspec)
316 {
317         NMSettingInfinibandPrivate *priv = NM_SETTING_INFINIBAND_GET_PRIVATE (object);
318
319         switch (prop_id) {
320         case PROP_MAC_ADDRESS:
321                 g_free (priv->mac_address);
322                 priv->mac_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value),
323                                                                            INFINIBAND_ALEN);
324                 break;
325         case PROP_MTU:
326                 priv->mtu = g_value_get_uint (value);
327                 break;
328         case PROP_TRANSPORT_MODE:
329                 g_free (priv->transport_mode);
330                 priv->transport_mode = g_value_dup_string (value);
331                 break;
332         case PROP_P_KEY:
333                 priv->p_key = g_value_get_int (value);
334                 g_clear_pointer (&priv->virtual_iface_name, g_free);
335                 break;
336         case PROP_PARENT:
337                 g_free (priv->parent);
338                 priv->parent = g_value_dup_string (value);
339                 g_clear_pointer (&priv->virtual_iface_name, g_free);
340                 break;
341         default:
342                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343                 break;
344         }
345 }
346
347 static void
348 get_property (GObject *object, guint prop_id,
349               GValue *value, GParamSpec *pspec)
350 {
351         NMSettingInfiniband *setting = NM_SETTING_INFINIBAND (object);
352
353         switch (prop_id) {
354         case PROP_MAC_ADDRESS:
355                 g_value_set_string (value, nm_setting_infiniband_get_mac_address (setting));
356                 break;
357         case PROP_MTU:
358                 g_value_set_uint (value, nm_setting_infiniband_get_mtu (setting));
359                 break;
360         case PROP_TRANSPORT_MODE:
361                 g_value_set_string (value, nm_setting_infiniband_get_transport_mode (setting));
362                 break;
363         case PROP_P_KEY:
364                 g_value_set_int (value, nm_setting_infiniband_get_p_key (setting));
365                 break;
366         case PROP_PARENT:
367                 g_value_set_string (value, nm_setting_infiniband_get_parent (setting));
368                 break;
369         default:
370                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371                 break;
372         }
373 }
374
375 static void
376 nm_setting_infiniband_class_init (NMSettingInfinibandClass *setting_class)
377 {
378         GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
379         NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
380
381         g_type_class_add_private (setting_class, sizeof (NMSettingInfinibandPrivate));
382
383         /* virtual methods */
384         object_class->set_property = set_property;
385         object_class->get_property = get_property;
386         object_class->finalize     = finalize;
387
388         parent_class->verify       = verify;
389
390         /* Properties */
391         /**
392          * NMSettingInfiniband:mac-address:
393          *
394          * If specified, this connection will only apply to the IPoIB device whose
395          * permanent MAC address matches. This property does not change the MAC
396          * address of the device (i.e. MAC spoofing).
397          **/
398         /* ---keyfile---
399          * property: mac-address
400          * format: ususal hex-digits-and-colons notation
401          * description: MAC address in traditional hex-digits-and-colons notation, or
402          *   or semicolon separated list of 20 decimal bytes (obsolete)
403          * example: mac-address= 80:00:00:6d:fe:80:00:00:00:00:00:00:00:02:55:00:70:33:cf:01
404          * ---end---
405          * ---ifcfg-rh---
406          * property: mac-address
407          * variable: HWADDR
408          * description: IBoIP 20-byte hardware address of the device (in traditional
409          *   hex-digits-and-colons notation).
410          * example: HWADDR=01:02:03:04:05:06:07:08:09:0A:01:02:03:04:05:06:07:08:09:11
411          * ---end---
412          */
413         g_object_class_install_property
414                 (object_class, PROP_MAC_ADDRESS,
415                  g_param_spec_string (NM_SETTING_INFINIBAND_MAC_ADDRESS, "", "",
416                                       NULL,
417                                       G_PARAM_READWRITE |
418                                       NM_SETTING_PARAM_INFERRABLE |
419                                       G_PARAM_STATIC_STRINGS));
420         _nm_setting_class_transform_property (parent_class, NM_SETTING_INFINIBAND_MAC_ADDRESS,
421                                               G_VARIANT_TYPE_BYTESTRING,
422                                               _nm_utils_hwaddr_to_dbus,
423                                               _nm_utils_hwaddr_from_dbus);
424
425         /**
426          * NMSettingInfiniband:mtu:
427          *
428          * If non-zero, only transmit packets of the specified size or smaller,
429          * breaking larger packets up into multiple frames.
430          **/
431         /* ---ifcfg-rh---
432          * property: mtu
433          * variable: MTU
434          * description: MTU of the interface.
435          * ---end---
436          */
437         g_object_class_install_property
438                 (object_class, PROP_MTU,
439                  g_param_spec_uint (NM_SETTING_INFINIBAND_MTU, "", "",
440                                     0, G_MAXUINT32, 0,
441                                     G_PARAM_READWRITE |
442                                     G_PARAM_CONSTRUCT |
443                                     NM_SETTING_PARAM_FUZZY_IGNORE |
444                                     G_PARAM_STATIC_STRINGS));
445
446         /**
447          * NMSettingInfiniband:transport-mode:
448          *
449          * The IP-over-InfiniBand transport mode. Either "datagram" or
450          * "connected".
451          **/
452         /* ---ifcfg-rh---
453          * property: transport-mode
454          * variable: CONNECTED_MODE
455          * default: CONNECTED_MODE=no
456          * description: CONNECTED_MODE=yes for "connected" mode, CONNECTED_MODE=no for
457          *   "datagram" mode
458          * ---end---
459          */
460         g_object_class_install_property
461                 (object_class, PROP_TRANSPORT_MODE,
462                  g_param_spec_string (NM_SETTING_INFINIBAND_TRANSPORT_MODE, "", "",
463                                       NULL,
464                                       G_PARAM_READWRITE |
465                                       G_PARAM_CONSTRUCT |
466                                       NM_SETTING_PARAM_INFERRABLE |
467                                       G_PARAM_STATIC_STRINGS));
468
469         /**
470          * NMSettingInfiniband:p-key:
471          *
472          * The InfiniBand P_Key to use for this device. A value of -1 means to use
473          * the default P_Key (aka "the P_Key at index 0").  Otherwise it is a 16-bit
474          * unsigned integer, whose high bit is set if it is a "full membership"
475          * P_Key.
476          **/
477         /* ---ifcfg-rh---
478          * property: p-key
479          * variable: PKEY_ID (and PKEY=yes)
480          * default: PKEY=no
481          * description: InfiniBand P_Key. The value can be a hex number prefixed with "0x"
482          *   or a decimal number.
483          *   When PKEY_ID is specified, PHYSDEV and DEVICE also must be specified.
484          * example: PKEY=yes PKEY_ID=2 PHYSDEV=mlx4_ib0 DEVICE=mlx4_ib0.8002
485          * ---end---
486          */
487         g_object_class_install_property
488                 (object_class, PROP_P_KEY,
489                  g_param_spec_int (NM_SETTING_INFINIBAND_P_KEY, "", "",
490                                    -1, 0xFFFF, -1,
491                                    G_PARAM_READWRITE |
492                                    G_PARAM_CONSTRUCT |
493                                    NM_SETTING_PARAM_INFERRABLE |
494                                    G_PARAM_STATIC_STRINGS));
495
496         /**
497          * NMSettingInfiniband:parent:
498          *
499          * The interface name of the parent device of this device. Normally %NULL,
500          * but if the #NMSettingInfiniband:p_key property is set, then you must
501          * specify the base device by setting either this property or
502          * #NMSettingInfiniband:mac-address.
503          **/
504         /* ---ifcfg-rh---
505          * property: parent
506          * variable: PHYSDEV (PKEY=yes)
507          * default: PKEY=no
508          * description: InfiniBand parent device.
509          * example: PHYSDEV=ib0
510          * ---end---
511          */
512         g_object_class_install_property
513                 (object_class, PROP_PARENT,
514                  g_param_spec_string (NM_SETTING_INFINIBAND_PARENT, "", "",
515                                       NULL,
516                                       G_PARAM_READWRITE |
517                                       G_PARAM_CONSTRUCT |
518                                       NM_SETTING_PARAM_INFERRABLE |
519                                       G_PARAM_STATIC_STRINGS));
520
521 }