From: Tom Gundersen Date: Tue, 21 Jan 2014 20:58:08 +0000 (+0100) Subject: networkd: add basic bonding support X-Git-Tag: v209~364 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=52433f6b65eccd1c54606dde999610640f3458ac networkd: add basic bonding support Refactor bridging support to be generic netdev support and extend it to cover bonding as well. --- diff --git a/Makefile.am b/Makefile.am index 935a1955a..6c4f83434 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4082,7 +4082,7 @@ systemd_networkd_SOURCES = \ src/network/networkd.h \ src/network/networkd.c \ src/network/networkd-link.c \ - src/network/networkd-bridge.c \ + src/network/networkd-netdev.c \ src/network/networkd-network.c \ src/network/networkd-address.c \ src/network/networkd-route.c \ @@ -4110,7 +4110,7 @@ test_network_SOURCES = \ src/network/test-network.c \ src/network/networkd.h \ src/network/networkd-link.c \ - src/network/networkd-bridge.c \ + src/network/networkd-netdev.c \ src/network/networkd-network.c \ src/network/networkd-address.c \ src/network/networkd-route.c \ diff --git a/man/systemd-networkd.service.xml b/man/systemd-networkd.service.xml index 9f628d3b4..57a3a7cf7 100644 --- a/man/systemd-networkd.service.xml +++ b/man/systemd-networkd.service.xml @@ -91,7 +91,7 @@ other extensions are ignored. Virtual network devices are created as soon as networkd is started. - The [Bridge] section accepts the following + The [Netdev] section accepts the following keys: @@ -102,6 +102,13 @@ bridge. This option is compulsory. + + Kind + + The netdev kind. Currently, 'bridge' and 'bond' are + supported. This option is compulsory. + + @@ -206,6 +213,12 @@ The name of the bridge to add the configured link to. + + Bond + + The name of the bond to add the configured link to. + + The [Address] section accepts the following keys: diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index abf6a3097..7181cf856 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -22,6 +22,7 @@ Match.Type, config_parse_string, 0, offsetof(Networ Match.Name, config_parse_ifname, 0, offsetof(Network, match_name) Network.Description, config_parse_string, 0, offsetof(Network, description) Network.Bridge, config_parse_bridge, 0, offsetof(Network, bridge) +Network.Bond, config_parse_bond, 0, offsetof(Network, bond) Network.DHCP, config_parse_bool, 0, offsetof(Network, dhcp) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 @@ -34,5 +35,6 @@ DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Networ DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domainname) -Bridge.Description, config_parse_string, 0, offsetof(Bridge, description) -Bridge.Name, config_parse_ifname, 0, offsetof(Bridge, name) +Netdev.Description, config_parse_string, 0, offsetof(Netdev, description) +Netdev.Name, config_parse_ifname, 0, offsetof(Netdev, name) +Netdev.Kind, config_parse_netdev_kind, 0, offsetof(Netdev, kind) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 2fa77f15f..f746f2dcc 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -95,7 +95,7 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) { Network *network; int r; uint64_t ifindex; - const char *devtype; + NetdevKind kind; assert(m); assert(device); @@ -113,9 +113,9 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) { *ret = link; - devtype = udev_device_get_devtype(device); - if (streq_ptr(devtype, "bridge")) { - r = bridge_set_link(m, link); + kind = netdev_kind_from_string(udev_device_get_devtype(device)); + if (kind != _NETDEV_KIND_INVALID) { + r = netdev_set_link(m, kind, link); if (r < 0 && r != -ENOENT) return r; } @@ -729,11 +729,11 @@ static int link_up(Link *link) { return 0; } -static int link_bridge_joined(Link *link) { +static int link_enslaved(Link *link) { int r; assert(link); - assert(link->state == LINK_STATE_JOINING_BRIDGE); + assert(link->state == LINK_STATE_ENSLAVING); assert(link->network); r = link_up(link); @@ -748,67 +748,87 @@ static int link_bridge_joined(Link *link) { return 0; } -static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { +static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { Link *link = userdata; int r; assert(link); - assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED); + assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED); assert(link->network); + link->enslaving --; + if (link->state == LINK_STATE_FAILED) return 1; r = sd_rtnl_message_get_errno(m); if (r < 0) { - log_struct_link(LOG_ERR, link, - "MESSAGE=%s: could not join bridge '%s': %s", - link->ifname, link->network->bridge->name, strerror(-r), - BRIDGE(link->network->bridge), - NULL); + log_error_link(link, "could not enslave: %s", + strerror(-r)); link_enter_failed(link); return 1; } - log_struct_link(LOG_DEBUG, link, - "MESSAGE=%s: joined bridge '%s'", - link->network->bridge->name, - BRIDGE(link->network->bridge), - NULL); + log_debug_link(link, "enslaved"); - link_bridge_joined(link); + if (link->enslaving == 0) + link_enslaved(link); return 1; } -static int link_enter_join_bridge(Link *link) { +static int link_enter_enslave(Link *link) { int r; assert(link); assert(link->network); assert(link->state == _LINK_STATE_INVALID); - link->state = LINK_STATE_JOINING_BRIDGE; + link->state = LINK_STATE_ENSLAVING; - if (!link->network->bridge) - return link_bridge_joined(link); + if (!link->network->bridge && !link->network->bond) + return link_enslaved(link); - log_struct_link(LOG_DEBUG, link, - "MESSAGE=%s: joining bridge '%s'", - link->network->bridge->name, - BRIDGE(link->network->bridge), - NULL); - log_debug_link(link, "joining bridge"); + if (link->network->bridge) { + log_struct_link(LOG_DEBUG, link, + "MESSAGE=%s: enslaving by '%s'", + link->network->bridge->name, + NETDEV(link->network->bridge), + NULL); - r = bridge_join(link->network->bridge, link, &bridge_handler); - if (r < 0) { - log_struct_link(LOG_WARNING, link, - "MESSAGE=%s: could not join bridge '%s': %s", - link->network->bridge->name, strerror(-r), - BRIDGE(link->network->bridge), + r = netdev_enslave(link->network->bridge, link, &enslave_handler); + if (r < 0) { + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not enslave by '%s': %s", + link->network->bridge->name, strerror(-r), + NETDEV(link->network->bridge), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving ++; + } + + if (link->network->bond) { + log_struct_link(LOG_DEBUG, link, + "MESSAGE=%s: enslaving by '%s'", + link->network->bond->name, + NETDEV(link->network->bond), NULL); - link_enter_failed(link); - return r; + + r = netdev_enslave(link->network->bond, link, &enslave_handler); + if (r < 0) { + log_struct_link(LOG_WARNING, link, + "MESSAGE=%s: could not enslave by '%s': %s", + link->network->bond->name, strerror(-r), + NETDEV(link->network->bond), + NULL); + link_enter_failed(link); + return r; + } + + link->enslaving ++; } return 0; @@ -875,7 +895,7 @@ int link_configure(Link *link) { return r; } - return link_enter_join_bridge(link); + return link_enter_enslave(link); } int link_update(Link *link, sd_rtnl_message *m) { diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 5ab9ba0ba..7b93c5b5e 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -70,8 +70,8 @@ int manager_new(Manager **ret) { if (!m->links) return -ENOMEM; - m->bridges = hashmap_new(string_hash_func, string_compare_func); - if (!m->bridges) + m->netdevs = hashmap_new(string_hash_func, string_compare_func); + if (!m->netdevs) return -ENOMEM; LIST_HEAD_INIT(m->networks); @@ -84,7 +84,7 @@ int manager_new(Manager **ret) { void manager_free(Manager *m) { Network *network; - Bridge *bridge; + Netdev *netdev; Link *link; udev_monitor_unref(m->udev_monitor); @@ -100,9 +100,9 @@ void manager_free(Manager *m) { link_free(link); hashmap_free(m->links); - while ((bridge = hashmap_first(m->bridges))) - bridge_free(bridge); - hashmap_free(m->bridges); + while ((netdev = hashmap_first(m->netdevs))) + netdev_free(netdev); + hashmap_free(m->netdevs); sd_rtnl_unref(m->rtnl); @@ -115,7 +115,7 @@ int manager_load_config(Manager *m) { /* update timestamp */ paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true); - r = bridge_load(m); + r = netdev_load(m); if (r < 0) return r; diff --git a/src/network/networkd-bridge.c b/src/network/networkd-netdev.c similarity index 50% rename from src/network/networkd-bridge.c rename to src/network/networkd-netdev.c index ce4887899..2d1cef112 100644 --- a/src/network/networkd-bridge.c +++ b/src/network/networkd-netdev.c @@ -26,119 +26,127 @@ #include "conf-parser.h" #include "list.h" -void bridge_free(Bridge *bridge) { - bridge_join_callback *callback; +static const char* const netdev_kind_table[] = { + [NETDEV_KIND_BRIDGE] = "bridge", + [NETDEV_KIND_BOND] = "bond" +}; - if (!bridge) +DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetdevKind); +DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetdevKind, "Failed to parse netdev kind"); + +void netdev_free(Netdev *netdev) { + netdev_enslave_callback *callback; + + if (!netdev) return; - while ((callback = bridge->callbacks)) { - LIST_REMOVE(callbacks, bridge->callbacks, callback); + while ((callback = netdev->callbacks)) { + LIST_REMOVE(callbacks, netdev->callbacks, callback); free(callback); } - if (bridge->name) - hashmap_remove(bridge->manager->bridges, bridge->name); + if (netdev->name) + hashmap_remove(netdev->manager->netdevs, netdev->name); - free(bridge->filename); + free(netdev->filename); - free(bridge->description); - free(bridge->name); + free(netdev->description); + free(netdev->name); - free(bridge); + free(netdev); } -int bridge_get(Manager *manager, const char *name, Bridge **ret) { - Bridge *bridge; +int netdev_get(Manager *manager, const char *name, Netdev **ret) { + Netdev *netdev; assert(manager); assert(name); assert(ret); - bridge = hashmap_get(manager->bridges, name); - if (!bridge) { + netdev = hashmap_get(manager->netdevs, name); + if (!netdev) { *ret = NULL; return -ENOENT; } - *ret = bridge; + *ret = netdev; return 0; } -static int bridge_enter_failed(Bridge *bridge) { - bridge->state = BRIDGE_STATE_FAILED; +static int netdev_enter_failed(Netdev *netdev) { + netdev->state = NETDEV_STATE_FAILED; return 0; } -static int bridge_join_ready(Bridge *bridge, Link* link, sd_rtnl_message_handler_t callback) { +static int netdev_enslave_ready(Netdev *netdev, Link* link, sd_rtnl_message_handler_t callback) { _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL; int r; - assert(bridge); - assert(bridge->state == BRIDGE_STATE_READY); + assert(netdev); + assert(netdev->state == NETDEV_STATE_READY); assert(link); assert(callback); r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not allocate RTM_SETLINK message: %s", strerror(-r)); return r; } - r = sd_rtnl_message_append_u32(req, IFLA_MASTER, bridge->link->ifindex); + r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->link->ifindex); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not append IFLA_MASTER attribute: %s", strerror(-r)); return r; } - r = sd_rtnl_call_async(bridge->manager->rtnl, req, callback, link, 0, NULL); + r = sd_rtnl_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); return r; } - log_debug_bridge(bridge, "joining link %s to bridge", link->ifname); + log_debug_netdev(netdev, "enslaving link '%s'", link->ifname); return 0; } -static int bridge_enter_ready(Bridge *bridge) { - bridge_join_callback *callback; +static int netdev_enter_ready(Netdev *netdev) { + netdev_enslave_callback *callback; - assert(bridge); - assert(bridge->name); + assert(netdev); + assert(netdev->name); - bridge->state = BRIDGE_STATE_READY; + netdev->state = NETDEV_STATE_READY; - log_info_bridge(bridge, "bridge ready"); + log_info_netdev(netdev, "netdev ready"); - LIST_FOREACH(callbacks, callback, bridge->callbacks) { - /* join the links that were attempted to be joined befor the + LIST_FOREACH(callbacks, callback, netdev->callbacks) { + /* enslave the links that were attempted to be enslaved befor the * link was ready */ - bridge_join_ready(bridge, callback->link, callback->callback); + netdev_enslave_ready(netdev, callback->link, callback->callback); } return 0; } -static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { - Bridge *bridge = userdata; +static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + Netdev *netdev = userdata; int r; - assert(bridge->state != _BRIDGE_STATE_INVALID); + assert(netdev->state != _NETDEV_STATE_INVALID); r = sd_rtnl_message_get_errno(m); if (r < 0) { - log_warning_bridge(bridge, "bridge failed: %s", strerror(-r)); - bridge_enter_failed(bridge); + log_warning_netdev(netdev, "netdev failed: %s", strerror(-r)); + netdev_enter_failed(netdev); return 1; } @@ -146,27 +154,28 @@ static int bridge_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda return 1; } -static int bridge_create(Bridge *bridge) { +static int netdev_create(Netdev *netdev) { _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL; + const char *kind; int r; - assert(bridge); - assert(bridge->state == _BRIDGE_STATE_INVALID); - assert(bridge->name); - assert(bridge->manager); - assert(bridge->manager->rtnl); + assert(netdev); + assert(netdev->state == _NETDEV_STATE_INVALID); + assert(netdev->name); + assert(netdev->manager); + assert(netdev->manager->rtnl); r = sd_rtnl_message_link_new(RTM_NEWLINK, 0, &req); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not allocate RTM_NEWLINK message: %s", strerror(-r)); return r; } - r = sd_rtnl_message_append_string(req, IFLA_IFNAME, bridge->name); + r = sd_rtnl_message_append_string(req, IFLA_IFNAME, netdev->name); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not append IFLA_IFNAME attribute: %s", strerror(-r)); return r; @@ -174,15 +183,21 @@ static int bridge_create(Bridge *bridge) { r = sd_rtnl_message_open_container(req, IFLA_LINKINFO); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not open IFLA_LINKINFO container: %s", strerror(-r)); return r; } - r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, "bridge"); + kind = netdev_kind_to_string(netdev->kind); + if (!kind) { + log_error_netdev(netdev, "Invalid kind"); + return -EINVAL; + } + + r = sd_rtnl_message_append_string(req, IFLA_INFO_KIND, kind); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not append IFLA_INFO_KIND attribute: %s", strerror(-r)); return r; @@ -190,66 +205,69 @@ static int bridge_create(Bridge *bridge) { r = sd_rtnl_message_close_container(req); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not close IFLA_LINKINFO container %s", strerror(-r)); return r; } - r = sd_rtnl_call_async(bridge->manager->rtnl, req, &bridge_create_handler, bridge, 0, NULL); + r = sd_rtnl_call_async(netdev->manager->rtnl, req, &netdev_create_handler, netdev, 0, NULL); if (r < 0) { - log_error_bridge(bridge, + log_error_netdev(netdev, "Could not send rtnetlink message: %s", strerror(-r)); return r; } - log_debug_bridge(bridge, "creating bridge"); + log_debug_netdev(netdev, "creating netdev"); - bridge->state = BRIDGE_STATE_CREATING; + netdev->state = NETDEV_STATE_CREATING; return 0; } -int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t callback) { - if (bridge->state == BRIDGE_STATE_READY) { - bridge_join_ready(bridge, link, callback); +int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callback) { + if (netdev->state == NETDEV_STATE_READY) { + netdev_enslave_ready(netdev, link, callback); } else { - /* the bridge is not yet read, save this request for when it is*/ - bridge_join_callback *cb; + /* the netdev is not yet read, save this request for when it is*/ + netdev_enslave_callback *cb; - cb = new0(bridge_join_callback, 1); + cb = new0(netdev_enslave_callback, 1); if (!cb) return log_oom(); cb->callback = callback; cb->link = link; - LIST_PREPEND(callbacks, bridge->callbacks, cb); + LIST_PREPEND(callbacks, netdev->callbacks, cb); } return 0; } -int bridge_set_link(Manager *m, Link *link) { - Bridge *bridge; +int netdev_set_link(Manager *m, NetdevKind kind, Link *link) { + Netdev *netdev; int r; - r = bridge_get(m, link->ifname, &bridge); + r = netdev_get(m, link->ifname, &netdev); if (r < 0) return r; - if (bridge->link && bridge->link != link) + if (netdev->link && netdev->link != link) return -EEXIST; - bridge->link = link; + if (netdev->kind != kind) + return -EINVAL; - bridge_enter_ready(bridge); + netdev->link = link; + + netdev_enter_ready(netdev); return 0; } -static int bridge_load_one(Manager *manager, const char *filename) { - _cleanup_bridge_free_ Bridge *bridge = NULL; +static int netdev_load_one(Manager *manager, const char *filename) { + _cleanup_netdev_free_ Netdev *netdev = NULL; _cleanup_fclose_ FILE *file = NULL; int r; @@ -264,53 +282,59 @@ static int bridge_load_one(Manager *manager, const char *filename) { return errno; } - bridge = new0(Bridge, 1); - if (!bridge) + netdev = new0(Netdev, 1); + if (!netdev) return log_oom(); - bridge->manager = manager; - bridge->state = _BRIDGE_STATE_INVALID; + netdev->manager = manager; + netdev->state = _NETDEV_STATE_INVALID; + netdev->kind = _NETDEV_KIND_INVALID; - r = config_parse(NULL, filename, file, "Bridge\0", config_item_perf_lookup, - (void*) network_gperf_lookup, false, false, bridge); + r = config_parse(NULL, filename, file, "Netdev\0", config_item_perf_lookup, + (void*) network_gperf_lookup, false, false, netdev); if (r < 0) { log_warning("Could not parse config file %s: %s", filename, strerror(-r)); return r; } - if (!bridge->name) { - log_warning("Bridge without Name configured in %s. Ignoring", filename); + if (netdev->kind == _NETDEV_KIND_INVALID) { + log_warning("Netdev without Kind configured in %s. Ignoring", filename); + return 0; + } + + if (!netdev->name) { + log_warning("Netdev without Name configured in %s. Ignoring", filename); return 0; } - bridge->filename = strdup(filename); - if (!bridge->filename) + netdev->filename = strdup(filename); + if (!netdev->filename) return log_oom(); - r = hashmap_put(bridge->manager->bridges, bridge->name, bridge); + r = hashmap_put(netdev->manager->netdevs, netdev->name, netdev); if (r < 0) return r; - LIST_HEAD_INIT(bridge->callbacks); + LIST_HEAD_INIT(netdev->callbacks); - r = bridge_create(bridge); + r = netdev_create(netdev); if (r < 0) return r; - bridge = NULL; + netdev = NULL; return 0; } -int bridge_load(Manager *manager) { - Bridge *bridge; +int netdev_load(Manager *manager) { + Netdev *netdev; char **files, **f; int r; assert(manager); - while ((bridge = hashmap_first(manager->bridges))) - bridge_free(bridge); + while ((netdev = hashmap_first(manager->netdevs))) + netdev_free(netdev); r = conf_files_list_strv(&files, ".netdev", NULL, network_dirs); if (r < 0) { @@ -319,7 +343,7 @@ int bridge_load(Manager *manager) { } STRV_FOREACH_BACKWARDS(f, files) { - r = bridge_load_one(manager, *f); + r = netdev_load_one(manager, *f); if (r < 0) return r; } diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 40f6b2305..e70329473 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -223,7 +223,7 @@ int config_parse_bridge(const char *unit, void *data, void *userdata) { Network *network = userdata; - Bridge *bridge; + Netdev *netdev; int r; assert(filename); @@ -231,14 +231,57 @@ int config_parse_bridge(const char *unit, assert(rvalue); assert(data); - r = bridge_get(network->manager, rvalue, &bridge); + r = netdev_get(network->manager, rvalue, &netdev); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bridge is invalid, ignoring assignment: %s", rvalue); return 0; } - network->bridge = bridge; + if (netdev->kind != NETDEV_KIND_BRIDGE) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Netdev is not a bridge, ignoring assignment: %s", rvalue); + return 0; + } + + network->bridge = netdev; + + return 0; +} + +int config_parse_bond(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Network *network = userdata; + Netdev *netdev; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = netdev_get(network->manager, rvalue, &netdev); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Bond is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (netdev->kind != NETDEV_KIND_BOND) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Netdev is not a bond, ignoring assignment: %s", rvalue); + return 0; + } + + network->bond = netdev; return 0; } diff --git a/src/network/networkd.h b/src/network/networkd.h index c684eb8a8..2323e3db8 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -34,42 +34,50 @@ #include "hashmap.h" #include "list.h" -typedef struct Bridge Bridge; +typedef struct Netdev Netdev; typedef struct Network Network; typedef struct Link Link; typedef struct Address Address; typedef struct Route Route; typedef struct Manager Manager; -typedef struct bridge_join_callback bridge_join_callback; +typedef struct netdev_enslave_callback netdev_enslave_callback; -struct bridge_join_callback { +struct netdev_enslave_callback { sd_rtnl_message_handler_t callback; Link *link; - LIST_FIELDS(bridge_join_callback, callbacks); + LIST_FIELDS(netdev_enslave_callback, callbacks); }; -typedef enum BridgeState { - BRIDGE_STATE_FAILED, - BRIDGE_STATE_CREATING, - BRIDGE_STATE_READY, - _BRIDGE_STATE_MAX, - _BRIDGE_STATE_INVALID = -1, -} BridgeState; - -struct Bridge { +typedef enum NetdevKind { + NETDEV_KIND_BRIDGE, + NETDEV_KIND_BOND, + _NETDEV_KIND_MAX, + _NETDEV_KIND_INVALID = -1 +} NetdevKind; + +typedef enum NetdevState { + NETDEV_STATE_FAILED, + NETDEV_STATE_CREATING, + NETDEV_STATE_READY, + _NETDEV_STATE_MAX, + _NETDEV_STATE_INVALID = -1, +} NetdevState; + +struct Netdev { Manager *manager; char *filename; char *description; char *name; + NetdevKind kind; Link *link; - BridgeState state; + NetdevState state; - LIST_HEAD(bridge_join_callback, callbacks); + LIST_HEAD(netdev_enslave_callback, callbacks); }; struct Network { @@ -84,7 +92,8 @@ struct Network { char *match_name; char *description; - Bridge *bridge; + Netdev *bridge; + Netdev *bond; bool dhcp; bool dhcp_dns; bool dhcp_mtu; @@ -141,7 +150,7 @@ struct Route { }; typedef enum LinkState { - LINK_STATE_JOINING_BRIDGE, + LINK_STATE_ENSLAVING, LINK_STATE_SETTING_ADDRESSES, LINK_STATE_SETTING_ROUTES, LINK_STATE_CONFIGURED, @@ -170,6 +179,7 @@ struct Link { unsigned addr_messages; unsigned route_messages; + unsigned enslaving; sd_dhcp_client *dhcp; }; @@ -183,7 +193,7 @@ struct Manager { sd_event_source *udev_event_source; Hashmap *links; - Hashmap *bridges; + Hashmap *netdevs; LIST_HEAD(Network, networks); usec_t network_dirs_ts_usec; @@ -210,18 +220,23 @@ int manager_update_resolv_conf(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) -/* Bridge */ +/* Netdev */ + +int netdev_load(Manager *manager); -int bridge_load(Manager *manager); +void netdev_free(Netdev *netdev); -void bridge_free(Bridge *bridge); +DEFINE_TRIVIAL_CLEANUP_FUNC(Netdev*, netdev_free); +#define _cleanup_netdev_free_ _cleanup_(netdev_freep) -DEFINE_TRIVIAL_CLEANUP_FUNC(Bridge*, bridge_free); -#define _cleanup_bridge_free_ _cleanup_(bridge_freep) +int netdev_get(Manager *manager, const char *name, Netdev **ret); +int netdev_set_link(Manager *m, NetdevKind kind, Link *link); +int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t cb); -int bridge_get(Manager *manager, const char *name, Bridge **ret); -int bridge_set_link(Manager *m, Link *link); -int bridge_join(Bridge *bridge, Link *link, sd_rtnl_message_handler_t cb); +const char *netdev_kind_to_string(NetdevKind d) _const_; +NetdevKind netdev_kind_from_string(const char *d) _pure_; + +int config_parse_netdev_kind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Network */ @@ -239,6 +254,10 @@ int config_parse_bridge(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_bond(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + /* gperf */ const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length); @@ -307,16 +326,16 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free); /* More macros which append INTERFACE= to the message */ -#define log_full_bridge(level, bridge, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", bridge->name, "%s: " fmt, bridge->name, ##__VA_ARGS__) -#define log_debug_bridge(bridge, ...) log_full_bridge(LOG_DEBUG, bridge, ##__VA_ARGS__) -#define log_info_bridge(bridge, ...) log_full_bridge(LOG_INFO, bridge, ##__VA_ARGS__) -#define log_notice_bridge(bridge, ...) log_full_bridge(LOG_NOTICE, bridge, ##__VA_ARGS__) -#define log_warning_bridge(bridge, ...) log_full_bridge(LOG_WARNING, bridge,## __VA_ARGS__) -#define log_error_bridge(bridge, ...) log_full_bridge(LOG_ERR, bridge, ##__VA_ARGS__) +#define log_full_netdev(level, netdev, fmt, ...) log_meta_object(level, __FILE__, __LINE__, __func__, "INTERFACE=", netdev->name, "%s: " fmt, netdev->name, ##__VA_ARGS__) +#define log_debug_netdev(netdev, ...) log_full_netdev(LOG_DEBUG, netdev, ##__VA_ARGS__) +#define log_info_netdev(netdev, ...) log_full_netdev(LOG_INFO, netdev, ##__VA_ARGS__) +#define log_notice_netdev(netdev, ...) log_full_netdev(LOG_NOTICE, netdev, ##__VA_ARGS__) +#define log_warning_netdev(netdev, ...) log_full_netdev(LOG_WARNING, netdev,## __VA_ARGS__) +#define log_error_netdev(netdev, ...) log_full_netdev(LOG_ERR, netdev, ##__VA_ARGS__) -#define log_struct_bridge(level, bridge, ...) log_struct(level, "INTERFACE=%s", bridge->name, __VA_ARGS__) +#define log_struct_netdev(level, netdev, ...) log_struct(level, "INTERFACE=%s", netdev->name, __VA_ARGS__) -#define BRIDGE(bridge) "INTERFACE=%s", bridge->name +#define NETDEV(netdev) "INTERFACE=%s", netdev->name #define ADDRESS_FMT_VAL(address) \ (address).s_addr & 0xFF, \ ((address).s_addr >> 8) & 0xFF, \