ni_bool_t ni_objectmodel_save_state(const char *filename) { xml_document_t *doc; ni_bool_t rv = FALSE; FILE *fp = NULL; ni_debug_objectmodel("saving server state to %s", filename); doc = xml_document_new(); if (!ni_objectmodel_save_state_xml(doc->root, __ni_objectmodel_server)) goto done; fp = ni_file_open(filename, "w", 0600); if (xml_document_print(doc, fp) < 0) { ni_error("%s: unable to write server state to %s", __func__, filename); goto done; } rv = TRUE; done: if (fp) fclose(fp); xml_document_free(doc); return rv; }
/* * Forward an addrconf drop call to a supplicant service, such as DHCP or zeroconf */ static dbus_bool_t ni_objectmodel_addrconf_forward_release(ni_dbus_addrconf_forwarder_t *forwarder, ni_netdev_t *dev, const ni_dbus_variant_t *dict, ni_dbus_message_t *reply, DBusError *error) { ni_addrconf_lease_t *lease; dbus_bool_t rv; /* If we have no lease, neither pending nor granted, there's nothing we need to do. */ if ((lease = ni_netdev_get_lease(dev, forwarder->addrfamily, forwarder->addrconf)) == NULL) return TRUE; rv = ni_objectmodel_addrconf_forwarder_call(forwarder, dev, "drop", &lease->uuid, NULL, error); if (!rv) { switch (ni_dbus_get_error(error, NULL)) { case -NI_ERROR_ADDRCONF_NO_LEASE: ni_debug_objectmodel("%s: no %s/%s lease", dev->name, ni_addrconf_type_to_name(forwarder->addrconf), ni_addrfamily_type_to_name(forwarder->addrfamily)); rv = TRUE; break; default: ni_debug_objectmodel("%s: service returned %s (%s)", forwarder->supplicant.interface, error->name, error->message); } return rv; } /* Check again whether we still have a lease for this. The addrconf supplicant may * actually be fast, so that the callback has arrived before the reply to our original * release() call. In that case, we would tell the client to wait for a release event * that has already been broadcast (and ignored). */ if ((lease = ni_netdev_get_lease(dev, forwarder->addrfamily, forwarder->addrconf)) != NULL) { /* Tell the client to wait for an addressReleased event with the given uuid */ ni_debug_objectmodel("%s/%s: found lease, waiting for drop notification from supplicant", ni_addrconf_type_to_name(forwarder->addrconf), ni_addrfamily_type_to_name(forwarder->addrfamily)); rv = __ni_objectmodel_return_callback_info(reply, NI_EVENT_ADDRESS_RELEASED, &lease->uuid, error); } return rv; }
static dbus_bool_t ni_objectmodel_gre_change(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_netconfig_t *nc = ni_global_state_handle(0); ni_netdev_t *dev, *cfg; ni_gre_t *gre; const char *err; /* we've already checked that argv matches our signature */ ni_assert(argc == 1); if (!(dev = ni_objectmodel_unwrap_netif(object, error)) || !(cfg = __ni_objectmodel_gre_device_arg(&argv[0])) || !(ni_netdev_get_gre(dev))) { ni_dbus_error_invalid_args(error, object->path, method->name); return FALSE; } gre = ni_netdev_get_gre(cfg); if ((err = ni_gre_validate(gre))) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); return FALSE; } cfg->link.ifindex = dev->link.ifindex; if (ni_string_empty(cfg->name)) ni_string_dup(&cfg->name, dev->name); if (ni_netdev_device_is_up(dev)) { ni_debug_objectmodel("Skipping gre changeDevice call on %s: " "device is up", dev->name); return TRUE; } if (!ni_string_empty(cfg->link.lowerdev.name) && !ni_objectmodel_bind_netdev_ref_index(cfg->name, "gre tunnel", &cfg->link.lowerdev, nc, error)) return FALSE; if (ni_system_tunnel_change(nc, dev, cfg) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to change gre properties on interface %s", dev->name); return FALSE; } return TRUE; }
static dbus_bool_t ni_objectmodel_dummy_change(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_netconfig_t *nc = ni_global_state_handle(0); ni_netdev_t *dev, *cfg; /* we've already checked that argv matches our signature */ ni_assert(argc == 1); if (!(dev = ni_objectmodel_unwrap_netif(object, error)) || !(cfg = __ni_objectmodel_dummy_device_arg(&argv[0]))) { ni_dbus_error_invalid_args(error, object->path, method->name); return FALSE; } cfg->link.ifindex = dev->link.ifindex; if (ni_string_empty(cfg->name)) ni_string_dup(&cfg->name, dev->name); if (ni_netdev_device_is_up(dev)) { ni_debug_objectmodel("Skipping dummy changeDevice call on %s: " "device is up", dev->name); return TRUE; } if (ni_system_dummy_change(nc, dev, cfg) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to change dummy properties on interface %s", dev->name); return FALSE; } if (cfg->link.hwaddr.type == ARPHRD_VOID) cfg->link.hwaddr.type = ARPHRD_ETHER; if (!ni_link_address_is_invalid(&cfg->link.hwaddr) && ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) { ni_error("Unable to change hwaddr on dummy interface %s", dev->name); /* fail? */ } return TRUE; }
/* * Register all naming services specified in the config file. * These naming services are supposed to be provided by shared libraries. * The symbol specified by the C binding element must refer to a * ni_objectmodel_ns struct. */ void ni_objectmodel_register_ns_dynamic(void) { ni_config_t *config = ni_global.config; ni_extension_t *ex; ni_assert(config); for (ex = config->ns_extensions; ex; ex = ex->next) { ni_c_binding_t *binding; void *addr; for (binding = ex->c_bindings; binding; binding = binding->next) { if ((addr = ni_c_binding_get_address(binding)) == NULL) { ni_error("cannot bind %s name service - invalid C binding", binding->name); continue; } ni_debug_objectmodel("trying to bind netif naming service \"%s\"", binding->name); ni_objectmodel_register_ns((ni_objectmodel_ns_t *) addr); } } }
/* * Change a macvlan/macvtap interface */ static dbus_bool_t __ni_objectmodel_macvlan_change(ni_netdev_t *cfg, ni_netdev_t *dev, DBusError *error) { ni_netconfig_t *nc = ni_global_state_handle(0); const char *err; ni_macvlan_t *macvlan; const char *dev_iftype = NULL; macvlan = ni_netdev_get_macvlan(cfg); if ((err = ni_macvlan_validate(macvlan))) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); return FALSE; } if ((cfg->link.lowerdev.index && (cfg->link.lowerdev.index != dev->link.lowerdev.index)) || (cfg->link.lowerdev.name && !ni_string_eq(cfg->link.lowerdev.name, dev->link.lowerdev.name))) { const char *cfg_iftype = ni_linktype_type_to_name(cfg->link.type); if (cfg->link.lowerdev.name) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Cannot change %s lower device to %s", cfg_iftype, cfg->link.lowerdev.name); } else { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Cannot change %s lower device to %u", cfg_iftype, cfg->link.lowerdev.index); } return FALSE; } cfg->link.lowerdev.index = dev->link.lowerdev.index; ni_string_dup(&cfg->link.lowerdev.name, dev->link.lowerdev.name); cfg->link.ifindex = dev->link.ifindex; if (ni_string_empty(cfg->name)) ni_string_dup(&cfg->name, dev->name); dev_iftype = ni_linktype_type_to_name(dev->link.type); if (!macvlan->mode) { macvlan->mode = dev->macvlan->mode; } else if ((macvlan->mode == NI_MACVLAN_MODE_PASSTHRU) != (dev->macvlan->mode == NI_MACVLAN_MODE_PASSTHRU)) { /* Passthrough mode can't be set or cleared dynamically */ dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "Cannot change %s mode to %s", dev_iftype, ni_macvlan_mode_to_name(macvlan->mode)); return FALSE; } if (ni_netdev_device_is_up(dev)) { ni_debug_objectmodel("Skipping %s changeDevice call on %s: " "device is up", dev_iftype, dev->name); return TRUE; } if (ni_system_macvlan_change(nc, dev, cfg) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to change %s properties on interface %s", dev_iftype, dev->name); return FALSE; } if (cfg->link.hwaddr.type == ARPHRD_VOID) cfg->link.hwaddr.type = ARPHRD_ETHER; if (!ni_link_address_is_invalid(&cfg->link.hwaddr) && ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) { ni_error("Unable to change hwaddr on %s interface %s", dev_iftype, dev->name); /* fail? */ } return TRUE; }
static dbus_bool_t ni_objectmodel_tuntap_change(ni_dbus_object_t *object, const ni_dbus_method_t *method, unsigned int argc, const ni_dbus_variant_t *argv, ni_dbus_message_t *reply, DBusError *error) { ni_netconfig_t *nc = ni_global_state_handle(0); ni_netdev_t *dev, *cfg; ni_tuntap_t *tuntap; const char *err; const char *iftype_name; /* we've already checked that argv matches our signature */ ni_assert(argc == 1); if (!(dev = ni_objectmodel_unwrap_netif(object, error)) || !(cfg = __ni_objectmodel_tuntap_device_arg(&argv[0], dev->link.type)) || !(ni_netdev_get_tuntap(dev))) { ni_dbus_error_invalid_args(error, object->path, method->name); return FALSE; } /* changeDevice method is only needed in case of TAP devices */ if (dev->link.type != NI_IFTYPE_TAP) return TRUE; iftype_name = ni_linktype_type_to_name(dev->link.type); tuntap = ni_netdev_get_tuntap(cfg); if ((err = ni_tuntap_validate(tuntap))) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s", err); return FALSE; } cfg->link.ifindex = dev->link.ifindex; if (ni_string_empty(cfg->name)) ni_string_dup(&cfg->name, dev->name); if (ni_netdev_device_is_up(dev)) { ni_debug_objectmodel("Skipping %s changeDevice call on %s: " "device is up", iftype_name, dev->name); return TRUE; } if (ni_system_tap_change(nc, dev, cfg) < 0) { dbus_set_error(error, DBUS_ERROR_FAILED, "Unable to change %s properties on interface %s", iftype_name, dev->name); return FALSE; } if (cfg->link.hwaddr.type == ARPHRD_VOID) cfg->link.hwaddr.type = ARPHRD_ETHER; if (ni_system_hwaddr_change(nc, dev, &cfg->link.hwaddr) < 0) { ni_error("Unable to change hwaddr on %s interface %s", iftype_name, dev->name); /* fail? */ } return TRUE; }