network: use request queue to configure bridge MDB

This commit is contained in:
Yu Watanabe
2021-06-08 06:33:27 +09:00
parent ff9e07838d
commit 9a038aaced
5 changed files with 86 additions and 71 deletions
+68 -42
View File
@@ -7,6 +7,7 @@
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "string-util.h"
#include "vlan-util.h"
@@ -79,7 +80,7 @@ static int bridge_mdb_new_static(
return 0;
}
static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
static int bridge_mdb_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
@@ -94,7 +95,7 @@ static int set_mdb_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
if (r == -EINVAL && streq_ptr(link->kind, "bridge") && (!link->network || !link->network->bridge)) {
/* To configure bridge MDB entries on bridge master, 1bc844ee0faa1b92e3ede00bdd948021c78d7088 (v5.4) is required. */
if (!link->manager->bridge_mdb_on_master_not_supported) {
log_link_warning_errno(link, r, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring: %m");
log_link_warning_errno(link, r, "Kernel seems not to support bridge MDB entries on bridge master, ignoring: %m");
link->manager->bridge_mdb_on_master_not_supported = true;
}
} else if (r < 0 && r != -EEXIST) {
@@ -124,15 +125,16 @@ static int link_get_bridge_master_ifindex(Link *link) {
}
/* send a request to the kernel to add an MDB entry */
static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
static int bridge_mdb_configure(BridgeMDB *mdb, Link *link, link_netlink_message_handler_t callback) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
struct br_mdb_entry entry;
int master, r;
assert(mdb);
assert(link);
assert(link->network);
assert(link->manager);
assert(mdb);
assert(callback);
if (DEBUG_LOGGING) {
_cleanup_free_ char *a = NULL;
@@ -154,11 +156,6 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
.vid = mdb->vlan_id,
};
/* create new RTM message */
r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
switch (mdb->family) {
case AF_INET:
entry.addr.u.ip4 = mdb->group_addr.in.s_addr;
@@ -174,11 +171,16 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
assert_not_reached("Invalid address family");
}
/* create new RTM message */
r = sd_rtnl_message_new_mdb(link->manager->rtnl, &req, RTM_NEWMDB, master);
if (r < 0)
return log_link_error_errno(link, r, "Could not create RTM_NEWMDB message: %m");
r = sd_netlink_message_append_data(req, MDBA_SET_ENTRY, &entry, sizeof(entry));
if (r < 0)
return log_link_error_errno(link, r, "Could not append MDBA_SET_ENTRY attribute: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, set_mdb_handler,
r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
@@ -188,18 +190,13 @@ static int bridge_mdb_configure(Link *link, BridgeMDB *mdb) {
return 1;
}
int link_set_bridge_mdb(Link *link) {
int link_request_static_bridge_mdb(Link *link) {
BridgeMDB *mdb;
int r;
assert(link);
assert(link->manager);
if (link->static_bridge_mdb_messages != 0) {
log_link_debug(link, "MDB entries are configuring.");
return 0;
}
link->static_bridge_mdb_configured = false;
if (!link->network)
@@ -208,48 +205,77 @@ int link_set_bridge_mdb(Link *link) {
if (hashmap_isempty(link->network->bridge_mdb_entries_by_section))
goto finish;
if (!link_has_carrier(link)) {
log_link_debug(link, "Link does not have carrier yet, setting MDB entries later.");
return 0;
}
if (link->network->bridge) {
Link *master;
r = link_get(link->manager, link->network->bridge->ifindex, &master);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get Link object for Bridge=%s", link->network->bridge->ifname);
if (!link_has_carrier(master)) {
log_link_debug(link, "Bridge interface %s does not have carrier yet, setting MDB entries later.", link->network->bridge->ifname);
return 0;
if (!link->network->bridge) {
if (!streq_ptr(link->kind, "bridge")) {
log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
goto finish;
} else if (link->manager->bridge_mdb_on_master_not_supported) {
log_link_debug(link, "Kernel seems not to support bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
goto finish;
}
} else if (!streq_ptr(link->kind, "bridge")) {
log_link_warning(link, "Link is neither a bridge master nor a bridge port, ignoring [BridgeMDB] sections.");
goto finish;
} else if (link->manager->bridge_mdb_on_master_not_supported) {
log_link_debug(link, "Kernel seems not to support configuring bridge MDB entries on bridge master, ignoring [BridgeMDB] sections.");
goto finish;
}
HASHMAP_FOREACH(mdb, link->network->bridge_mdb_entries_by_section) {
r = bridge_mdb_configure(link, mdb);
r = link_queue_request(link, REQUEST_TYPE_BRIDGE_MDB, mdb, false,
&link->static_bridge_mdb_messages, bridge_mdb_configure_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to add MDB entry to multicast group database: %m");
link->static_bridge_mdb_messages++;
return log_link_error_errno(link, r, "Failed to request MDB entry to multicast group database: %m");
}
finish:
if (link->static_bridge_mdb_messages == 0) {
link->static_bridge_mdb_configured = true;
link_check_ready(link);
} else {
log_link_debug(link, "Setting bridge MDB entries.");
link_set_state(link, LINK_STATE_CONFIGURING);
}
return 0;
}
static bool bridge_mdb_is_ready_to_configure(Link *link) {
Link *master;
if (!link_is_ready_to_configure(link, false))
return false;
if (!link->network->bridge)
return true; /* The interface is bridge master. */
if (link->master_ifindex <= 0)
return false;
if (link->master_ifindex != link->network->bridge->ifindex)
return false;
if (link_get(link->manager, link->master_ifindex, &master) < 0)
return false;
if (!streq_ptr(master->kind, "bridge"))
return false;
if (!IN_SET(master->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return false;
if (!link_has_carrier(master))
return false;
return true;
}
int request_process_bridge_mdb(Request *req) {
assert(req);
assert(req->link);
assert(req->mdb);
assert(req->type == REQUEST_TYPE_BRIDGE_MDB);
if (!bridge_mdb_is_ready_to_configure(req->link))
return 0;
return bridge_mdb_configure(req->mdb, req->link, req->netlink_handler);
}
static int bridge_mdb_verify(BridgeMDB *mdb) {
if (section_is_invalid(mdb->section))
return -EINVAL;
+3 -1
View File
@@ -9,6 +9,7 @@
typedef struct Link Link;
typedef struct Network Network;
typedef struct Request Request;
typedef struct BridgeMDB {
Network *network;
@@ -23,7 +24,8 @@ BridgeMDB *bridge_mdb_free(BridgeMDB *mdb);
void network_drop_invalid_bridge_mdb_entries(Network *network);
int link_set_bridge_mdb(Link *link);
int link_request_static_bridge_mdb(Link *link);
int request_process_bridge_mdb(Request *req);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_group_address);
CONFIG_PARSER_PROTOTYPE(config_parse_mdb_vlan_id);
+5 -28
View File
@@ -826,10 +826,6 @@ static int link_set_static_configs(Link *link) {
assert(link->network);
assert(link->state != _LINK_STATE_INVALID);
r = link_set_bridge_mdb(link);
if (r < 0)
return r;
r = link_set_ipv6_proxy_ndp_addresses(link);
if (r < 0)
return r;
@@ -846,6 +842,10 @@ static int link_set_static_configs(Link *link) {
if (r < 0)
return r;
r = link_request_static_bridge_mdb(link);
if (r < 0)
return r;
r = link_request_static_neighbors(link);
if (r < 0)
return r;
@@ -2802,30 +2802,7 @@ static int link_carrier_gained(Link *link) {
return r;
}
r = link_handle_bound_by_list(link);
if (r < 0)
return r;
if (!link->static_bridge_mdb_configured) {
r = link_set_bridge_mdb(link);
if (r < 0)
return r;
}
if (streq_ptr(link->kind, "bridge")) {
Link *slave;
SET_FOREACH(slave, link->slaves) {
if (slave->static_bridge_mdb_configured)
continue;
r = link_set_bridge_mdb(slave);
if (r < 0)
link_enter_failed(slave);
}
}
return 0;
return link_handle_bound_by_list(link);
}
static int link_carrier_lost(Link *link) {
+7
View File
@@ -2,6 +2,7 @@
#include "networkd-address.h"
#include "networkd-bridge-fdb.h"
#include "networkd-bridge-mdb.h"
#include "networkd-dhcp-server.h"
#include "networkd-manager.h"
#include "networkd-neighbor.h"
@@ -18,6 +19,9 @@ static void request_free_object(RequestType type, void *object) {
case REQUEST_TYPE_BRIDGE_FDB:
bridge_fdb_free(object);
break;
case REQUEST_TYPE_BRIDGE_MDB:
bridge_mdb_free(object);
break;
case REQUEST_TYPE_DHCP_SERVER:
break;
case REQUEST_TYPE_NEIGHBOR:
@@ -131,6 +135,9 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
case REQUEST_TYPE_BRIDGE_FDB:
r = request_process_bridge_fdb(req);
break;
case REQUEST_TYPE_BRIDGE_MDB:
r = request_process_bridge_mdb(req);
break;
case REQUEST_TYPE_DHCP_SERVER:
r = request_process_dhcp_server(req);
break;
+3
View File
@@ -7,6 +7,7 @@
typedef struct Address Address;
typedef struct BridgeFDB BridgeFDB;
typedef struct BridgeMDB BridgeMDB;
typedef struct Neighbor Neighbor;
typedef struct NextHop NextHop;
typedef struct Route Route;
@@ -20,6 +21,7 @@ typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType {
REQUEST_TYPE_ADDRESS,
REQUEST_TYPE_BRIDGE_FDB,
REQUEST_TYPE_BRIDGE_MDB,
REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_NEIGHBOR,
REQUEST_TYPE_NEXTHOP,
@@ -36,6 +38,7 @@ typedef struct Request {
union {
Address *address;
BridgeFDB *fdb;
BridgeMDB *mdb;
Neighbor *neighbor;
NextHop *nexthop;
Route *route;