diff options
Diffstat (limited to 'src/devices/ovs')
| -rw-r--r-- | src/devices/ovs/meson.build | 2 | ||||
| -rw-r--r-- | src/devices/ovs/nm-device-ovs-interface.c | 39 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovsdb.c | 172 | ||||
| -rw-r--r-- | src/devices/ovs/nm-ovsdb.h | 3 |
4 files changed, 173 insertions, 43 deletions
diff --git a/src/devices/ovs/meson.build b/src/devices/ovs/meson.build index 27e1b4d0..8457e68a 100644 --- a/src/devices/ovs/meson.build +++ b/src/devices/ovs/meson.build @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1+ + sources = files( 'nm-device-ovs-bridge.c', 'nm-device-ovs-interface.c', diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c index 2868dee0..951b5788 100644 --- a/src/devices/ovs/nm-device-ovs-interface.c +++ b/src/devices/ovs/nm-device-ovs-interface.c @@ -121,6 +121,43 @@ _is_internal_interface (NMDevice *device) return nm_streq (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), "internal"); } +static void +set_platform_mtu_cb (GError *error, gpointer user_data) +{ + NMDevice *device = user_data; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE (device); + + if ( error + && !g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { + _LOGW (LOGD_DEVICE, "could not change mtu of '%s': %s", + nm_device_get_iface (device), error->message); + } + + g_object_unref (device); +} + +static gboolean +set_platform_mtu (NMDevice *device, guint32 mtu) +{ + /* + * If the MTU is not set in ovsdb, Open vSwitch will change + * the MTU of an internal interface to match the minimum of + * the other interfaces in the bridge. + */ + /* FIXME(shutdown): the function should become cancellable so + * that it doesn't need to hold a reference to the device, and + * it can be stopped during shutdown. + */ + if (_is_internal_interface (device)) { + nm_ovsdb_set_interface_mtu (nm_ovsdb_get (), + nm_device_get_ip_iface (device), + mtu, set_platform_mtu_cb, + g_object_ref (device)); + } + + return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->set_platform_mtu (device, mtu); +} + static NMActStageReturn act_stage3_ip_config_start (NMDevice *device, int addr_family, @@ -351,4 +388,6 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass) device_class->link_changed = link_changed; device_class->act_stage3_ip_config_start = act_stage3_ip_config_start; device_class->can_unmanaged_external_down = can_unmanaged_external_down; + device_class->set_platform_mtu = set_platform_mtu; + device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; } diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c index ec4f5c74..b6550b25 100644 --- a/src/devices/ovs/nm-ovsdb.c +++ b/src/devices/ovs/nm-ovsdb.c @@ -64,6 +64,7 @@ typedef struct { GHashTable *ports; /* port uuid => OpenvswitchPort */ GHashTable *bridges; /* bridge uuid => OpenvswitchBridge */ char *db_uuid; + guint num_failures; } NMOvsdbPrivate; struct _NMOvsdb { @@ -87,7 +88,7 @@ NM_DEFINE_SINGLETON_GETTER (NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB); /*****************************************************************************/ static void ovsdb_try_connect (NMOvsdb *self); -static void ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing); +static void ovsdb_disconnect (NMOvsdb *self, gboolean retry, gboolean is_disposing); static void ovsdb_read (NMOvsdb *self); static void ovsdb_write (NMOvsdb *self); static void ovsdb_next_command (NMOvsdb *self); @@ -103,6 +104,7 @@ typedef enum { OVSDB_MONITOR, OVSDB_ADD_INTERFACE, OVSDB_DEL_INTERFACE, + OVSDB_SET_INTERFACE_MTU, } OvsdbCommand; typedef struct { @@ -112,7 +114,10 @@ typedef struct { OvsdbMethodCallback callback; gpointer user_data; union { - char *ifname; + struct { + char *ifname; + guint32 mtu; + }; struct { NMConnection *bridge; NMConnection *port; @@ -123,6 +128,8 @@ typedef struct { }; } OvsdbMethodCall; +#define OVSDB_MAX_FAILURES 3 + static void _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) { @@ -154,6 +161,13 @@ _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg) msg ? ": " : "", msg ? str : ""); break; + case OVSDB_SET_INTERFACE_MTU: + _LOGT ("%s: set-iface-mtu interface=%s%s%s mtu=%u", + comment, call->ifname, + msg ? ": " : "", + msg ? str : "", + call->mtu); + break; } if (msg) @@ -172,7 +186,8 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, const char *ifname, NMConnection *bridge, NMConnection *port, NMConnection *interface, NMDevice *bridge_device, NMDevice *interface_device, - OvsdbMethodCallback callback, gpointer user_data) + guint32 mtu, OvsdbMethodCallback callback, gpointer user_data, + gboolean add_first) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); OvsdbMethodCall *call; @@ -180,8 +195,13 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, /* Ensure we're not unsynchronized before we queue the method call. */ ovsdb_try_connect (self); - g_array_set_size (priv->calls, priv->calls->len + 1); - call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + if (add_first) { + g_array_prepend_val (priv->calls, (OvsdbMethodCall) {}); + call = &g_array_index (priv->calls, OvsdbMethodCall, 0); + } else { + g_array_set_size (priv->calls, priv->calls->len + 1); + call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + } call->id = COMMAND_PENDING; call->command = command; call->callback = callback; @@ -200,6 +220,10 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command, case OVSDB_DEL_INTERFACE: call->ifname = g_strdup (ifname); break; + case OVSDB_SET_INTERFACE_MTU: + call->ifname = g_strdup (ifname); + call->mtu = mtu; + break; } _call_trace ("enqueue", call, NULL); @@ -338,11 +362,20 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_ gs_free char *cloned_mac = NULL; gs_free_error GError *error = NULL; json_t *row; + guint32 mtu = 0; s_ovs_iface = nm_connection_get_setting_ovs_interface (interface); if (s_ovs_iface) type = nm_setting_ovs_interface_get_interface_type (s_ovs_iface); + if (nm_streq0 (type, "internal")) { + NMSettingWired *s_wired; + + s_wired = _nm_connection_get_setting (interface, NM_TYPE_SETTING_WIRED); + if (s_wired) + mtu = nm_setting_wired_get_mtu (s_wired); + } + if (!nm_device_hw_addr_get_cloned (interface_device, interface, FALSE, @@ -384,6 +417,9 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_ if (cloned_mac) json_object_set_new (row, "mac", json_string (cloned_mac)); + if (mtu != 0) + json_object_set_new (row, "mtu_request", json_integer (mtu)); + json_array_append_new (params, json_pack ("{s:s, s:s, s:o, s:s}", "op", "insert", @@ -820,6 +856,22 @@ ovsdb_next_command (NMOvsdb *self) "id", call->id, "method", "transact", "params", params); break; + case OVSDB_SET_INTERFACE_MTU: + params = json_array (); + json_array_append_new (params, json_string ("Open_vSwitch")); + json_array_append_new (params, _inc_next_cfg (priv->db_uuid)); + + json_array_append_new (params, + json_pack ("{s:s, s:s, s:{s: i}, s:[[s, s, s]]}", + "op", "update", + "table", "Interface", + "row", "mtu_request", call->mtu, + "where", "name", "==", call->ifname)); + + msg = json_pack ("{s:i, s:s, s:o}", + "id", call->id, + "method", "transact", "params", params); + break; } g_return_if_fail (msg); @@ -1153,7 +1205,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) "result", &result, "error", &error) == -1) { _LOGW ("couldn't grok the message: %s", json_error.text); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } @@ -1164,7 +1216,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) /* It's a method call! */ if (!params) { _LOGW ("a method call with no params: '%s'", method); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } @@ -1184,13 +1236,13 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) /* This is a response to a method call. */ if (!priv->calls->len) { _LOGE ("there are no queued calls expecting response %" G_GUINT64_FORMAT, id); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } call = &g_array_index (priv->calls, OvsdbMethodCall, 0); if (call->id != id) { _LOGE ("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT, call->id, id); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); return; } /* Cool, we found a corresponding call. Finish it. */ @@ -1208,6 +1260,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg) user_data = call->user_data; g_array_remove_index (priv->calls, 0); callback (self, result, local, user_data); + priv->num_failures = 0; /* Don't progress further commands in case the callback hit an error * and disconnected us. */ @@ -1266,9 +1319,11 @@ ovsdb_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) size = g_input_stream_read_finish (stream, res, &error); if (size == -1) { + /* ovsdb-server was possibly restarted */ _LOGW ("short read from ovsdb: %s", error->message); + priv->num_failures++; g_clear_error (&error); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); return; } @@ -1314,9 +1369,11 @@ ovsdb_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) size = g_output_stream_write_finish (stream, res, &error); if (size == -1) { + /* ovsdb-server was possibly restarted */ _LOGW ("short write to ovsdb: %s", error->message); + priv->num_failures++; g_clear_error (&error); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE); return; } @@ -1359,7 +1416,7 @@ ovsdb_write (NMOvsdb *self) * puts us back in sync. */ static void -ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) +ovsdb_disconnect (NMOvsdb *self, gboolean retry, gboolean is_disposing) { NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); OvsdbMethodCall *call; @@ -1367,18 +1424,26 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) gpointer user_data; gs_free_error GError *error = NULL; + nm_assert (!retry || !is_disposing); + if (!priv->client) return; - _LOGD ("disconnecting from ovsdb"); - nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb"); + _LOGD ("disconnecting from ovsdb, retry %d", retry); - while (priv->calls->len) { - call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); - callback = call->callback; - user_data = call->user_data; - g_array_remove_index (priv->calls, priv->calls->len - 1); - callback (self, NULL, error, user_data); + if (retry) { + if (priv->calls->len != 0) + g_array_index (priv->calls, OvsdbMethodCall, 0).id = COMMAND_PENDING; + } else { + nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb"); + + while (priv->calls->len) { + call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1); + callback = call->callback; + user_data = call->user_data; + g_array_remove_index (priv->calls, priv->calls->len - 1); + callback (self, NULL, error, user_data); + } } priv->bufp = 0; @@ -1386,17 +1451,20 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing) g_string_truncate (priv->output, 0); g_clear_object (&priv->client); g_clear_object (&priv->conn); - g_clear_pointer (&priv->db_uuid, g_free); + nm_clear_g_free (&priv->db_uuid); nm_clear_g_cancellable (&priv->cancellable); + + if (retry) + ovsdb_try_connect (self); } static void _monitor_bridges_cb (NMOvsdb *self, json_t *result, GError *error, gpointer user_data) { if (error) { - if (!nm_utils_error_is_cancelled (error, TRUE)) { + if (!nm_utils_error_is_cancelled_or_disposing (error)) { _LOGI ("%s", error->message); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); } return; } @@ -1420,7 +1488,7 @@ _client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) _LOGI ("%s", error->message); - ovsdb_disconnect (self, FALSE); + ovsdb_disconnect (self, FALSE, FALSE); g_clear_error (&error); return; } @@ -1461,7 +1529,8 @@ ovsdb_try_connect (NMOvsdb *self) /* Queue a monitor call before any other command, ensuring that we have an up * to date view of existing bridged that we need for add and remove ops. */ ovsdb_call_method (self, OVSDB_MONITOR, NULL, - NULL, NULL, NULL, NULL, NULL, _monitor_bridges_cb, NULL); + NULL, NULL, NULL, NULL, NULL, 0, + _monitor_bridges_cb, NULL, TRUE); } /*****************************************************************************/ @@ -1499,11 +1568,8 @@ out: g_slice_free (OvsdbCall, call); } -void -nm_ovsdb_add_interface (NMOvsdb *self, - NMConnection *bridge, NMConnection *port, NMConnection *interface, - NMDevice *bridge_device, NMDevice *interface_device, - NMOvsdbCallback callback, gpointer user_data) +static OvsdbCall * +ovsdb_call_new (NMOvsdbCallback callback, gpointer user_data) { OvsdbCall *call; @@ -1511,24 +1577,43 @@ nm_ovsdb_add_interface (NMOvsdb *self, call->callback = callback; call->user_data = user_data; + return call; +} + +void +nm_ovsdb_add_interface (NMOvsdb *self, + NMConnection *bridge, NMConnection *port, NMConnection *interface, + NMDevice *bridge_device, NMDevice *interface_device, + NMOvsdbCallback callback, gpointer user_data) +{ ovsdb_call_method (self, OVSDB_ADD_INTERFACE, NULL, bridge, port, interface, bridge_device, interface_device, - _transact_cb, call); + 0, + _transact_cb, + ovsdb_call_new (callback, user_data), + FALSE); } void nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname, NMOvsdbCallback callback, gpointer user_data) { - OvsdbCall *call; - - call = g_slice_new (OvsdbCall); - call->callback = callback; - call->user_data = user_data; - ovsdb_call_method (self, OVSDB_DEL_INTERFACE, ifname, - NULL, NULL, NULL, NULL, NULL, _transact_cb, call); + NULL, NULL, NULL, NULL, NULL, 0, + _transact_cb, + ovsdb_call_new (callback, user_data), + FALSE); +} + +void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu, + NMOvsdbCallback callback, gpointer user_data) +{ + ovsdb_call_method (self, OVSDB_SET_INTERFACE_MTU, ifname, + NULL, NULL, NULL, NULL, NULL, mtu, + _transact_cb, + ovsdb_call_new (callback, user_data), + FALSE); } /*****************************************************************************/ @@ -1549,7 +1634,8 @@ _clear_call (gpointer data) g_clear_object (&call->interface_device); break; case OVSDB_DEL_INTERFACE: - g_clear_pointer (&call->ifname, g_free); + case OVSDB_SET_INTERFACE_MTU: + nm_clear_g_free (&call->ifname); break; } } @@ -1609,7 +1695,7 @@ dispose (GObject *object) NMOvsdb *self = NM_OVSDB (object); NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self); - ovsdb_disconnect (self, TRUE); + ovsdb_disconnect (self, FALSE, TRUE); if (priv->input) { g_string_free (priv->input, TRUE); @@ -1624,9 +1710,9 @@ dispose (GObject *object) priv->calls = NULL; } - g_clear_pointer (&priv->bridges, g_hash_table_destroy); - g_clear_pointer (&priv->ports, g_hash_table_destroy); - g_clear_pointer (&priv->interfaces, g_hash_table_destroy); + nm_clear_pointer (&priv->bridges, g_hash_table_destroy); + nm_clear_pointer (&priv->ports, g_hash_table_destroy); + nm_clear_pointer (&priv->interfaces, g_hash_table_destroy); G_OBJECT_CLASS (nm_ovsdb_parent_class)->dispose (object); } diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h index 59f46206..72a2dc73 100644 --- a/src/devices/ovs/nm-ovsdb.h +++ b/src/devices/ovs/nm-ovsdb.h @@ -34,4 +34,7 @@ void nm_ovsdb_add_interface (NMOvsdb *self, void nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname, NMOvsdbCallback callback, gpointer user_data); +void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu, + NMOvsdbCallback callback, gpointer user_data); + #endif /* __NETWORKMANAGER_OVSDB_H__ */ |