network: bridge-tunnel: add [BridgeTunnel] section

network-vxlan-src-vni-external
jeltz 2 years ago
parent ab80fe9493
commit c0a606c505
Signed by: jeltz
GPG Key ID: 800882B66C0C3326

@ -4406,6 +4406,12 @@ Token=prefixstable:2002:da8:1::</programlisting></para>
<varname>VLAN=</varname> above and will enable the VLAN ID for ingress as well.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>TunnelMap=</varname></term>
<listitem>
<para>Specifies a mapping from a VLAN ID range to a tunnel ID range.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

@ -71,6 +71,8 @@ sources = files('''
networkd-bridge-mdb.h
networkd-bridge-vlan.c
networkd-bridge-vlan.h
networkd-bridge-tunnel.c
networkd-bridge-tunnel.h
networkd-can.c
networkd-can.h
networkd-conf.c

@ -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);

@ -15,6 +15,7 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "parse-util.h"
#include "strv.h"
#include "vlan-util.h"
static bool is_bit_set(unsigned bit, uint32_t scope) {

@ -10,6 +10,7 @@
#include "sd-netlink.h"
#include "conf-parser.h"
#include "list.h"
#define BRIDGE_VLAN_BITMAP_MAX 4096
#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)

@ -1100,6 +1100,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_request_to_set_bridge_tunnel(link);
if (r < 0)
return r;
r = link_request_to_activate(link);
if (r < 0)
return r;

@ -335,6 +335,8 @@ BridgeMDB.VLANId, config_parse_mdb_vlan_id,
BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
BridgeTunnel.VLANId, config_parse_brtun_vlan_id, 0, 0
BridgeTunnel.TunnelId, config_parse_brtun_tunnel_id, 0, 0
DHCPPrefixDelegation.UplinkInterface, config_parse_uplink, 0, 0
DHCPPrefixDelegation.SubnetId, config_parse_dhcp_pd_subnet_id, 0, offsetof(Network, dhcp_pd_subnet_id)
DHCPPrefixDelegation.Announce, config_parse_bool, 0, offsetof(Network, dhcp_pd_announce)

@ -514,6 +514,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"BridgeFDB\0"
"BridgeMDB\0"
"BridgeVLAN\0"
"BridgeTunnel\0"
"IPv6SendRA\0"
"IPv6PrefixDelegation\0"
"IPv6Prefix\0"
@ -749,6 +750,7 @@ static Network *network_free(Network *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->bridge_tunnels_by_section, bridge_tunnel_free);
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);

@ -15,6 +15,7 @@
#include "net-condition.h"
#include "netdev.h"
#include "networkd-bridge-vlan.h"
#include "networkd-bridge-tunnel.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
@ -328,6 +329,7 @@ struct Network {
Hashmap *nexthops_by_section;
Hashmap *bridge_fdb_entries_by_section;
Hashmap *bridge_mdb_entries_by_section;
Hashmap *bridge_tunnels_by_section;
Hashmap *neighbors_by_section;
Hashmap *address_labels_by_section;
Hashmap *prefixes_by_section;

@ -21,6 +21,7 @@ static const char *const set_link_operation_table[_SET_LINK_OPERATION_MAX] = {
[SET_LINK_BOND] = "bond configurations",
[SET_LINK_BRIDGE] = "bridge configurations",
[SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations",
[SET_LINK_BRIDGE_TUNNEL] = "bridge tunnel configurations",
[SET_LINK_CAN] = "CAN interface configurations",
[SET_LINK_FLAGS] = "link flags",
[SET_LINK_GROUP] = "interface group",
@ -142,6 +143,10 @@ static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m,
return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE_VLAN, /* ignore = */ false, NULL);
}
static int link_set_bridge_tunnel_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_BRIDGE_TUNNEL, /* ignore = */ false, NULL);
}
static int link_set_can_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return set_link_handler_internal(rtnl, m, link, SET_LINK_CAN, /* ignore = */ false, NULL);
}
@ -399,6 +404,31 @@ static int link_configure_fill_message(
if (r < 0)
return r;
break;
case SET_LINK_BRIDGE_TUNNEL:
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
if (r < 0)
return r;
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
if (r < 0)
return r;
if (link->master_ifindex <= 0) {
/* master needs BRIDGE_FLAGS_SELF flag */
r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
if (r < 0)
return r;
}
r = bridge_tunnel_append_info(link->network, req);
if (r < 0)
return r;
r = sd_netlink_message_close_container(req);
if (r < 0)
return r;
break;
case SET_LINK_CAN:
r = can_set_netlink_message(link, req);
@ -542,6 +572,7 @@ static bool link_is_ready_to_call_set_link(Request *req) {
return false;
break;
case SET_LINK_BRIDGE_VLAN:
case SET_LINK_BRIDGE_TUNNEL:
if (!link->master_set)
return false;
if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge"))
@ -784,6 +815,28 @@ int link_request_to_set_bridge_vlan(Link *link) {
return link_request_set_link(link, SET_LINK_BRIDGE_VLAN, link_set_bridge_vlan_handler, NULL);
}
int link_request_to_set_bridge_tunnel(Link *link) {
assert(link);
assert(link->network);
/* TODO: check that vlan_tunnel is enabled on the master link */
if (!link->network->bridge && !streq_ptr(link->kind, "bridge")) {
Link *master;
if (!link->network->keep_master)
return 0;
if (link_get_master(link, &master) < 0)
return 0;
if (!streq_ptr(master->kind, "bridge"))
return 0;
}
return link_request_set_link(link, SET_LINK_BRIDGE_TUNNEL, link_set_bridge_tunnel_handler, NULL);
}
int link_request_to_set_can(Link *link) {
assert(link);
assert(link->network);

@ -11,6 +11,7 @@ typedef enum SetLinkOperation {
SET_LINK_BOND, /* Setting bond configs. */
SET_LINK_BRIDGE, /* Setting bridge configs. */
SET_LINK_BRIDGE_VLAN, /* Setting bridge VLAN configs. */
SET_LINK_BRIDGE_TUNNEL, /* Setting bridge tunnel configs. */
SET_LINK_CAN, /* Setting CAN interface configs. */
SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */
SET_LINK_GROUP, /* Setting interface group. */
@ -30,6 +31,7 @@ int link_request_to_set_addrgen_mode(Link *link);
int link_request_to_set_bond(Link *link);
int link_request_to_set_bridge(Link *link);
int link_request_to_set_bridge_vlan(Link *link);
int link_request_to_set_bridge_tunnel(Link *link);
int link_request_to_set_can(Link *link);
int link_request_to_set_flags(Link *link);
int link_request_to_set_group(Link *link);

@ -321,6 +321,8 @@ shared_sources = files('''
verbs.h
vlan-util.c
vlan-util.h
tunnel-util.c
tunnel-util.h
volatile-util.c
volatile-util.h
watchdog.c

@ -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);

@ -271,6 +271,9 @@ LifetimeSec=
EgressUntagged=
VLAN=
PVID=
[BridgeTunnel]
VLANId=
TunnelId=
[LLDP]
MUDURL=
[CAN]

Loading…
Cancel
Save