mirror of
https://github.com/systemd/systemd.git
synced 2025-02-02 13:47:27 +03:00
networkd: add support to configure VLAN on bridge ports
This commit is contained in:
parent
6cad256dbe
commit
13b498f967
@ -5480,6 +5480,8 @@ libnetworkd_core_la_SOURCES = \
|
|||||||
src/network/networkd-manager-bus.c \
|
src/network/networkd-manager-bus.c \
|
||||||
src/network/networkd-fdb.h \
|
src/network/networkd-fdb.h \
|
||||||
src/network/networkd-fdb.c \
|
src/network/networkd-fdb.c \
|
||||||
|
src/network/networkd-brvlan.h \
|
||||||
|
src/network/networkd-brvlan.c \
|
||||||
src/network/networkd-address-pool.h \
|
src/network/networkd-address-pool.h \
|
||||||
src/network/networkd-address-pool.c \
|
src/network/networkd-address-pool.c \
|
||||||
src/network/networkd-util.h \
|
src/network/networkd-util.h \
|
||||||
|
@ -1130,6 +1130,39 @@
|
|||||||
</varlistentry>
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
<refsect1>
|
||||||
|
<title>[BridgeVLAN] Section Options</title>
|
||||||
|
<para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
|
||||||
|
the following keys. Specify several <literal>[BridgeVLAN]</literal> sections to configure several VLAN entries.
|
||||||
|
The <varname>VLANFiltering=</varname> option has to be enabled, see <literal>[Bridge]</literal> section in
|
||||||
|
<citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||||
|
|
||||||
|
<variablelist class='network-directives'>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>VLAN=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid
|
||||||
|
from 1 to 4094.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>EgressUntagged=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>The VLAN ID specified here will be used to untag frames on egress. Configuring
|
||||||
|
<varname>EgressUntagged=</varname> implicates the use of <varname>VLAN=</varname> above and will enable the
|
||||||
|
VLAN ID for ingress as well. This can be either a single ID or a range M-N.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>PVID=</varname></term>
|
||||||
|
<listitem>
|
||||||
|
<para>The Port VLAN ID specified here is assigned to all untagged frames at ingress.
|
||||||
|
<varname>PVID=</varname> can be used only once. Configuring <varname>PVID=</varname> implicates the use of
|
||||||
|
<varname>VLAN=</varname> above and will enable the VLAN ID for ingress as well.</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>Example</title>
|
<title>Example</title>
|
||||||
@ -1174,6 +1207,26 @@ Name=enp2s0
|
|||||||
|
|
||||||
[Network]
|
[Network]
|
||||||
Bridge=bridge0</programlisting>
|
Bridge=bridge0</programlisting>
|
||||||
|
</example>
|
||||||
|
<example>
|
||||||
|
<title>/etc/systemd/network/25-bridge-slave-interface-vlan.network</title>
|
||||||
|
|
||||||
|
<programlisting>[Match]
|
||||||
|
Name=enp2s0
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
Bridge=bridge0
|
||||||
|
|
||||||
|
[BridgeVLAN]
|
||||||
|
VLAN=1-32
|
||||||
|
PVID=42
|
||||||
|
EgressUntagged=42
|
||||||
|
|
||||||
|
[BridgeVLAN]
|
||||||
|
VLAN=100-200
|
||||||
|
|
||||||
|
[BridgeVLAN]
|
||||||
|
EgressUntagged=300-400</programlisting>
|
||||||
</example>
|
</example>
|
||||||
<example>
|
<example>
|
||||||
<title>/etc/systemd/network/25-ipip.network</title>
|
<title>/etc/systemd/network/25-ipip.network</title>
|
||||||
|
@ -89,6 +89,15 @@
|
|||||||
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
|
#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
|
||||||
#define UNIQ __COUNTER__
|
#define UNIQ __COUNTER__
|
||||||
|
|
||||||
|
/* builtins */
|
||||||
|
#if __SIZEOF_INT__ == 4
|
||||||
|
#define BUILTIN_FFS_U32(x) __builtin_ffs(x);
|
||||||
|
#elif __SIZEOF_LONG__ == 4
|
||||||
|
#define BUILTIN_FFS_U32(x) __builtin_ffsl(x);
|
||||||
|
#else
|
||||||
|
#error "neither int nor long are four bytes long?!?"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Rounds up */
|
/* Rounds up */
|
||||||
|
|
||||||
#define ALIGN4(l) (((l) + 3) & ~3)
|
#define ALIGN4(l) (((l) + 3) & ~3)
|
||||||
|
@ -759,6 +759,14 @@ struct btrfs_ioctl_quota_ctl_args {
|
|||||||
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
|
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BRIDGE_VLAN_INFO_RANGE_BEGIN
|
||||||
|
#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BRIDGE_VLAN_INFO_RANGE_END
|
||||||
|
#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
|
#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
|
||||||
#define IFLA_BR_UNSPEC 0
|
#define IFLA_BR_UNSPEC 0
|
||||||
#define IFLA_BR_FORWARD_DELAY 1
|
#define IFLA_BR_FORWARD_DELAY 1
|
||||||
|
335
src/network/networkd-brvlan.c
Normal file
335
src/network/networkd-brvlan.c
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright (C) 2016 BISDN GmbH. All rights reserved.
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
systemd is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <linux/if_bridge.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "alloc-util.h"
|
||||||
|
#include "conf-parser.h"
|
||||||
|
#include "netlink-util.h"
|
||||||
|
#include "networkd-brvlan.h"
|
||||||
|
#include "networkd.h"
|
||||||
|
#include "parse-util.h"
|
||||||
|
#include "vlan-util.h"
|
||||||
|
|
||||||
|
static bool is_bit_set(unsigned bit, uint32_t scope) {
|
||||||
|
assert(bit < sizeof(scope)*8);
|
||||||
|
return scope & (1 << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void set_bit(unsigned nr, uint32_t *addr) {
|
||||||
|
if (nr < BRIDGE_VLAN_BITMAP_MAX)
|
||||||
|
addr[nr / 32] |= (((uint32_t) 1) << (nr % 32));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int is_vid_valid(unsigned vid) {
|
||||||
|
if (vid > VLANID_MAX || vid == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_next_bit(int i, uint32_t x) {
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if (i >= 32)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* find first bit */
|
||||||
|
if (i < 0)
|
||||||
|
return BUILTIN_FFS_U32(x);
|
||||||
|
|
||||||
|
/* mask off prior finds to get next */
|
||||||
|
j = __builtin_ffs(x >> i);
|
||||||
|
return j ? j + i : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) {
|
||||||
|
struct bridge_vlan_info br_vlan;
|
||||||
|
int i, j, k, r, done, cnt;
|
||||||
|
uint16_t begin, end;
|
||||||
|
bool untagged;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
assert(req);
|
||||||
|
assert(br_vid_bitmap);
|
||||||
|
assert(br_untagged_bitmap);
|
||||||
|
|
||||||
|
i = cnt = -1;
|
||||||
|
|
||||||
|
begin = end = UINT16_MAX;
|
||||||
|
for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
|
||||||
|
unsigned base_bit;
|
||||||
|
uint32_t vid_map = br_vid_bitmap[k];
|
||||||
|
uint32_t untagged_map = br_untagged_bitmap[k];
|
||||||
|
|
||||||
|
base_bit = k * 32;
|
||||||
|
i = -1;
|
||||||
|
done = 0;
|
||||||
|
do {
|
||||||
|
j = find_next_bit(i, vid_map);
|
||||||
|
if (j > 0) {
|
||||||
|
/* first hit of any bit */
|
||||||
|
if (begin == UINT16_MAX && end == UINT16_MAX) {
|
||||||
|
begin = end = j - 1 + base_bit;
|
||||||
|
untagged = is_bit_set(j - 1, untagged_map);
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this bit is a continuation of prior bits */
|
||||||
|
if (j - 2 + base_bit == end && untagged == is_bit_set(j - 1, untagged_map) && (uint16_t)j - 1 + base_bit != pvid && (uint16_t)begin != pvid) {
|
||||||
|
end++;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
done = 1;
|
||||||
|
|
||||||
|
if (begin != UINT16_MAX) {
|
||||||
|
cnt++;
|
||||||
|
if (done && k < BRIDGE_VLAN_BITMAP_LEN - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
br_vlan.flags = 0;
|
||||||
|
if (untagged)
|
||||||
|
br_vlan.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
|
||||||
|
|
||||||
|
if (begin == end) {
|
||||||
|
br_vlan.vid = begin;
|
||||||
|
|
||||||
|
if (begin == pvid)
|
||||||
|
br_vlan.flags |= BRIDGE_VLAN_INFO_PVID;
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
|
||||||
|
} else {
|
||||||
|
br_vlan.vid = begin;
|
||||||
|
br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
|
||||||
|
|
||||||
|
br_vlan.vid = end;
|
||||||
|
br_vlan.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
|
||||||
|
br_vlan.flags |= BRIDGE_VLAN_INFO_RANGE_END;
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_data(req, IFLA_BRIDGE_VLAN_INFO, &br_vlan, sizeof(br_vlan));
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not append IFLA_BRIDGE_VLAN_INFO attribute: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (j > 0) {
|
||||||
|
begin = end = j - 1 + base_bit;
|
||||||
|
untagged = is_bit_set(j - 1, untagged_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
next:
|
||||||
|
i = j;
|
||||||
|
} while(!done);
|
||||||
|
}
|
||||||
|
if (!cnt)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_brvlan_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
|
||||||
|
Link *link = userdata;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
r = sd_netlink_message_get_errno(m);
|
||||||
|
if (r < 0 && r != -EEXIST)
|
||||||
|
log_link_error_errno(link, r, "Could not add VLAN to bridge port: %m");
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap) {
|
||||||
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||||
|
int r;
|
||||||
|
uint16_t flags;
|
||||||
|
sd_netlink *rtnl;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
assert(link->manager);
|
||||||
|
assert(br_vid_bitmap);
|
||||||
|
assert(br_untagged_bitmap);
|
||||||
|
assert(link->network);
|
||||||
|
|
||||||
|
/* pvid might not be in br_vid_bitmap yet */
|
||||||
|
if (pvid)
|
||||||
|
set_bit(pvid, br_vid_bitmap);
|
||||||
|
|
||||||
|
rtnl = link->manager->rtnl;
|
||||||
|
|
||||||
|
/* create new RTM message */
|
||||||
|
r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, link->ifindex);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
|
||||||
|
|
||||||
|
r = sd_rtnl_message_link_set_family(req, PF_BRIDGE);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not set message family: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
|
||||||
|
|
||||||
|
/* master needs flag self */
|
||||||
|
if (!link->network->bridge) {
|
||||||
|
flags = BRIDGE_FLAGS_SELF;
|
||||||
|
sd_netlink_message_append_data(req, IFLA_BRIDGE_FLAGS, &flags, sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add vlan info */
|
||||||
|
r = append_vlan_info_data(link, req, pvid, br_vid_bitmap, br_untagged_bitmap);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not append VLANs: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_close_container(req);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not close IFLA_AF_SPEC container: %m");
|
||||||
|
|
||||||
|
/* send message to the kernel */
|
||||||
|
r = sd_netlink_call_async(rtnl, req, set_brvlan_handler, link, 0, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_vid_range(const char *rvalue, uint16_t *vid, uint16_t *vid_end) {
|
||||||
|
int r;
|
||||||
|
char *p;
|
||||||
|
char *_rvalue = NULL;
|
||||||
|
uint16_t _vid = UINT16_MAX;
|
||||||
|
uint16_t _vid_end = UINT16_MAX;
|
||||||
|
|
||||||
|
assert(rvalue);
|
||||||
|
assert(vid);
|
||||||
|
assert(vid_end);
|
||||||
|
|
||||||
|
_rvalue = strdupa(rvalue);
|
||||||
|
p = strchr(_rvalue, '-');
|
||||||
|
if (p) {
|
||||||
|
*p = '\0';
|
||||||
|
p++;
|
||||||
|
r = parse_vlanid(_rvalue, &_vid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!_vid)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
r = parse_vlanid(p, &_vid_end);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!_vid_end)
|
||||||
|
return -ERANGE;
|
||||||
|
} else {
|
||||||
|
r = parse_vlanid(_rvalue, &_vid);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!_vid)
|
||||||
|
return -ERANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*vid = _vid;
|
||||||
|
*vid_end = _vid_end;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_brvlan_vlan(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) {
|
||||||
|
Network *network = userdata;
|
||||||
|
int r;
|
||||||
|
uint16_t vid, vid_end;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = parse_vid_range(rvalue, &vid, &vid_end);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UINT16_MAX == vid_end)
|
||||||
|
set_bit(vid++, network->br_vid_bitmap);
|
||||||
|
else {
|
||||||
|
if (vid >= vid_end) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (; vid <= vid_end; vid++)
|
||||||
|
set_bit(vid, network->br_vid_bitmap);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_brvlan_untagged(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) {
|
||||||
|
Network *network = userdata;
|
||||||
|
int r;
|
||||||
|
uint16_t vid, vid_end;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(section);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = parse_vid_range(rvalue, &vid, &vid_end);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse VLAN: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UINT16_MAX == vid_end) {
|
||||||
|
set_bit(vid, network->br_vid_bitmap);
|
||||||
|
set_bit(vid, network->br_untagged_bitmap);
|
||||||
|
} else {
|
||||||
|
if (vid >= vid_end) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid VLAN range, ignoring %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (; vid <= vid_end; vid++) {
|
||||||
|
set_bit(vid, network->br_vid_bitmap);
|
||||||
|
set_bit(vid, network->br_untagged_bitmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
29
src/network/networkd-brvlan.h
Normal file
29
src/network/networkd-brvlan.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright (C) 2016 BISDN GmbH. All rights reserved.
|
||||||
|
|
||||||
|
systemd is free software; you can redistribute it and/or modify it
|
||||||
|
under the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
systemd is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct Link Link;
|
||||||
|
|
||||||
|
int br_vlan_configure(Link *link, uint16_t pvid, uint32_t *br_vid_bitmap, uint32_t *br_untagged_bitmap);
|
||||||
|
|
||||||
|
int config_parse_brvlan_vlan(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);
|
||||||
|
int config_parse_brvlan_untagged(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);
|
@ -1114,6 +1114,16 @@ int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int link_set_bridge_vlan(Link *link) {
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
r = br_vlan_configure(link, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
|
||||||
|
if (r < 0)
|
||||||
|
log_link_error_errno(link, r, "Failed to assign VLANs to bridge port: %m");
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int link_set_bridge_fdb(Link *link) {
|
static int link_set_bridge_fdb(Link *link) {
|
||||||
FdbEntry *fdb_entry;
|
FdbEntry *fdb_entry;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
@ -1996,6 +2006,12 @@ static int link_joined(Link *link) {
|
|||||||
log_link_error_errno(link, r, "Could not set bridge message: %m");
|
log_link_error_errno(link, r, "Could not set bridge message: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (link->network->bridge || NETDEV_KIND_BRIDGE == netdev_kind_from_string(link->kind)) {
|
||||||
|
r = link_set_bridge_vlan(link);
|
||||||
|
if (r < 0)
|
||||||
|
log_link_error_errno(link, r, "Could not set bridge vlan: %m");
|
||||||
|
}
|
||||||
|
|
||||||
return link_enter_set_addresses(link);
|
return link_enter_set_addresses(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "networkd.h"
|
#include "networkd.h"
|
||||||
#include "networkd-conf.h"
|
#include "networkd-conf.h"
|
||||||
#include "network-internal.h"
|
#include "network-internal.h"
|
||||||
|
#include "vlan-util.h"
|
||||||
%}
|
%}
|
||||||
struct ConfigPerfItem;
|
struct ConfigPerfItem;
|
||||||
%null_strings
|
%null_strings
|
||||||
@ -112,6 +113,9 @@ Bridge.AllowPortToBeRoot, config_parse_bool,
|
|||||||
Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
|
Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood)
|
||||||
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
|
BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0
|
||||||
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
|
BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0
|
||||||
|
BridgeVLAN.PVID, config_parse_vlanid, 0, offsetof(Network, pvid)
|
||||||
|
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
|
||||||
|
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
|
||||||
/* backwards compatibility: do not add new entries to this section */
|
/* backwards compatibility: do not add new entries to this section */
|
||||||
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
|
Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local)
|
||||||
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
|
DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
|
||||||
|
@ -147,7 +147,8 @@ static int network_load_one(Manager *manager, const char *filename) {
|
|||||||
"DHCPServer\0"
|
"DHCPServer\0"
|
||||||
"IPv6AcceptRA\0"
|
"IPv6AcceptRA\0"
|
||||||
"Bridge\0"
|
"Bridge\0"
|
||||||
"BridgeFDB\0",
|
"BridgeFDB\0"
|
||||||
|
"BridgeVLAN\0",
|
||||||
config_item_perf_lookup, network_network_gperf_lookup,
|
config_item_perf_lookup, network_network_gperf_lookup,
|
||||||
false, false, true, network);
|
false, false, true, network);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "resolve-util.h"
|
#include "resolve-util.h"
|
||||||
|
|
||||||
#include "networkd-address.h"
|
#include "networkd-address.h"
|
||||||
|
#include "networkd-brvlan.h"
|
||||||
#include "networkd-fdb.h"
|
#include "networkd-fdb.h"
|
||||||
#include "networkd-lldp-tx.h"
|
#include "networkd-lldp-tx.h"
|
||||||
#include "networkd-netdev.h"
|
#include "networkd-netdev.h"
|
||||||
@ -37,6 +38,9 @@
|
|||||||
#define DHCP_ROUTE_METRIC 1024
|
#define DHCP_ROUTE_METRIC 1024
|
||||||
#define IPV4LL_ROUTE_METRIC 2048
|
#define IPV4LL_ROUTE_METRIC 2048
|
||||||
|
|
||||||
|
#define BRIDGE_VLAN_BITMAP_MAX 4096
|
||||||
|
#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)
|
||||||
|
|
||||||
typedef enum DCHPClientIdentifier {
|
typedef enum DCHPClientIdentifier {
|
||||||
DHCP_CLIENT_ID_MAC,
|
DHCP_CLIENT_ID_MAC,
|
||||||
DHCP_CLIENT_ID_DUID,
|
DHCP_CLIENT_ID_DUID,
|
||||||
@ -146,6 +150,10 @@ struct Network {
|
|||||||
bool unicast_flood;
|
bool unicast_flood;
|
||||||
unsigned cost;
|
unsigned cost;
|
||||||
|
|
||||||
|
uint16_t pvid;
|
||||||
|
uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||||
|
uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||||
|
|
||||||
AddressFamilyBoolean ip_forward;
|
AddressFamilyBoolean ip_forward;
|
||||||
bool ip_masquerade;
|
bool ip_masquerade;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user