diff options
Diffstat (limited to 'src/core/devices')
| -rw-r--r-- | src/core/devices/nm-device-6lowpan.c | 9 | ||||
| -rw-r--r-- | src/core/devices/nm-device-ipvlan.c | 11 | ||||
| -rw-r--r-- | src/core/devices/nm-device-macsec.c | 9 | ||||
| -rw-r--r-- | src/core/devices/nm-device-macvlan.c | 11 | ||||
| -rw-r--r-- | src/core/devices/nm-device-vlan.c | 11 | ||||
| -rw-r--r-- | src/core/devices/nm-device-wireguard.c | 56 | ||||
| -rw-r--r-- | src/core/devices/nm-device.c | 43 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-device-ovs-bridge.c | 26 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-device-ovs-interface.c | 100 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-device-ovs-port.c | 27 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-ovsdb.c | 300 | ||||
| -rw-r--r-- | src/core/devices/ovs/nm-ovsdb.h | 2 |
12 files changed, 361 insertions, 244 deletions
diff --git a/src/core/devices/nm-device-6lowpan.c b/src/core/devices/nm-device-6lowpan.c index 3dabcb9b..61b1e4ee 100644 --- a/src/core/devices/nm-device-6lowpan.c +++ b/src/core/devices/nm-device-6lowpan.c @@ -138,14 +138,6 @@ link_changed(NMDevice *device, const NMPlatformLink *pllink) } static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_6lowpan_parent_class)->is_available(device, flags); -} - -static gboolean complete_connection(NMDevice *device, NMConnection *connection, const char *specific_object, @@ -237,7 +229,6 @@ nm_device_6lowpan_class_init(NMDevice6LowpanClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; device_class->link_changed = link_changed; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->update_connection = update_connection; } diff --git a/src/core/devices/nm-device-ipvlan.c b/src/core/devices/nm-device-ipvlan.c index 00a1b579..abeb82f7 100644 --- a/src/core/devices/nm-device-ipvlan.c +++ b/src/core/devices/nm-device-ipvlan.c @@ -222,16 +222,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_ipvlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - -static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, gboolean check_properties, @@ -376,7 +366,6 @@ nm_device_ipvlan_class_init(NMDeviceIpvlanClass *klass) device_class->check_connection_compatible = check_connection_compatible; device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; - device_class->is_available = is_available; device_class->link_changed = link_changed; device_class->update_connection = update_connection; diff --git a/src/core/devices/nm-device-macsec.c b/src/core/devices/nm-device-macsec.c index 89a06720..2ff1eeb3 100644 --- a/src/core/devices/nm-device-macsec.c +++ b/src/core/devices/nm-device-macsec.c @@ -684,14 +684,6 @@ get_generic_capabilities(NMDevice *dev) /******************************************************************/ static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macsec_parent_class)->is_available(device, flags); -} - -static gboolean create_and_realize(NMDevice *device, NMConnection *connection, NMDevice *parent, @@ -903,7 +895,6 @@ nm_device_macsec_class_init(NMDeviceMacsecClass *klass) device_class->deactivate = deactivate; device_class->get_generic_capabilities = get_generic_capabilities; device_class->link_changed = link_changed; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->state_changed = device_state_changed; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; diff --git a/src/core/devices/nm-device-macvlan.c b/src/core/devices/nm-device-macvlan.c index 9501e8f1..c5bcc91a 100644 --- a/src/core/devices/nm-device-macvlan.c +++ b/src/core/devices/nm-device-macvlan.c @@ -271,16 +271,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_macvlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - -static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, gboolean check_properties, @@ -508,7 +498,6 @@ nm_device_macvlan_class_init(NMDeviceMacvlanClass *klass) device_class->create_and_realize = create_and_realize; device_class->get_generic_capabilities = get_generic_capabilities; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; device_class->link_changed = link_changed; device_class->parent_changed_notify = parent_changed_notify; device_class->update_connection = update_connection; diff --git a/src/core/devices/nm-device-vlan.c b/src/core/devices/nm-device-vlan.c index 59a429ca..9d03e337 100644 --- a/src/core/devices/nm-device-vlan.c +++ b/src/core/devices/nm-device-vlan.c @@ -293,16 +293,6 @@ get_generic_capabilities(NMDevice *device) /*****************************************************************************/ static gboolean -is_available(NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - if (!nm_device_parent_get_device(device)) - return FALSE; - return NM_DEVICE_CLASS(nm_device_vlan_parent_class)->is_available(device, flags); -} - -/*****************************************************************************/ - -static gboolean check_connection_compatible(NMDevice *device, NMConnection *connection, gboolean check_properties, @@ -561,7 +551,6 @@ nm_device_vlan_class_init(NMDeviceVlanClass *klass) device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; device_class->act_stage1_prepare = act_stage1_prepare; device_class->get_configured_mtu = nm_device_get_configured_mtu_wired_parent; - device_class->is_available = is_available; device_class->parent_changed_notify = parent_changed_notify; device_class->check_connection_compatible = check_connection_compatible; diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 4a08192e..299e3b30 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -23,6 +23,7 @@ #include "nm-active-connection.h" #include "nm-act-request.h" #include "dns/nm-dns-manager.h" +#include "nm-firewall-utils.h" #define _NMLOG_DEVICE_TYPE NMDeviceWireGuard #include "nm-device-logging.h" @@ -1207,6 +1208,40 @@ skip: *out_allowed_ips_data = g_steal_pointer(&allowed_ips); } +static void +_configure_firewall(NMDeviceWireGuard *self, NMConnection *connection, int addr_family, gboolean up) +{ + NMDeviceWireGuardPrivate *priv = NM_DEVICE_WIREGUARD_GET_PRIVATE(self); + const char *ip_iface; + NMSettingIPConfig *ip_config; + + ip_iface = nm_device_get_ip_iface(NM_DEVICE(self)); + + nm_assert(ip_iface); + + switch (addr_family) { + case AF_INET: + if (!priv->auto_default_route_enabled_4) + return; + + ip_config = nm_connection_get_setting_ip4_config(connection); + break; + case AF_INET6: + if (!priv->auto_default_route_enabled_6) + return; + + ip_config = nm_connection_get_setting_ip6_config(connection); + break; + default: + nm_assert_not_reached(); + } + + nm_assert(ip_config); + nm_assert(priv->auto_default_route_fwmark); + + nm_firewall_config_set_wg_rule(ip_iface, ip_config, priv->auto_default_route_fwmark, up); +} + /*****************************************************************************/ static void @@ -1300,6 +1335,18 @@ create_and_realize(NMDevice *device, return TRUE; } +static void +deactivate(NMDevice *device) +{ + NMDeviceWireGuard *self = NM_DEVICE_WIREGUARD(device); + NMConnection *connection = nm_device_get_applied_connection(NM_DEVICE(self)); + + if (connection) { + _configure_firewall(self, connection, AF_INET, FALSE); + _configure_firewall(self, connection, AF_INET6, FALSE); + } +} + /*****************************************************************************/ static void @@ -1768,6 +1815,10 @@ act_stage3_ip_config(NMDevice *device, int addr_family) nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL; l3cd = _get_dev2_ip_config(NM_DEVICE_WIREGUARD(device), addr_family); + _configure_firewall(NM_DEVICE_WIREGUARD(device), + nm_device_get_applied_connection(device), + addr_family, + TRUE); nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, l3cd); } @@ -1866,6 +1917,10 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne if (state >= NM_DEVICE_STATE_CONFIG) { priv->auto_default_route_refresh = TRUE; + + _configure_firewall(self, con_old, AF_INET, FALSE); + _configure_firewall(self, con_old, AF_INET6, FALSE); + link_config(NM_DEVICE_WIREGUARD(device), "reapply", LINK_CONFIG_MODE_REAPPLY, NULL); } @@ -2018,6 +2073,7 @@ nm_device_wireguard_class_init(NMDeviceWireGuardClass *klass) device_class->state_changed = device_state_changed; device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; device_class->act_stage2_config = act_stage2_config; device_class->act_stage2_config_also_for_external_or_assume = TRUE; device_class->act_stage3_ip_config = act_stage3_ip_config; diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index e310a9c6..2f2f25a5 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -603,6 +603,7 @@ typedef struct _NMDevicePrivate { bool is_attached : 1; + bool device_link_carrier_changed_down : 1; bool device_link_changed_down : 1; bool concheck_rp_filter_checked : 1; @@ -2759,22 +2760,23 @@ _ethtool_fec_set(NMDevice *self, g_hash_table_iter_init(&iter, hash); while (g_hash_table_iter_next(&iter, (gpointer *) &name, (gpointer *) &variant)) { - NMEthtoolID ethtool_id = nm_ethtool_id_get_by_name(name); - - if (!nm_ethtool_id_is_fec(ethtool_id)) - continue; - - nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); - fec_mode = g_variant_get_uint32(variant); + if (nm_ethtool_id_is_fec(nm_ethtool_id_get_by_name(name))) { + nm_assert(g_variant_is_of_type(variant, G_VARIANT_TYPE_UINT32)); + fec_mode = g_variant_get_uint32(variant); + break; + } } - nm_platform_ethtool_get_fec_mode(platform, ethtool_state->ifindex, &old_fec_mode); - /* The NM_SETTING_ETHTOOL_FEC_MODE_NONE is query only value, hence do nothing. */ if (!fec_mode || fec_mode == NM_SETTING_ETHTOOL_FEC_MODE_NONE) { return; } + if (!nm_platform_ethtool_get_fec_mode(platform, ethtool_state->ifindex, &old_fec_mode)) { + _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d: cannot get current value", fec_mode); + return; + } + if (!nm_platform_ethtool_set_fec_mode(platform, ethtool_state->ifindex, fec_mode)) _LOGW(LOGD_DEVICE, "ethtool: failure setting FEC %d", fec_mode); else { @@ -7123,6 +7125,9 @@ nm_device_controller_release_port(NMDevice *self, NM_UNMANAGED_IS_PORT, NM_UNMAN_FLAG_OP_FORGET, NM_DEVICE_STATE_REASON_REMOVED); + + /* Once the port is detached, unmanaged-external-down might change */ + _dev_unmanaged_check_external_down(self, FALSE, FALSE); } /*****************************************************************************/ @@ -7558,10 +7563,12 @@ device_link_changed(gpointer user_data) gboolean carrier_was_up; gboolean update_unmanaged_specs = FALSE; gboolean got_hw_addr = FALSE, had_hw_addr; + gboolean carrier_seen_down = priv->device_link_carrier_changed_down; gboolean seen_down = priv->device_link_changed_down; - priv->device_link_changed_id = 0; - priv->device_link_changed_down = FALSE; + priv->device_link_changed_id = 0; + priv->device_link_changed_down = FALSE; + priv->device_link_carrier_changed_down = FALSE; ifindex = nm_device_get_ifindex(self); if (ifindex <= 0) @@ -7712,7 +7719,8 @@ device_link_changed(gpointer user_data) if (priv->state >= NM_DEVICE_STATE_IP_CONFIG && priv->state <= NM_DEVICE_STATE_ACTIVATED && !nm_device_managed_type_is_external(self)) nm_device_l3cfg_commit(self, NM_L3_CFG_COMMIT_TYPE_REAPPLY, FALSE); - + } + if (priv->carrier && (!carrier_was_up || carrier_seen_down)) { /* If the device is active without a carrier (probably because it is * tagged for carrier ignore) ensure that when the carrier appears we * renew DHCP leases and such. @@ -7803,6 +7811,8 @@ link_changed_cb(NMPlatform *platform, priv = NM_DEVICE_GET_PRIVATE(self); if (ifindex == nm_device_get_ifindex(self)) { + if (!(pllink->n_ifi_flags & IFF_LOWER_UP)) + priv->device_link_carrier_changed_down = TRUE; if (!(pllink->n_ifi_flags & IFF_UP)) priv->device_link_changed_down = TRUE; if (!priv->device_link_changed_id) { @@ -8814,6 +8824,9 @@ nm_device_controller_add_port(NMDevice *self, NMDevice *port, gboolean configure } else g_return_val_if_fail(port_priv->controller == self, FALSE); + /* Once the port is attached, unmanaged-external-down might change */ + _dev_unmanaged_check_external_down(self, TRUE, FALSE); + nm_device_queue_recheck_assume(self); nm_device_queue_recheck_assume(port); @@ -13417,6 +13430,8 @@ _dev_ipsharedx_cleanup(NMDevice *self, int addr_family) nm_clear_l3cd(&priv->ipshared_data_4.v4.l3cd); _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_SHARED_4, NULL, FALSE); + } else { + _dev_l3_register_l3cds_set_one(self, L3_CONFIG_DATA_TYPE_PD_6, NULL, FALSE); } _dev_ipsharedx_set_state(self, addr_family, NM_DEVICE_IP_STATE_NONE); @@ -15085,8 +15100,8 @@ respawn_ping_cb(gpointer user_data) nm_clear_g_source_inst(&ping_op->watch); if (!spawn_ping_for_operation(self, ping_op)) { - cleanup_ping_operation(ping_op); priv->ping_operations = g_list_remove(priv->ping_operations, ping_op); + cleanup_ping_operation(ping_op); if (g_list_length(priv->ping_operations) == 0) { ip_check_pre_up(self); @@ -15129,7 +15144,6 @@ ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) if (success) { if (ping_op->ping_addresses_require_all) { - cleanup_ping_operation(ping_op); priv->ping_operations = g_list_remove(priv->ping_operations, ping_op); if (g_list_length(priv->ping_operations) == 0) { _LOGD(ping_op->log_domain, @@ -15139,6 +15153,7 @@ ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data) nm_clear_g_source_inst(&priv->ping_timeout); ip_check_pre_up(self); } + cleanup_ping_operation(ping_op); } else { nm_assert(priv->ping_operations); diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 09777669..c9b1f4c6 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -135,13 +135,36 @@ nm_device_ovs_reapply_connection(NMDevice *self, NMConnection *con_old, NMConnec nm_ovsdb_set_reapply(nm_ovsdb_get(), device_type, nm_device_get_ip_iface(self), - nm_connection_get_uuid(con_new), + nm_simple_connection_new_clone(con_new), _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_EXTERNAL_IDS), _nm_connection_get_setting(con_old, NM_TYPE_SETTING_OVS_OTHER_CONFIG), _nm_connection_get_setting(con_new, NM_TYPE_SETTING_OVS_OTHER_CONFIG)); } +static gboolean +can_reapply_change(NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS(nm_device_ovs_bridge_parent_class); + + if (nm_streq(setting_name, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + error, + NM_SETTING_OVS_BRIDGE_FAIL_MODE, + NM_SETTING_OVS_BRIDGE_MCAST_SNOOPING_ENABLE, + NM_SETTING_OVS_BRIDGE_RSTP_ENABLE, + NM_SETTING_OVS_BRIDGE_STP_ENABLE); + } + + return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); +} + /*****************************************************************************/ static void @@ -180,6 +203,7 @@ nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass) device_class->ready_for_ip_config = ready_for_ip_config; device_class->attach_port = attach_port; device_class->detach_port = detach_port; + device_class->can_reapply_change = can_reapply_change; device_class->can_reapply_change_ovs_external_ids = TRUE; device_class->reapply_connection = nm_device_ovs_reapply_connection; } diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c index 06a1da15..512aa5c3 100644 --- a/src/core/devices/ovs/nm-device-ovs-interface.c +++ b/src/core/devices/ovs/nm-device-ovs-interface.c @@ -26,16 +26,18 @@ typedef struct { NMOvsdb *ovsdb; struct { - /* The source for the idle handler to set the TUN ifindex */ - GSource *tun_set_ifindex_idle_source; - /* The cloned MAC to set */ - char *cloned_mac; - /* The id for the signal watching the TUN link to appear/change */ + /* The signal id for the TUN link-changed event */ gulong tun_link_signal_id; - /* The TUN ifindex to set in the idle handler */ + /* The idle handler source for the TUN link-changed event */ + GSource *tun_link_idle_source; + /* The ifindex for the TUN link-changed event */ int tun_ifindex; + + /* The cloned MAC to set */ + char *cloned_mac; /* Whether we have determined the cloned MAC */ bool cloned_mac_evaluated : 1; + /* Whether we are waiting for the kernel link */ bool waiting : 1; } wait_link; @@ -261,39 +263,33 @@ ready_for_ip_config(NMDevice *device, gboolean is_manual) } static gboolean -_set_ip_ifindex_tun(gpointer user_data) +_netdev_tun_link_cb_in_idle(gpointer user_data) { NMDevice *device = user_data; NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - _LOGT(LOGD_CORE, - "ovs-wait-link: setting ip-ifindex %d from tun interface", - priv->wait_link.tun_ifindex); - - nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); - - nm_device_set_ip_ifindex(device, priv->wait_link.tun_ifindex); - - if (check_waiting_for_link(device, "set-ip-ifindex-tun")) { - /* If the link is not ready, it means the MAC is not set yet. We don't have - * a convenient way to monitor for ip-ifindex changes other than listening - * for platform events again.*/ - nm_assert(!priv->wait_link.tun_link_signal_id); - priv->wait_link.tun_link_signal_id = g_signal_connect(nm_device_get_platform(device), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK(_netdev_tun_link_cb), - self); - return G_SOURCE_CONTINUE; + if (nm_device_get_ip_ifindex(device) <= 0) { + _LOGT(LOGD_CORE, + "ovs-wait-link: setting ip-ifindex %d from tun link", + priv->wait_link.tun_ifindex); + nm_device_set_ip_ifindex(device, priv->wait_link.tun_ifindex); } - _LOGT(LOGD_CORE, "tun link is ready"); + if (check_waiting_for_link(device, "tun-link-changed")) { + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + return G_SOURCE_CONTINUE; + } + _LOGT(LOGD_CORE, "ovs-wait-link: tun link is ready"); nm_device_link_properties_set(device, FALSE); + nm_device_bring_up(device); nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); nm_device_activate_schedule_stage3_ip_config(device, FALSE); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); return G_SOURCE_CONTINUE; } @@ -309,40 +305,28 @@ _netdev_tun_link_cb(NMPlatform *platform, const NMPlatformSignalChangeType change_type = change_type_i; NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); - int ip_ifindex; - if (pllink->type != NM_LINK_TYPE_TUN || !nm_streq0(pllink->name, nm_device_get_iface(device))) + /* This is the handler for the link-changed platform events. It is triggered for all + * link changes. Keep only the ones matching our device. */ + if (!NM_IN_SET(change_type, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED)) return; - - ip_ifindex = nm_device_get_ip_ifindex(device); - if (ip_ifindex > 0) { - /* When we have an ifindex, we are only waiting for the MAC to settle */ - if (change_type != NM_PLATFORM_SIGNAL_CHANGED) - return; - - if (!check_waiting_for_link(device, "tun-link-changed")) { - _LOGT(LOGD_CORE, "ovs-wait-link: tun link is ready, cloned MAC is set"); - - nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); - nm_device_link_properties_set(device, FALSE); - - nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); - nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); - nm_device_activate_schedule_stage3_ip_config(device, FALSE); - } - return; - } - - /* No ip-ifindex on the device, set it when the link appears */ - if (change_type != NM_PLATFORM_SIGNAL_ADDED) + if (pllink->type != NM_LINK_TYPE_TUN || !nm_streq0(pllink->name, nm_device_get_iface(device))) return; _LOGT(LOGD_CORE, - "ovs-wait-link: found matching tun interface, schedule set-ip-ifindex(%d)", + "ovs-wait-link: got platform event \'%s\' for ifindex %d, scheduling idle handler", + change_type == NM_PLATFORM_SIGNAL_ADDED ? "added" : "changed", ifindex); - nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); - priv->wait_link.tun_ifindex = ifindex; - priv->wait_link.tun_set_ifindex_idle_source = nm_g_idle_add_source(_set_ip_ifindex_tun, device); + + /* The handler is invoked by the platform synchronously in the netlink receive loop. + * We can't perform other platform operations (like bringing the interface up) since + * the code there is not re-entrant. Schedule an idle handler. */ + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + priv->wait_link.tun_link_idle_source = + nm_g_idle_add_source(_netdev_tun_link_cb_in_idle, device); + priv->wait_link.tun_ifindex = ifindex; + + return; } static gboolean @@ -464,7 +448,7 @@ act_stage3_ip_config(NMDevice *device, int addr_family) nm_device_activate_schedule_stage3_ip_config(device, TRUE); return; } - nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); nm_device_link_properties_set(device, FALSE); @@ -488,7 +472,7 @@ deactivate(NMDevice *device) priv->wait_link.cloned_mac_evaluated = FALSE; nm_clear_g_free(&priv->wait_link.cloned_mac); nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); - nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); } typedef struct { @@ -581,7 +565,7 @@ deactivate_async(NMDevice *device, _LOGT(LOGD_CORE, "deactivate: start async"); nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); - nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); + nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); priv->wait_link.tun_ifindex = -1; priv->wait_link.cloned_mac_evaluated = FALSE; nm_clear_g_free(&priv->wait_link.cloned_mac); @@ -682,7 +666,7 @@ dispose(GObject *object) nm_assert(!priv->wait_link.waiting); nm_assert(priv->wait_link.tun_link_signal_id == 0); - nm_assert(!priv->wait_link.tun_set_ifindex_idle_source); + nm_assert(!priv->wait_link.tun_link_idle_source); if (priv->ovsdb) { g_signal_handlers_disconnect_by_func(priv->ovsdb, G_CALLBACK(ovsdb_ready), self); diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 7eacedb8..e9928548 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -256,6 +256,32 @@ detach_port(NMDevice *device, return ret; } +static gboolean +can_reapply_change(NMDevice *device, + const char *setting_name, + NMSetting *s_old, + NMSetting *s_new, + GHashTable *diffs, + GError **error) +{ + NMDeviceClass *device_class = NM_DEVICE_CLASS(nm_device_ovs_port_parent_class); + + if (nm_streq(setting_name, NM_SETTING_OVS_PORT_SETTING_NAME)) { + return nm_device_hash_check_invalid_keys(diffs, + NM_SETTING_OVS_PORT_SETTING_NAME, + error, + NM_SETTING_OVS_PORT_TAG, + NM_SETTING_OVS_PORT_VLAN_MODE, + NM_SETTING_OVS_PORT_BOND_UPDELAY, + NM_SETTING_OVS_PORT_BOND_DOWNDELAY, + NM_SETTING_OVS_PORT_LACP, + NM_SETTING_OVS_PORT_BOND_MODE, + NM_SETTING_OVS_PORT_TRUNKS); + } + + return device_class->can_reapply_change(device, setting_name, s_old, s_new, diffs, error); +} + /*****************************************************************************/ static void @@ -293,6 +319,7 @@ nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass) device_class->ready_for_ip_config = ready_for_ip_config; device_class->attach_port = attach_port; device_class->detach_port = detach_port; + device_class->can_reapply_change = can_reapply_change; device_class->can_reapply_change_ovs_external_ids = TRUE; device_class->reapply_connection = nm_device_ovs_reapply_connection; } diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 528d44d8..2dbc842a 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -101,13 +101,13 @@ typedef union { guint32 mtu; } set_interface_mtu; struct { - NMDeviceType device_type; - char *ifname; - char *connection_uuid; - GHashTable *external_ids_old; - GHashTable *external_ids_new; - GHashTable *other_config_old; - GHashTable *other_config_new; + NMDeviceType device_type; + char *ifname; + NMConnection *connection; + GHashTable *external_ids_old; + GHashTable *external_ids_new; + GHashTable *other_config_old; + GHashTable *other_config_new; } set_reapply; } OvsdbMethodPayload; @@ -242,24 +242,21 @@ static void cleanup_check_ready(NMOvsdb *self); }, \ })) -#define OVSDB_METHOD_PAYLOAD_SET_REAPPLY(xdevice_type, \ - xifname, \ - xconnection_uuid, \ - xexternal_ids_old, \ - xexternal_ids_new, \ - xother_config_old, \ - xother_config_new) \ - (&((const OvsdbMethodPayload) { \ - .set_reapply = \ - { \ - .device_type = xdevice_type, \ - .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ - .connection_uuid = (char *) NM_CONSTCAST(char, (xconnection_uuid)), \ - .external_ids_old = (xexternal_ids_old), \ - .external_ids_new = (xexternal_ids_new), \ - .other_config_old = (xother_config_old), \ - .other_config_new = (xother_config_new), \ - }, \ +#define OVSDB_METHOD_PAYLOAD_SET_REAPPLY(xdevice_type, \ + xifname, \ + xconnection, \ + xexternal_ids_old, \ + xexternal_ids_new, \ + xother_config_old, \ + xother_config_new) \ + (&((const OvsdbMethodPayload) { \ + .set_reapply = {.device_type = xdevice_type, \ + .ifname = (char *) NM_CONSTCAST(char, (xifname)), \ + .connection = (xconnection), \ + .external_ids_old = (xexternal_ids_old), \ + .external_ids_new = (xexternal_ids_new), \ + .other_config_old = (xother_config_old), \ + .other_config_new = (xother_config_new)}, \ })) /*****************************************************************************/ @@ -316,7 +313,7 @@ _call_complete(OvsdbMethodCall *call, json_t *response, GError *error) break; case OVSDB_SET_REAPPLY: nm_clear_g_free(&call->payload.set_reapply.ifname); - nm_clear_g_free(&call->payload.set_reapply.connection_uuid); + nm_clear_g_object(&call->payload.set_reapply.connection); nm_clear_pointer(&call->payload.set_reapply.external_ids_old, g_hash_table_destroy); nm_clear_pointer(&call->payload.set_reapply.external_ids_new, g_hash_table_destroy); nm_clear_pointer(&call->payload.set_reapply.other_config_old, g_hash_table_destroy); @@ -476,9 +473,9 @@ ovsdb_call_method(NMOvsdb *self, call->payload.set_interface_mtu.mtu); break; case OVSDB_SET_REAPPLY: - call->payload.set_reapply.device_type = payload->set_reapply.device_type; - call->payload.set_reapply.ifname = g_strdup(payload->set_reapply.ifname); - call->payload.set_reapply.connection_uuid = g_strdup(payload->set_reapply.connection_uuid); + call->payload.set_reapply.device_type = payload->set_reapply.device_type; + call->payload.set_reapply.ifname = g_strdup(payload->set_reapply.ifname); + call->payload.set_reapply.connection = payload->set_reapply.connection; call->payload.set_reapply.external_ids_old = nm_g_hash_table_ref(payload->set_reapply.external_ids_old); call->payload.set_reapply.external_ids_new = @@ -488,8 +485,8 @@ ovsdb_call_method(NMOvsdb *self, call->payload.set_reapply.other_config_new = nm_g_hash_table_ref(payload->set_reapply.other_config_new); _LOGT_call(call, - "new: set external-ids/other-config con-uuid=%s, interface=%s", - call->payload.set_reapply.connection_uuid, + "new: reapply con-uuid=%s, interface=%s", + nm_connection_get_uuid(payload->set_reapply.connection), call->payload.set_reapply.ifname); break; } @@ -976,65 +973,79 @@ _insert_interface(json_t *params, "rowInterface")); } -/** - * _insert_port: - * - * Returns an commands that adds new port from a given connection. - */ static void -_insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) +ovsdb_row_set_string_or_null(json_t *row, const char *key, const char *str) +{ + /* ovsdb represents a NULL string (no value) as an empty set */ + if (str) { + json_object_set_new(row, key, json_string(str)); + } else { + json_object_set_new(row, key, json_pack("[s, []]", "set")); + } +} + +static json_t * +create_port_row_object(NMConnection *connection) { NMSettingOvsPort *s_ovs_port; - const char *vlan_mode = NULL; - json_t *trunks = NULL; - guint tag = 0; - const char *lacp = NULL; - const char *bond_mode = NULL; - guint bond_updelay = 0; - guint bond_downdelay = 0; json_t *row; + const char *s; + guint u; - s_ovs_port = nm_connection_get_setting_ovs_port(port); + s_ovs_port = nm_connection_get_setting_ovs_port(connection); + nm_assert(s_ovs_port); row = json_object(); - if (s_ovs_port) { + s = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); + ovsdb_row_set_string_or_null(row, "vlan_mode", s); + + u = nm_setting_ovs_port_get_tag(s_ovs_port); + json_object_set_new(row, "tag", u != 0 ? json_integer(u) : json_pack("[s, []]", "set")); + + u = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); + json_object_set_new(row, "bond_updelay", json_integer(u)); + + u = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); + json_object_set_new(row, "bond_downdelay", json_integer(u)); + + s = nm_setting_ovs_port_get_lacp(s_ovs_port); + ovsdb_row_set_string_or_null(row, "lacp", s); + + s = nm_setting_ovs_port_get_bond_mode(s_ovs_port); + ovsdb_row_set_string_or_null(row, "bond_mode", s); + + { const GPtrArray *ranges; - guint i; + json_t *trunks = json_array(); guint64 start; guint64 end; - - vlan_mode = nm_setting_ovs_port_get_vlan_mode(s_ovs_port); - tag = nm_setting_ovs_port_get_tag(s_ovs_port); - lacp = nm_setting_ovs_port_get_lacp(s_ovs_port); - bond_mode = nm_setting_ovs_port_get_bond_mode(s_ovs_port); - bond_updelay = nm_setting_ovs_port_get_bond_updelay(s_ovs_port); - bond_downdelay = nm_setting_ovs_port_get_bond_downdelay(s_ovs_port); + guint i; ranges = _nm_setting_ovs_port_get_trunks_arr(s_ovs_port); for (i = 0; i < ranges->len; i++) { - if (!trunks) - trunks = json_array(); nm_range_get_range(ranges->pdata[i], &start, &end); for (; start <= end; start++) json_array_append_new(trunks, json_integer(start)); } - } - if (vlan_mode) - json_object_set_new(row, "vlan_mode", json_string(vlan_mode)); - if (tag) - json_object_set_new(row, "tag", json_integer(tag)); - if (trunks) json_object_set_new(row, "trunks", json_pack("[s, o]", "set", trunks)); - if (lacp) - json_object_set_new(row, "lacp", json_string(lacp)); - if (bond_mode) - json_object_set_new(row, "bond_mode", json_string(bond_mode)); - if (bond_updelay) - json_object_set_new(row, "bond_updelay", json_integer(bond_updelay)); - if (bond_downdelay) - json_object_set_new(row, "bond_downdelay", json_integer(bond_downdelay)); + } + + return row; +} + +/** + * _insert_port: + * + * Returns a command that adds new port from a given connection. + */ +static void +_insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) +{ + json_t *row; + + row = create_port_row_object(port); json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(port))); json_object_set_new(row, "interfaces", json_pack("[s, O]", "set", new_interfaces)); @@ -1058,10 +1069,50 @@ _insert_port(json_t *params, NMConnection *port, json_t *new_interfaces) "rowPort")); } +static json_t * +create_bridge_row_object(NMConnection *connection, gboolean is_reapply) +{ + NMSettingOvsBridge *s_ovs_bridge; + json_t *row; + gboolean b; + const char *s; + + s_ovs_bridge = nm_connection_get_setting_ovs_bridge(connection); + nm_assert(s_ovs_bridge); + + row = json_object(); + + b = nm_setting_ovs_bridge_get_mcast_snooping_enable(s_ovs_bridge); + json_object_set_new(row, "mcast_snooping_enable", json_boolean(b)); + + b = nm_setting_ovs_bridge_get_rstp_enable(s_ovs_bridge); + json_object_set_new(row, "rstp_enable", json_boolean(b)); + + b = nm_setting_ovs_bridge_get_stp_enable(s_ovs_bridge); + json_object_set_new(row, "stp_enable", json_boolean(b)); + + s = nm_setting_ovs_bridge_get_fail_mode(s_ovs_bridge); + ovsdb_row_set_string_or_null(row, "fail_mode", s); + + if (!is_reapply) { + /* The datapath type can't be reapplied because after changing it, + * ovs removes the existing ovs-interface and creates a tun one (or + * vice-versa). */ + s = nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge); + if (s) { + /* Cannot use ovsdb_row_set_string_or_null() here as the column + * is a set and must not be empty. */ + json_object_set_new(row, "datapath_type", json_string(s)); + } + } + + return row; +} + /** * _insert_bridge: * - * Returns an commands that adds new bridge from a given connection. + * Returns a command that adds new bridge from a given connection. */ static void _insert_bridge(json_t *params, @@ -1070,36 +1121,9 @@ _insert_bridge(json_t *params, json_t *new_ports, const char *cloned_mac) { - NMSettingOvsBridge *s_ovs_bridge; - const char *fail_mode = NULL; - gboolean mcast_snooping_enable = FALSE; - gboolean rstp_enable = FALSE; - gboolean stp_enable = FALSE; - const char *datapath_type = NULL; - json_t *row; - - s_ovs_bridge = nm_connection_get_setting_ovs_bridge(bridge); - - row = json_object(); - - if (s_ovs_bridge) { - fail_mode = nm_setting_ovs_bridge_get_fail_mode(s_ovs_bridge); - mcast_snooping_enable = nm_setting_ovs_bridge_get_mcast_snooping_enable(s_ovs_bridge); - rstp_enable = nm_setting_ovs_bridge_get_rstp_enable(s_ovs_bridge); - stp_enable = nm_setting_ovs_bridge_get_stp_enable(s_ovs_bridge); - datapath_type = nm_setting_ovs_bridge_get_datapath_type(s_ovs_bridge); - } + json_t *row; - if (fail_mode) - json_object_set_new(row, "fail_mode", json_string(fail_mode)); - if (mcast_snooping_enable) - json_object_set_new(row, "mcast_snooping_enable", json_boolean(mcast_snooping_enable)); - if (rstp_enable) - json_object_set_new(row, "rstp_enable", json_boolean(rstp_enable)); - if (stp_enable) - json_object_set_new(row, "stp_enable", json_boolean(stp_enable)); - if (datapath_type) - json_object_set_new(row, "datapath_type", json_string(datapath_type)); + row = create_bridge_row_object(bridge, FALSE); json_object_set_new(row, "name", json_string(nm_connection_get_interface_name(bridge))); json_object_set_new(row, "ports", json_pack("[s, O]", "set", new_ports)); @@ -1541,13 +1565,47 @@ ovsdb_next_command(NMOvsdb *self) break; case OVSDB_SET_REAPPLY: { - json_t *mutations; + NMConnection *connection; + json_t *mutations; + json_t *row; + const char *table; + + connection = call->payload.set_reapply.connection; + table = _device_type_to_table(call->payload.set_reapply.device_type); + + /* Reapply device properties */ + switch (call->payload.set_reapply.device_type) { + case NM_DEVICE_TYPE_OVS_BRIDGE: + row = create_bridge_row_object(connection, TRUE); + break; + case NM_DEVICE_TYPE_OVS_PORT: + row = create_port_row_object(connection); + break; + default: + row = NULL; + break; + } - mutations = json_array(); + if (row) { + json_array_append_new(params, + json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", + "op", + "update", + "table", + table, + "row", + row, + "where", + "name", + "==", + call->payload.set_reapply.ifname)); + } + /* Reapply external-ids and other-config */ + mutations = json_array(); _j_create_strv_array_update(mutations, STRDICT_TYPE_EXTERNAL_IDS, - call->payload.set_reapply.connection_uuid, + nm_connection_get_uuid(connection), call->payload.set_reapply.external_ids_old, call->payload.set_reapply.external_ids_new); _j_create_strv_array_update(mutations, @@ -1556,19 +1614,18 @@ ovsdb_next_command(NMOvsdb *self) call->payload.set_reapply.other_config_old, call->payload.set_reapply.other_config_new); - json_array_append_new( - params, - json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", - "op", - "mutate", - "table", - _device_type_to_table(call->payload.set_reapply.device_type), - "mutations", - mutations, - "where", - "name", - "==", - call->payload.set_reapply.ifname)); + json_array_append_new(params, + json_pack("{s:s, s:s, s:o, s:[[s, s, s]]}", + "op", + "mutate", + "table", + table, + "mutations", + mutations, + "where", + "name", + "==", + call->payload.set_reapply.ifname)); break; } @@ -2411,7 +2468,7 @@ again: * content is broken (_json_read_msg() cannot extract any data) and * we disconnect. */ priv->input_timeout_source = - nm_g_timeout_add_seconds_source(5, _ovsdb_read_input_timeout_cb, NULL); + nm_g_timeout_add_seconds_source(5, _ovsdb_read_input_timeout_cb, self); } return; } @@ -2975,7 +3032,7 @@ void nm_ovsdb_set_reapply(NMOvsdb *self, NMDeviceType device_type, const char *ifname, - const char *connection_uuid, + NMConnection *connection_take, NMSettingOvsExternalIDs *s_external_ids_old, NMSettingOvsExternalIDs *s_external_ids_new, NMSettingOvsOtherConfig *s_other_config_old, @@ -2986,6 +3043,11 @@ nm_ovsdb_set_reapply(NMOvsdb *self, gs_unref_hashtable GHashTable *other_config_old = NULL; gs_unref_hashtable GHashTable *other_config_new = NULL; + nm_assert(NM_IN_SET(device_type, + NM_DEVICE_TYPE_OVS_BRIDGE, + NM_DEVICE_TYPE_OVS_PORT, + NM_DEVICE_TYPE_OVS_INTERFACE)); + external_ids_old = s_external_ids_old ? nm_strdict_clone(_nm_setting_ovs_external_ids_get_data(s_external_ids_old)) @@ -3011,7 +3073,7 @@ nm_ovsdb_set_reapply(NMOvsdb *self, OVSDB_SET_REAPPLY, OVSDB_METHOD_PAYLOAD_SET_REAPPLY(device_type, ifname, - connection_uuid, + connection_take, external_ids_old, external_ids_new, other_config_old, diff --git a/src/core/devices/ovs/nm-ovsdb.h b/src/core/devices/ovs/nm-ovsdb.h index a022ff00..9b3fb8f9 100644 --- a/src/core/devices/ovs/nm-ovsdb.h +++ b/src/core/devices/ovs/nm-ovsdb.h @@ -50,7 +50,7 @@ void nm_ovsdb_set_interface_mtu(NMOvsdb *self, void nm_ovsdb_set_reapply(NMOvsdb *self, NMDeviceType device_type, const char *ifname, - const char *connection_uuid, + NMConnection *connection_take, NMSettingOvsExternalIDs *s_external_ids_old, NMSettingOvsExternalIDs *s_external_ids_new, NMSettingOvsOtherConfig *s_other_config_old, |