mirror of
https://github.com/systemd/systemd.git
synced 2025-01-03 05:18:09 +03:00
Merge pull request #3431 from poettering/network-fixes
put limits on addresses and routers per link and per network
This commit is contained in:
commit
d9c11f2b01
@ -144,7 +144,10 @@ int sd_netlink_open(sd_netlink **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size) {
|
||||
int sd_netlink_inc_rcvbuf(sd_netlink *rtnl, size_t size) {
|
||||
assert_return(rtnl, -EINVAL);
|
||||
assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
|
||||
|
||||
return fd_inc_rcvbuf(rtnl->fd, size);
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,9 @@
|
||||
#include "utf8.h"
|
||||
#include "util.h"
|
||||
|
||||
#define ADDRESSES_PER_LINK_MAX 2048U
|
||||
#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
|
||||
|
||||
int address_new(Address **ret) {
|
||||
_cleanup_address_free_ Address *address = NULL;
|
||||
|
||||
@ -54,6 +57,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
|
||||
_cleanup_address_free_ Address *address = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
|
||||
if (section) {
|
||||
address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
|
||||
if (address) {
|
||||
@ -64,18 +70,21 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
|
||||
}
|
||||
}
|
||||
|
||||
if (network->n_static_addresses >= STATIC_ADDRESSES_PER_NETWORK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (section) {
|
||||
address->section = section;
|
||||
hashmap_put(network->addresses_by_section,
|
||||
UINT_TO_PTR(address->section), address);
|
||||
hashmap_put(network->addresses_by_section, UINT_TO_PTR(address->section), address);
|
||||
}
|
||||
|
||||
address->network = network;
|
||||
LIST_APPEND(addresses, network->static_addresses, address);
|
||||
network->n_static_addresses++;
|
||||
|
||||
*ret = address;
|
||||
address = NULL;
|
||||
@ -89,10 +98,11 @@ void address_free(Address *address) {
|
||||
|
||||
if (address->network) {
|
||||
LIST_REMOVE(addresses, address->network->static_addresses, address);
|
||||
assert(address->network->n_static_addresses > 0);
|
||||
address->network->n_static_addresses--;
|
||||
|
||||
if (address->section)
|
||||
hashmap_remove(address->network->addresses_by_section,
|
||||
UINT_TO_PTR(address->section));
|
||||
hashmap_remove(address->network->addresses_by_section, UINT_TO_PTR(address->section));
|
||||
}
|
||||
|
||||
if (address->link) {
|
||||
@ -328,7 +338,12 @@ static int address_release(Address *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) {
|
||||
int address_update(
|
||||
Address *address,
|
||||
unsigned char flags,
|
||||
unsigned char scope,
|
||||
const struct ifa_cacheinfo *cinfo) {
|
||||
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
@ -383,31 +398,38 @@ int address_drop(Address *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
|
||||
Address address = {}, *existing;
|
||||
int address_get(Link *link,
|
||||
int family,
|
||||
const union in_addr_union *in_addr,
|
||||
unsigned char prefixlen,
|
||||
Address **ret) {
|
||||
|
||||
Address address, *existing;
|
||||
|
||||
assert(link);
|
||||
assert(in_addr);
|
||||
assert(ret);
|
||||
|
||||
address.family = family;
|
||||
address.in_addr = *in_addr;
|
||||
address.prefixlen = prefixlen;
|
||||
address = (Address) {
|
||||
.family = family,
|
||||
.in_addr = *in_addr,
|
||||
.prefixlen = prefixlen,
|
||||
};
|
||||
|
||||
existing = set_get(link->addresses, &address);
|
||||
if (existing) {
|
||||
*ret = existing;
|
||||
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
} else {
|
||||
existing = set_get(link->addresses_foreign, &address);
|
||||
if (!existing)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*ret = existing;
|
||||
existing = set_get(link->addresses_foreign, &address);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int address_remove(
|
||||
@ -509,7 +531,12 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) {
|
||||
int address_configure(
|
||||
Address *address,
|
||||
Link *link,
|
||||
sd_netlink_message_handler_t callback,
|
||||
bool update) {
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
@ -520,6 +547,11 @@ int address_configure(Address *address, Link *link, sd_netlink_message_handler_t
|
||||
assert(link->manager);
|
||||
assert(link->manager->rtnl);
|
||||
|
||||
/* If this is a new address, then refuse adding more than the limit */
|
||||
if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
|
||||
set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
r = address_acquire(link, address, &address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -63,7 +63,7 @@ void address_free(Address *address);
|
||||
int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
|
||||
int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo);
|
||||
int address_update(Address *address, unsigned char flags, unsigned char scope, const struct ifa_cacheinfo *cinfo);
|
||||
int address_drop(Address *address);
|
||||
int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update);
|
||||
int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback);
|
||||
|
@ -27,14 +27,19 @@
|
||||
#include "networkd.h"
|
||||
#include "util.h"
|
||||
|
||||
#define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
|
||||
|
||||
/* create a new FDB entry or get an existing one. */
|
||||
int fdb_entry_new_static(Network *const network,
|
||||
const unsigned section,
|
||||
FdbEntry **ret) {
|
||||
int fdb_entry_new_static(
|
||||
Network *network,
|
||||
unsigned section,
|
||||
FdbEntry **ret) {
|
||||
|
||||
_cleanup_fdbentry_free_ FdbEntry *fdb_entry = NULL;
|
||||
struct ether_addr *mac_addr = NULL;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
|
||||
/* search entry in hashmap first. */
|
||||
if (section) {
|
||||
@ -47,6 +52,9 @@ int fdb_entry_new_static(Network *const network,
|
||||
}
|
||||
}
|
||||
|
||||
if (network->n_static_fdb_entries >= STATIC_FDB_ENTRIES_PER_NETWORK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
/* allocate space for MAC address. */
|
||||
mac_addr = new0(struct ether_addr, 1);
|
||||
if (!mac_addr)
|
||||
@ -54,7 +62,6 @@ int fdb_entry_new_static(Network *const network,
|
||||
|
||||
/* allocate space for and FDB entry. */
|
||||
fdb_entry = new0(FdbEntry, 1);
|
||||
|
||||
if (!fdb_entry) {
|
||||
/* free previously allocated space for mac_addr. */
|
||||
free(mac_addr);
|
||||
@ -66,6 +73,7 @@ int fdb_entry_new_static(Network *const network,
|
||||
fdb_entry->mac_addr = mac_addr;
|
||||
|
||||
LIST_PREPEND(static_fdb_entries, network->static_fdb_entries, fdb_entry);
|
||||
network->n_static_fdb_entries++;
|
||||
|
||||
if (section) {
|
||||
fdb_entry->section = section;
|
||||
@ -94,7 +102,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
|
||||
}
|
||||
|
||||
/* send a request to the kernel to add a FDB entry in its static MAC table. */
|
||||
int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
|
||||
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
sd_netlink *rtnl;
|
||||
int r;
|
||||
@ -145,12 +153,13 @@ void fdb_entry_free(FdbEntry *fdb_entry) {
|
||||
return;
|
||||
|
||||
if (fdb_entry->network) {
|
||||
LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries,
|
||||
fdb_entry);
|
||||
LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries, fdb_entry);
|
||||
|
||||
assert(fdb_entry->network->n_static_fdb_entries > 0);
|
||||
fdb_entry->network->n_static_fdb_entries--;
|
||||
|
||||
if (fdb_entry->section)
|
||||
hashmap_remove(fdb_entry->network->fdb_entries_by_section,
|
||||
UINT_TO_PTR(fdb_entry->section));
|
||||
hashmap_remove(fdb_entry->network->fdb_entries_by_section, UINT_TO_PTR(fdb_entry->section));
|
||||
}
|
||||
|
||||
free(fdb_entry->mac_addr);
|
||||
|
@ -36,9 +36,9 @@ struct FdbEntry {
|
||||
LIST_FIELDS(FdbEntry, static_fdb_entries);
|
||||
};
|
||||
|
||||
int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret);
|
||||
int fdb_entry_new_static(Network *network, unsigned section, FdbEntry **ret);
|
||||
void fdb_entry_free(FdbEntry *fdb_entry);
|
||||
int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry);
|
||||
int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free);
|
||||
#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep)
|
||||
|
@ -1096,7 +1096,7 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int link_set_bridge_fdb(Link *const link) {
|
||||
static int link_set_bridge_fdb(Link *link) {
|
||||
FdbEntry *fdb_entry;
|
||||
int r = 0;
|
||||
|
||||
@ -1111,7 +1111,7 @@ static int link_set_bridge_fdb(Link *const link) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int link_set_proxy_arp(Link *const link) {
|
||||
static int link_set_proxy_arp(Link *link) {
|
||||
const char *p = NULL;
|
||||
int r;
|
||||
|
||||
|
@ -172,6 +172,10 @@ struct Network {
|
||||
LIST_HEAD(Route, static_routes);
|
||||
LIST_HEAD(FdbEntry, static_fdb_entries);
|
||||
|
||||
unsigned n_static_addresses;
|
||||
unsigned n_static_routes;
|
||||
unsigned n_static_fdb_entries;
|
||||
|
||||
Hashmap *addresses_by_section;
|
||||
Hashmap *routes_by_section;
|
||||
Hashmap *fdb_entries_by_section;
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
#define ROUTES_PER_LINK_MAX 2048U
|
||||
#define STATIC_ROUTES_PER_NETWORK_MAX 1024U
|
||||
|
||||
int route_new(Route **ret) {
|
||||
_cleanup_route_free_ Route *route = NULL;
|
||||
|
||||
@ -51,6 +54,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
|
||||
_cleanup_route_free_ Route *route = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
|
||||
if (section) {
|
||||
route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section));
|
||||
if (route) {
|
||||
@ -61,6 +67,9 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
|
||||
}
|
||||
}
|
||||
|
||||
if (network->n_static_routes >= STATIC_ROUTES_PER_NETWORK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
r = route_new(&route);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -77,6 +86,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
|
||||
|
||||
route->network = network;
|
||||
LIST_PREPEND(routes, network->static_routes, route);
|
||||
network->n_static_routes++;
|
||||
|
||||
*ret = route;
|
||||
route = NULL;
|
||||
@ -91,9 +101,11 @@ void route_free(Route *route) {
|
||||
if (route->network) {
|
||||
LIST_REMOVE(routes, route->network->static_routes, route);
|
||||
|
||||
assert(route->network->n_static_routes > 0);
|
||||
route->network->n_static_routes--;
|
||||
|
||||
if (route->section)
|
||||
hashmap_remove(route->network->routes_by_section,
|
||||
UINT_TO_PTR(route->section));
|
||||
hashmap_remove(route->network->routes_by_section, UINT_TO_PTR(route->section));
|
||||
}
|
||||
|
||||
if (route->link) {
|
||||
@ -176,48 +188,55 @@ static const struct hash_ops route_hash_ops = {
|
||||
|
||||
int route_get(Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table,
|
||||
Route **ret) {
|
||||
Route route = {
|
||||
|
||||
Route route, *existing;
|
||||
|
||||
assert(link);
|
||||
assert(dst);
|
||||
|
||||
route = (Route) {
|
||||
.family = family,
|
||||
.dst = *dst,
|
||||
.dst_prefixlen = dst_prefixlen,
|
||||
.tos = tos,
|
||||
.priority = priority,
|
||||
.table = table,
|
||||
}, *existing;
|
||||
|
||||
assert(link);
|
||||
assert(dst);
|
||||
assert(ret);
|
||||
|
||||
route.dst = *dst;
|
||||
};
|
||||
|
||||
existing = set_get(link->routes, &route);
|
||||
if (existing) {
|
||||
*ret = existing;
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 1;
|
||||
} else {
|
||||
existing = set_get(link->routes_foreign, &route);
|
||||
if (!existing)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
*ret = existing;
|
||||
existing = set_get(link->routes_foreign, &route);
|
||||
if (existing) {
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static int route_add_internal(Link *link, Set **routes,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
static int route_add_internal(
|
||||
Link *link,
|
||||
Set **routes,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table,
|
||||
Route **ret) {
|
||||
|
||||
_cleanup_route_free_ Route *route = NULL;
|
||||
int r;
|
||||
|
||||
@ -254,23 +273,29 @@ static int route_add_internal(Link *link, Set **routes,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_add_foreign(Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
int route_add_foreign(
|
||||
Link *link,
|
||||
int family,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table,
|
||||
Route **ret) {
|
||||
|
||||
return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
|
||||
}
|
||||
|
||||
int route_add(Link *link,
|
||||
int route_add(
|
||||
Link *link,
|
||||
int family,
|
||||
union in_addr_union *dst,
|
||||
const union in_addr_union *dst,
|
||||
unsigned char dst_prefixlen,
|
||||
unsigned char tos,
|
||||
uint32_t priority,
|
||||
unsigned char table, Route **ret) {
|
||||
unsigned char table,
|
||||
Route **ret) {
|
||||
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
@ -303,12 +328,13 @@ int route_add(Link *link,
|
||||
}
|
||||
|
||||
int route_update(Route *route,
|
||||
union in_addr_union *src,
|
||||
const union in_addr_union *src,
|
||||
unsigned char src_prefixlen,
|
||||
union in_addr_union *gw,
|
||||
union in_addr_union *prefsrc,
|
||||
const union in_addr_union *gw,
|
||||
const union in_addr_union *prefsrc,
|
||||
unsigned char scope,
|
||||
unsigned char protocol) {
|
||||
|
||||
assert(route);
|
||||
assert(src);
|
||||
assert(gw);
|
||||
@ -449,8 +475,11 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int route_configure(Route *route, Link *link,
|
||||
sd_netlink_message_handler_t callback) {
|
||||
int route_configure(
|
||||
Route *route,
|
||||
Link *link,
|
||||
sd_netlink_message_handler_t callback) {
|
||||
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
_cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
|
||||
usec_t lifetime;
|
||||
@ -462,6 +491,10 @@ int route_configure(Route *route, Link *link,
|
||||
assert(link->ifindex > 0);
|
||||
assert(route->family == AF_INET || route->family == AF_INET6);
|
||||
|
||||
if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
|
||||
set_size(route->link->routes) >= ROUTES_PER_LINK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
|
||||
RTM_NEWROUTE, route->family,
|
||||
route->protocol);
|
||||
|
@ -57,10 +57,10 @@ void route_free(Route *route);
|
||||
int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback);
|
||||
int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback);
|
||||
|
||||
int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
|
||||
int route_get(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_add_foreign(Link *link, int family, const union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret);
|
||||
int route_update(Route *route, const union in_addr_union *src, unsigned char src_prefixlen, const union in_addr_union *gw, const union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol);
|
||||
|
||||
int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
||||
|
@ -43,7 +43,7 @@ typedef int (*sd_netlink_message_handler_t)(sd_netlink *nl, sd_netlink_message *
|
||||
int sd_netlink_new_from_netlink(sd_netlink **nl, int fd);
|
||||
int sd_netlink_open(sd_netlink **nl);
|
||||
int sd_netlink_open_fd(sd_netlink **nl, int fd);
|
||||
int sd_netlink_inc_rcvbuf(const sd_netlink *const rtnl, const int size);
|
||||
int sd_netlink_inc_rcvbuf(sd_netlink *nl, const size_t size);
|
||||
|
||||
sd_netlink *sd_netlink_ref(sd_netlink *nl);
|
||||
sd_netlink *sd_netlink_unref(sd_netlink *nl);
|
||||
|
Loading…
Reference in New Issue
Block a user