if (neighbor->network) {
assert(neighbor->section);
- hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
+ ordered_hashmap_remove(neighbor->network->neighbors_by_section, neighbor->section);
}
config_section_free(neighbor->section);
if (r < 0)
return r;
- neighbor = hashmap_get(network->neighbors_by_section, n);
+ neighbor = ordered_hashmap_get(network->neighbors_by_section, n);
if (neighbor) {
*ret = TAKE_PTR(neighbor);
return 0;
.source = NETWORK_CONFIG_SOURCE_STATIC,
};
- r = hashmap_ensure_put(&network->neighbors_by_section, &config_section_hash_ops, neighbor->section, neighbor);
+ r = ordered_hashmap_ensure_put(&network->neighbors_by_section, &config_section_hash_ops, neighbor->section, neighbor);
if (r < 0)
return r;
siphash24_compress(&neighbor->family, sizeof(neighbor->family), state);
- switch (neighbor->family) {
- case AF_INET:
- case AF_INET6:
- /* Equality of neighbors are given by the pair (addr,lladdr) */
- siphash24_compress(&neighbor->in_addr, FAMILY_ADDRESS_SIZE(neighbor->family), state);
- break;
- default:
+ if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
/* treat any other address family as AF_UNSPEC */
- break;
- }
+ return;
- hw_addr_hash_func(&neighbor->ll_addr, state);
+ /* Equality of neighbors are given by the destination address.
+ * See neigh_lookup() in the kernel. */
+ siphash24_compress(&neighbor->in_addr, FAMILY_ADDRESS_SIZE(neighbor->family), state);
}
static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
if (r != 0)
return r;
- switch (a->family) {
- case AF_INET:
- case AF_INET6:
- r = memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
- if (r != 0)
- return r;
- }
+ if (!IN_SET(a->family, AF_INET, AF_INET6))
+ /* treat any other address family as AF_UNSPEC */
+ return 0;
- return hw_addr_compare(&a->ll_addr, &b->ll_addr);
+ return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
}
-DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(neighbor_hash_ops, Neighbor, neighbor_hash_func, neighbor_compare_func, neighbor_free);
+DEFINE_PRIVATE_HASH_OPS(
+ neighbor_hash_ops,
+ Neighbor,
+ neighbor_hash_func,
+ neighbor_compare_func);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
+ neighbor_hash_ops_free,
+ Neighbor,
+ neighbor_hash_func,
+ neighbor_compare_func,
+ neighbor_free);
static int neighbor_get(Link *link, const Neighbor *in, Neighbor **ret) {
Neighbor *existing;
assert(link);
assert(neighbor);
- r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor);
+ r = set_ensure_put(&link->neighbors, &neighbor_hash_ops_free, neighbor);
if (r < 0)
return r;
if (r == 0)
link->static_neighbors_configured = false;
- HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
+ ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
r = link_request_neighbor(link, neighbor);
if (r < 0)
return log_link_warning_errno(link, r, "Could not request neighbor: %m");
}
/* Next, unmark requested neighbors. They will be configured later. */
- HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
+ ORDERED_HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) {
Neighbor *existing;
if (neighbor_get(link, neighbor, &existing) >= 0)
return 0;
}
-void network_drop_invalid_neighbors(Network *network) {
+int network_drop_invalid_neighbors(Network *network) {
+ _cleanup_set_free_ Set *neighbors = NULL;
Neighbor *neighbor;
+ int r;
assert(network);
- HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
- if (neighbor_section_verify(neighbor) < 0)
+ ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section) {
+ Neighbor *dup;
+
+ if (neighbor_section_verify(neighbor) < 0) {
+ /* Drop invalid [Neighbor] sections. Note that neighbor_free() will drop the
+ * neighbor from neighbors_by_section. */
neighbor_free(neighbor);
+ continue;
+ }
+
+ /* Always use the setting specified later. So, remove the previously assigned setting. */
+ dup = set_remove(neighbors, neighbor);
+ if (dup) {
+ log_warning("%s: Duplicated neighbor settings for %s is specified at line %u and %u, "
+ "dropping the address setting specified at line %u.",
+ dup->section->filename,
+ IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
+ neighbor->section->line,
+ dup->section->line, dup->section->line);
+ /* neighbor_free() will drop the address from neighbors_by_section. */
+ neighbor_free(dup);
+ }
+
+ /* Use neighbor_hash_ops, instead of neighbor_hash_ops_free. Otherwise, the Neighbor objects
+ * will be freed. */
+ r = set_ensure_put(&neighbors, &neighbor_hash_ops, neighbor);
+ if (r < 0)
+ return log_oom();
+ assert(r > 0);
+ }
+
+ return 0;
}
network_drop_invalid_nexthops(network);
network_drop_invalid_bridge_fdb_entries(network);
network_drop_invalid_bridge_mdb_entries(network);
- network_drop_invalid_neighbors(network);
+ r = network_drop_invalid_neighbors(network);
+ if (r < 0)
+ return r;
network_drop_invalid_address_labels(network);
network_drop_invalid_prefixes(network);
network_drop_invalid_route_prefixes(network);
hashmap_free_with_destructor(network->nexthops_by_section, nexthop_free);
hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free);
hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free);
- hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
+ ordered_hashmap_free_with_destructor(network->neighbors_by_section, neighbor_free);
hashmap_free_with_destructor(network->address_labels_by_section, address_label_free);
hashmap_free_with_destructor(network->prefixes_by_section, prefix_free);
hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free);
if (mdb->family == AF_INET6)
return true;
- HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
+ ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
if (neighbor->family == AF_INET6)
return true;