network: bridge-tunnel: add [BridgeTunnel] section
parent
ab80fe9493
commit
c0a606c505
@ -0,0 +1,245 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/if_bridge.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "networkd-bridge-tunnel.h"
|
||||
#include "networkd-network.h"
|
||||
#include "networkd-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "tunnel-util.h"
|
||||
#include "vlan-util.h"
|
||||
|
||||
BridgeTunnel *bridge_tunnel_free(BridgeTunnel *tun) {
|
||||
if (!tun)
|
||||
return NULL;
|
||||
|
||||
if (tun->network) {
|
||||
assert(tun->section);
|
||||
hashmap_remove(tun->network->bridge_tunnels_by_section, tun->section);
|
||||
}
|
||||
|
||||
config_section_free(tun->section);
|
||||
|
||||
return mfree(tun);
|
||||
}
|
||||
|
||||
DEFINE_SECTION_CLEANUP_FUNCTIONS(BridgeTunnel, bridge_tunnel_free);
|
||||
|
||||
static int bridge_tunnel_new_static(
|
||||
Network *network,
|
||||
const char *filename,
|
||||
unsigned section_line,
|
||||
BridgeTunnel **ret) {
|
||||
|
||||
_cleanup_(config_section_freep) ConfigSection *n = NULL;
|
||||
_cleanup_(bridge_tunnel_freep) BridgeTunnel *tun = NULL;
|
||||
int r;
|
||||
|
||||
assert(network);
|
||||
assert(ret);
|
||||
assert(filename);
|
||||
assert(section_line > 0);
|
||||
|
||||
r = config_section_new(filename, section_line, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
tun = hashmap_get(network->bridge_tunnels_by_section, n);
|
||||
if (tun) {
|
||||
*ret = TAKE_PTR(tun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (hashmap_size(network->bridge_tunnels_by_section) >= STATIC_BRIDGE_TUNNELS_PER_NETWORK_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
tun = new(BridgeTunnel, 1);
|
||||
if (!tun)
|
||||
return -ENOMEM;
|
||||
|
||||
*tun = (BridgeTunnel) {
|
||||
.network = network,
|
||||
.section = TAKE_PTR(n),
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&network->bridge_tunnels_by_section, &config_section_hash_ops, tun->section, tun);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(tun);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool bridge_tunnel_full(const BridgeTunnel *tun) {
|
||||
assert(tun);
|
||||
|
||||
return tun->use_id && tun->use_vid;
|
||||
}
|
||||
|
||||
static bool bridge_tunnel_ranges_eq(const BridgeTunnel *tun) {
|
||||
assert(tun);
|
||||
assert(tun->vid <= tun->vid_end);
|
||||
assert(tun->id <= tun->id_end);
|
||||
|
||||
return (uint32_t)tun->vid_end - tun->vid == tun->id_end - tun->id;
|
||||
}
|
||||
|
||||
void network_drop_invalid_bridge_tunnels(Network *network) {
|
||||
BridgeTunnel *tun;
|
||||
|
||||
assert(network);
|
||||
|
||||
HASHMAP_FOREACH(tun, network->bridge_tunnels_by_section)
|
||||
if (section_is_invalid(tun->section) || !bridge_tunnel_full(tun))
|
||||
bridge_tunnel_free(tun);
|
||||
}
|
||||
|
||||
static int bridge_tunnel_append_bound(
|
||||
sd_netlink_message *req,
|
||||
uint32_t id,
|
||||
uint16_t vid,
|
||||
uint16_t flags) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(req, IFLA_BRIDGE_VLAN_TUNNEL_ID, id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bridge_tunnel_append_info(const Network *network, sd_netlink_message *req) {
|
||||
BridgeTunnel *tun;
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(network);
|
||||
|
||||
HASHMAP_FOREACH(tun, network->bridge_tunnels_by_section) {
|
||||
if (tun->id_end - tun->id > 0) {
|
||||
r = bridge_tunnel_append_bound(req, tun->id, tun->vid, BRIDGE_VLAN_INFO_RANGE_BEGIN);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = bridge_tunnel_append_bound(req, tun->id_end, tun->vid_end, BRIDGE_VLAN_INFO_RANGE_END);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
r = bridge_tunnel_append_bound(req, tun->id, tun->vid, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_brtun_vlan_id(
|
||||
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) {
|
||||
|
||||
_cleanup_(bridge_tunnel_free_or_set_invalidp) BridgeTunnel *tun = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(network);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = bridge_tunnel_new_static(network, filename, section_line, &tun);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = parse_vid_range(rvalue, &tun->vid, &tun->vid_end);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse VLANId: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tun->use_id && !bridge_tunnel_ranges_eq(tun)) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid VLAN range: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tun->use_vid = true;
|
||||
|
||||
TAKE_PTR(tun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_brtun_tunnel_id(
|
||||
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) {
|
||||
|
||||
_cleanup_(bridge_tunnel_free_or_set_invalidp) BridgeTunnel *tun = NULL;
|
||||
Network *network = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(network);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = bridge_tunnel_new_static(network, filename, section_line, &tun);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
r = parse_tunid_range(rvalue, &tun->id, &tun->id_end);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse TunnelId: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tun->use_vid && !bridge_tunnel_ranges_eq(tun)) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid tunnel range: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tun->use_id = true;
|
||||
|
||||
TAKE_PTR(tun);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
|
||||
#define STATIC_BRIDGE_TUNNELS_PER_NETWORK_MAX 1024U
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
|
||||
typedef struct BridgeTunnel {
|
||||
Network *network;
|
||||
ConfigSection *section;
|
||||
|
||||
uint16_t vid;
|
||||
uint16_t vid_end;
|
||||
bool use_vid;
|
||||
|
||||
uint32_t id;
|
||||
uint32_t id_end;
|
||||
bool use_id;
|
||||
} BridgeTunnel;
|
||||
|
||||
BridgeTunnel *bridge_tunnel_free(BridgeTunnel *tun);
|
||||
|
||||
void network_drop_invalid_bridge_tunnels(Network *network);
|
||||
|
||||
int bridge_tunnel_append_info(const Network *network, sd_netlink_message *req);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_brtun_vlan_id);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_brtun_tunnel_id);
|
@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "tunnel-util.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
|
||||
int parse_tunid_range(const char *p, uint32_t *tunid, uint32_t *tunid_end) {
|
||||
uint32_t lower, upper;
|
||||
int r;
|
||||
|
||||
r = parse_range(p, &lower, &upper);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (lower > upper)
|
||||
return -EINVAL;
|
||||
|
||||
*tunid = lower;
|
||||
*tunid_end = upper;
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
int parse_tunid_range(const char *p, uint32_t *tunid, uint32_t *tunid_end);
|
Loading…
Reference in New Issue