mirror of
https://github.com/systemd/systemd
synced 2024-07-22 10:44:58 +00:00
Merge pull request #29987 from yuwata/network-bridge-vlan
network: remove unnecessary bridge vlan IDs
This commit is contained in:
commit
bfa95c369a
|
@ -5866,8 +5866,9 @@ ServerAddress=192.168.0.1/24</programlisting>
|
|||
<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. Takes
|
||||
an integer in the range 1…4094.</para>
|
||||
<para>The VLAN ID allowed on the port. This can be either a single ID or a range M-N. Takes an
|
||||
integer in the range 1…4094. This setting can be specified multiple times. If an empty string is
|
||||
assigned, then the all previous assignments are cleared.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v231"/>
|
||||
</listitem>
|
||||
|
@ -5876,8 +5877,10 @@ ServerAddress=192.168.0.1/24</programlisting>
|
|||
<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>
|
||||
<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. This
|
||||
setting can be specified multiple times. If an empty string is assigned, then the all previous
|
||||
assignments are cleared.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v231"/>
|
||||
</listitem>
|
||||
|
@ -5885,9 +5888,11 @@ ServerAddress=192.168.0.1/24</programlisting>
|
|||
<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>
|
||||
<para>The port VLAN ID specified here is assigned to all untagged frames at ingress. Takes an
|
||||
VLAN ID or negative boolean value (e.g. <literal>no</literal>). When false, the currently
|
||||
assigned port VLAN ID will be dropped. Configuring <varname>PVID=</varname> implicates the use of
|
||||
<varname>VLAN=</varname> setting in the above and will enable the VLAN ID for ingress as well.
|
||||
Defaults to unset, and will keep the assigned port VLAN ID if exists.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v231"/>
|
||||
</listitem>
|
||||
|
|
|
@ -17,140 +17,311 @@
|
|||
#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 & (UINT32_C(1) << bit);
|
||||
static bool is_bit_set(unsigned nr, const uint32_t *addr) {
|
||||
assert(nr < BRIDGE_VLAN_BITMAP_MAX);
|
||||
return addr[nr / 32] & (UINT32_C(1) << (nr % 32));
|
||||
}
|
||||
|
||||
static void set_bit(unsigned nr, uint32_t *addr) {
|
||||
if (nr < BRIDGE_VLAN_BITMAP_MAX)
|
||||
addr[nr / 32] |= (UINT32_C(1) << (nr % 32));
|
||||
assert(nr < BRIDGE_VLAN_BITMAP_MAX);
|
||||
addr[nr / 32] |= (UINT32_C(1) << (nr % 32));
|
||||
}
|
||||
|
||||
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 add_single(sd_netlink_message *m, uint16_t id, bool untagged, bool is_pvid) {
|
||||
assert(m);
|
||||
assert(id < BRIDGE_VLAN_BITMAP_MAX);
|
||||
return sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
|
||||
&(struct bridge_vlan_info) {
|
||||
.vid = id,
|
||||
.flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
|
||||
(is_pvid ? BRIDGE_VLAN_INFO_PVID : 0),
|
||||
},
|
||||
sizeof(struct bridge_vlan_info));
|
||||
}
|
||||
|
||||
int bridge_vlan_append_info(
|
||||
const Link *link,
|
||||
sd_netlink_message *req,
|
||||
uint16_t pvid,
|
||||
const uint32_t *br_vid_bitmap,
|
||||
const uint32_t *br_untagged_bitmap) {
|
||||
static int add_range(sd_netlink_message *m, uint16_t begin, uint16_t end, bool untagged) {
|
||||
int r;
|
||||
|
||||
struct bridge_vlan_info br_vlan;
|
||||
bool done, untagged = false;
|
||||
uint16_t begin, end;
|
||||
int r, cnt;
|
||||
assert(m);
|
||||
assert(begin <= end);
|
||||
assert(end < BRIDGE_VLAN_BITMAP_MAX);
|
||||
|
||||
if (begin == end)
|
||||
return add_single(m, begin, untagged, /* is_pvid = */ false);
|
||||
|
||||
r = sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
|
||||
&(struct bridge_vlan_info) {
|
||||
.vid = begin,
|
||||
.flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
|
||||
BRIDGE_VLAN_INFO_RANGE_BEGIN,
|
||||
},
|
||||
sizeof(struct bridge_vlan_info));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_data(m, IFLA_BRIDGE_VLAN_INFO,
|
||||
&(struct bridge_vlan_info) {
|
||||
.vid = end,
|
||||
.flags = (untagged ? BRIDGE_VLAN_INFO_UNTAGGED : 0) |
|
||||
BRIDGE_VLAN_INFO_RANGE_END,
|
||||
},
|
||||
sizeof(struct bridge_vlan_info));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint16_t link_get_pvid(Link *link, bool *ret_untagged) {
|
||||
assert(link);
|
||||
assert(req);
|
||||
assert(br_vid_bitmap);
|
||||
assert(br_untagged_bitmap);
|
||||
assert(link->network);
|
||||
|
||||
cnt = 0;
|
||||
|
||||
begin = end = UINT16_MAX;
|
||||
for (int k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) {
|
||||
uint32_t untagged_map = br_untagged_bitmap[k];
|
||||
uint32_t vid_map = br_vid_bitmap[k];
|
||||
unsigned base_bit = k * 32;
|
||||
int i = -1;
|
||||
|
||||
done = false;
|
||||
do {
|
||||
int 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 = true;
|
||||
|
||||
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 r;
|
||||
} 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 r;
|
||||
|
||||
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 r;
|
||||
}
|
||||
|
||||
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 (vlanid_is_valid(link->network->bridge_vlan_pvid)) {
|
||||
if (ret_untagged)
|
||||
*ret_untagged = is_bit_set(link->network->bridge_vlan_pvid,
|
||||
link->network->bridge_vlan_untagged_bitmap);
|
||||
return link->network->bridge_vlan_pvid;
|
||||
}
|
||||
|
||||
assert(cnt > 0);
|
||||
return cnt;
|
||||
if (link->network->bridge_vlan_pvid == BRIDGE_VLAN_KEEP_PVID) {
|
||||
if (ret_untagged)
|
||||
*ret_untagged = link->bridge_vlan_pvid_is_untagged;
|
||||
return link->bridge_vlan_pvid;
|
||||
}
|
||||
|
||||
if (ret_untagged)
|
||||
*ret_untagged = false;
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
static int bridge_vlan_append_set_info(Link *link, sd_netlink_message *m) {
|
||||
uint16_t pvid, begin = UINT16_MAX;
|
||||
bool untagged, pvid_is_untagged;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(m);
|
||||
|
||||
pvid = link_get_pvid(link, &pvid_is_untagged);
|
||||
|
||||
for (uint16_t k = 0; k < BRIDGE_VLAN_BITMAP_MAX; k++) {
|
||||
|
||||
if (k == pvid) {
|
||||
/* PVID needs to be sent alone. Finish previous bits. */
|
||||
if (begin != UINT16_MAX) {
|
||||
assert(begin < k);
|
||||
|
||||
r = add_range(m, begin, k - 1, untagged);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
begin = UINT16_MAX;
|
||||
}
|
||||
|
||||
r = add_single(m, pvid, pvid_is_untagged, /* is_pvid = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!is_bit_set(k, link->network->bridge_vlan_bitmap)) {
|
||||
/* This bit is not set. Finish previous bits. */
|
||||
if (begin != UINT16_MAX) {
|
||||
assert(begin < k);
|
||||
|
||||
r = add_range(m, begin, k - 1, untagged);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
begin = UINT16_MAX;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (begin != UINT16_MAX) {
|
||||
bool u;
|
||||
|
||||
assert(begin < k);
|
||||
|
||||
u = is_bit_set(k, link->network->bridge_vlan_untagged_bitmap);
|
||||
if (untagged == u)
|
||||
continue;
|
||||
|
||||
/* Tagging flag is changed from the previous bits. Finish them. */
|
||||
r = add_range(m, begin, k - 1, untagged);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
begin = k;
|
||||
untagged = u;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is the starting point of a new bit sequence. Save the position and the tagging flag. */
|
||||
begin = k;
|
||||
untagged = is_bit_set(k, link->network->bridge_vlan_untagged_bitmap);
|
||||
}
|
||||
|
||||
/* No pending bit sequence.
|
||||
* Why? There is a trick. The conf parsers below only accepts vlan ID in the range 0…4094, but in
|
||||
* the above loop, we run 0…4095. */
|
||||
assert_cc(BRIDGE_VLAN_BITMAP_MAX > VLANID_MAX);
|
||||
assert(begin == UINT16_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bridge_vlan_append_del_info(Link *link, sd_netlink_message *m) {
|
||||
uint16_t pvid, begin = UINT16_MAX;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(m);
|
||||
|
||||
pvid = link_get_pvid(link, NULL);
|
||||
|
||||
for (uint16_t k = 0; k < BRIDGE_VLAN_BITMAP_MAX; k++) {
|
||||
|
||||
if (k == pvid ||
|
||||
!is_bit_set(k, link->bridge_vlan_bitmap) ||
|
||||
is_bit_set(k, link->network->bridge_vlan_bitmap)) {
|
||||
/* This bit is not necessary to be removed. Finish previous bits. */
|
||||
if (begin != UINT16_MAX) {
|
||||
assert(begin < k);
|
||||
|
||||
r = add_range(m, begin, k - 1, /* untagged = */ false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
begin = UINT16_MAX;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (begin != UINT16_MAX)
|
||||
continue;
|
||||
|
||||
/* This is the starting point of a new bit sequence. Save the position. */
|
||||
begin = k;
|
||||
}
|
||||
|
||||
/* No pending bit sequence. */
|
||||
assert(begin == UINT16_MAX);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bridge_vlan_set_message(Link *link, sd_netlink_message *m, bool is_set) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
r = sd_rtnl_message_link_set_family(m, AF_BRIDGE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_open_container(m, 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(m, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (is_set)
|
||||
r = bridge_vlan_append_set_info(link, m);
|
||||
else
|
||||
r = bridge_vlan_append_del_info(link, m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
|
||||
|
||||
int link_update_bridge_vlan(Link *link, sd_netlink_message *m) {
|
||||
_cleanup_free_ void *data = NULL;
|
||||
size_t len;
|
||||
uint16_t begin = UINT16_MAX;
|
||||
int r, family;
|
||||
|
||||
assert(link);
|
||||
assert(m);
|
||||
|
||||
r = sd_rtnl_message_get_family(m, &family);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (family != AF_BRIDGE)
|
||||
return 0;
|
||||
|
||||
r = sd_netlink_message_read_data(m, IFLA_AF_SPEC, &len, &data);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memzero(link->bridge_vlan_bitmap, sizeof(link->bridge_vlan_bitmap));
|
||||
|
||||
for (struct rtattr *rta = data; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
|
||||
struct bridge_vlan_info *p;
|
||||
|
||||
if (RTA_TYPE(rta) != IFLA_BRIDGE_VLAN_INFO)
|
||||
continue;
|
||||
if (RTA_PAYLOAD(rta) != sizeof(struct bridge_vlan_info))
|
||||
continue;
|
||||
|
||||
p = RTA_DATA(rta);
|
||||
|
||||
if (FLAGS_SET(p->flags, BRIDGE_VLAN_INFO_RANGE_BEGIN)) {
|
||||
begin = p->vid;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(p->flags, BRIDGE_VLAN_INFO_RANGE_END)) {
|
||||
for (uint16_t k = begin; k <= p->vid; k++)
|
||||
set_bit(k, link->bridge_vlan_bitmap);
|
||||
|
||||
begin = UINT16_MAX;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (FLAGS_SET(p->flags, BRIDGE_VLAN_INFO_PVID)) {
|
||||
link->bridge_vlan_pvid = p->vid;
|
||||
link->bridge_vlan_pvid_is_untagged = FLAGS_SET(p->flags, BRIDGE_VLAN_INFO_UNTAGGED);
|
||||
}
|
||||
|
||||
set_bit(p->vid, link->bridge_vlan_bitmap);
|
||||
begin = UINT16_MAX;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void network_adjust_bridge_vlan(Network *network) {
|
||||
assert(network);
|
||||
|
||||
if (!network->use_br_vlan)
|
||||
return;
|
||||
for (uint16_t k = 0; k < BRIDGE_VLAN_BITMAP_MAX; k++)
|
||||
if (is_bit_set(k, network->bridge_vlan_untagged_bitmap))
|
||||
set_bit(k, network->bridge_vlan_bitmap);
|
||||
|
||||
/* pvid might not be in br_vid_bitmap yet */
|
||||
if (network->pvid)
|
||||
set_bit(network->pvid, network->br_vid_bitmap);
|
||||
if (vlanid_is_valid(network->bridge_vlan_pvid))
|
||||
set_bit(network->bridge_vlan_pvid, network->bridge_vlan_bitmap);
|
||||
}
|
||||
|
||||
int config_parse_brvlan_pvid(
|
||||
int config_parse_bridge_vlan_id(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -162,21 +333,37 @@ int config_parse_brvlan_pvid(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
uint16_t pvid;
|
||||
uint16_t v, *id = ASSERT_PTR(data);
|
||||
int r;
|
||||
|
||||
r = parse_vlanid(rvalue, &pvid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
network->pvid = pvid;
|
||||
network->use_br_vlan = true;
|
||||
if (isempty(rvalue)) {
|
||||
*id = BRIDGE_VLAN_KEEP_PVID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parse_boolean(rvalue) == 0) {
|
||||
*id = BRIDGE_VLAN_REMOVE_PVID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_vlanid(rvalue, &v);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse %s=, ignoring: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*id = v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_brvlan_vlan(
|
||||
int config_parse_bridge_vlan_id_range(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
|
@ -188,7 +375,7 @@ int config_parse_brvlan_vlan(
|
|||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Network *network = userdata;
|
||||
uint32_t *bitmap = ASSERT_PTR(data);
|
||||
uint16_t vid, vid_end;
|
||||
int r;
|
||||
|
||||
|
@ -196,54 +383,22 @@ int config_parse_brvlan_vlan(
|
|||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
memzero(bitmap, BRIDGE_VLAN_BITMAP_LEN * sizeof(uint32_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = parse_vid_range(rvalue, &vid, &vid_end);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse VLAN, ignoring: %s", rvalue);
|
||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||
"Failed to parse %s=, ignoring: %s",
|
||||
lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; vid <= vid_end; vid++)
|
||||
set_bit(vid, network->br_vid_bitmap);
|
||||
set_bit(vid, bitmap);
|
||||
|
||||
network->use_br_vlan = true;
|
||||
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;
|
||||
uint16_t vid, vid_end;
|
||||
int r;
|
||||
|
||||
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_WARNING, filename, line, r, "Could not parse VLAN: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; vid <= vid_end; vid++) {
|
||||
set_bit(vid, network->br_vid_bitmap);
|
||||
set_bit(vid, network->br_untagged_bitmap);
|
||||
}
|
||||
|
||||
network->use_br_vlan = true;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -6,26 +6,28 @@
|
|||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "vlan-util.h"
|
||||
|
||||
#define BRIDGE_VLAN_BITMAP_MAX 4096
|
||||
#define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32)
|
||||
|
||||
#define BRIDGE_VLAN_KEEP_PVID UINT16_MAX
|
||||
#define BRIDGE_VLAN_REMOVE_PVID (UINT16_MAX - 1)
|
||||
assert_cc(BRIDGE_VLAN_REMOVE_PVID > VLANID_MAX);
|
||||
|
||||
typedef struct Link Link;
|
||||
typedef struct Network Network;
|
||||
|
||||
void network_adjust_bridge_vlan(Network *network);
|
||||
|
||||
int bridge_vlan_append_info(
|
||||
const Link * link,
|
||||
sd_netlink_message *req,
|
||||
uint16_t pvid,
|
||||
const uint32_t *br_vid_bitmap,
|
||||
const uint32_t *br_untagged_bitmap);
|
||||
int bridge_vlan_set_message(Link *link, sd_netlink_message *m, bool is_set);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_pvid);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_vlan);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_brvlan_untagged);
|
||||
int link_update_bridge_vlan(Link *link, sd_netlink_message *m);
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_vlan_id);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_bridge_vlan_id_range);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "networkd-address.h"
|
||||
#include "networkd-bridge-fdb.h"
|
||||
#include "networkd-bridge-mdb.h"
|
||||
#include "networkd-bridge-vlan.h"
|
||||
#include "networkd-can.h"
|
||||
#include "networkd-dhcp-prefix-delegation.h"
|
||||
#include "networkd-dhcp-server.h"
|
||||
|
@ -2435,6 +2436,10 @@ static int link_update(Link *link, sd_netlink_message *message) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_update_bridge_vlan(link, message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return needs_reconfigure;
|
||||
}
|
||||
|
||||
|
@ -2508,6 +2513,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
|||
.ifname = TAKE_PTR(ifname),
|
||||
.kind = TAKE_PTR(kind),
|
||||
|
||||
.bridge_vlan_pvid = UINT16_MAX,
|
||||
|
||||
.ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID,
|
||||
|
||||
.state_file = TAKE_PTR(state_file),
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "log-link.h"
|
||||
#include "netif-util.h"
|
||||
#include "network-util.h"
|
||||
#include "networkd-bridge-vlan.h"
|
||||
#include "networkd-ipv6ll.h"
|
||||
#include "networkd-util.h"
|
||||
#include "ordered-set.h"
|
||||
|
@ -72,6 +73,11 @@ typedef struct Link {
|
|||
sd_device *dev;
|
||||
char *driver;
|
||||
|
||||
/* bridge vlan */
|
||||
uint16_t bridge_vlan_pvid;
|
||||
bool bridge_vlan_pvid_is_untagged;
|
||||
uint32_t bridge_vlan_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||
|
||||
/* to prevent multiple ethtool calls */
|
||||
bool ethtool_driver_read;
|
||||
bool ethtool_permanent_hw_addr_read;
|
||||
|
@ -149,6 +155,7 @@ typedef struct Link {
|
|||
bool activated:1;
|
||||
bool master_set:1;
|
||||
bool stacked_netdevs_created:1;
|
||||
bool bridge_vlan_set:1;
|
||||
|
||||
sd_dhcp_server *dhcp_server;
|
||||
|
||||
|
|
|
@ -753,6 +753,20 @@ static int manager_enumerate_links(Manager *m) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
req = sd_netlink_message_unref(req);
|
||||
|
||||
r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link);
|
||||
}
|
||||
|
||||
|
|
|
@ -510,10 +510,9 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
if (r < 0) {
|
||||
log_warning_errno(r, "rtnl: received neighbor message with invalid state, ignoring: %m");
|
||||
return 0;
|
||||
} else if (!FLAGS_SET(state, NUD_PERMANENT)) {
|
||||
log_debug("rtnl: received non-static neighbor, ignoring.");
|
||||
} else if (!FLAGS_SET(state, NUD_PERMANENT))
|
||||
/* Currently, we are interested in only static neighbors. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_rtnl_message_neigh_get_ifindex(message, &ifindex);
|
||||
if (r < 0) {
|
||||
|
@ -525,12 +524,10 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
}
|
||||
|
||||
r = link_get_by_index(m, ifindex, &link);
|
||||
if (r < 0) {
|
||||
if (r < 0)
|
||||
/* when enumerating we might be out of sync, but we will get the neighbor again. Also,
|
||||
* kernel sends messages about neighbors after a link is removed. So, just ignore it. */
|
||||
log_debug("rtnl: received neighbor for link '%d' we don't know about, ignoring.", ifindex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp = new0(Neighbor, 1);
|
||||
|
||||
|
@ -539,7 +536,10 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
|
|||
if (r < 0) {
|
||||
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
|
||||
return 0;
|
||||
} else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
||||
}
|
||||
if (tmp->family == AF_BRIDGE) /* Currently, we do not support it. */
|
||||
return 0;
|
||||
if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
|
||||
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -368,9 +368,9 @@ BridgeFDB.AssociatedWith, config_parse_fdb_ntf_flags,
|
|||
BridgeFDB.OutgoingInterface, config_parse_fdb_interface, 0, 0
|
||||
BridgeMDB.MulticastGroupAddress, config_parse_mdb_group_address, 0, 0
|
||||
BridgeMDB.VLANId, config_parse_mdb_vlan_id, 0, 0
|
||||
BridgeVLAN.PVID, config_parse_brvlan_pvid, 0, 0
|
||||
BridgeVLAN.VLAN, config_parse_brvlan_vlan, 0, 0
|
||||
BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, 0, 0
|
||||
BridgeVLAN.PVID, config_parse_bridge_vlan_id, 0, offsetof(Network, bridge_vlan_pvid)
|
||||
BridgeVLAN.VLAN, config_parse_bridge_vlan_id_range, 0, offsetof(Network, bridge_vlan_bitmap)
|
||||
BridgeVLAN.EgressUntagged, config_parse_bridge_vlan_id_range, 0, offsetof(Network, bridge_vlan_untagged_bitmap)
|
||||
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)
|
||||
|
|
|
@ -450,6 +450,8 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
|||
.priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
|
||||
.multicast_router = _MULTICAST_ROUTER_INVALID,
|
||||
|
||||
.bridge_vlan_pvid = BRIDGE_VLAN_KEEP_PVID,
|
||||
|
||||
.lldp_mode = LLDP_MODE_ROUTERS_ONLY,
|
||||
.lldp_multicast_mode = _SD_LLDP_MULTICAST_MODE_INVALID,
|
||||
|
||||
|
|
|
@ -289,10 +289,9 @@ struct Network {
|
|||
MulticastRouter multicast_router;
|
||||
|
||||
/* Bridge VLAN */
|
||||
bool use_br_vlan;
|
||||
uint16_t pvid;
|
||||
uint32_t br_vid_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||
uint32_t br_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||
uint16_t bridge_vlan_pvid;
|
||||
uint32_t bridge_vlan_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||
uint32_t bridge_vlan_untagged_bitmap[BRIDGE_VLAN_BITMAP_LEN];
|
||||
|
||||
/* CAN support */
|
||||
uint32_t can_bitrate;
|
||||
|
|
|
@ -312,7 +312,8 @@ static const char *const request_type_table[_REQUEST_TYPE_MAX] = {
|
|||
[REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE] = "IPv6LL address generation mode",
|
||||
[REQUEST_TYPE_SET_LINK_BOND] = "bond configurations",
|
||||
[REQUEST_TYPE_SET_LINK_BRIDGE] = "bridge configurations",
|
||||
[REQUEST_TYPE_SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations",
|
||||
[REQUEST_TYPE_SET_LINK_BRIDGE_VLAN] = "bridge VLAN configurations (step 1)",
|
||||
[REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN] = "bridge VLAN configurations (step 2)",
|
||||
[REQUEST_TYPE_SET_LINK_CAN] = "CAN interface configurations",
|
||||
[REQUEST_TYPE_SET_LINK_FLAGS] = "link flags",
|
||||
[REQUEST_TYPE_SET_LINK_GROUP] = "interface group",
|
||||
|
|
|
@ -37,6 +37,7 @@ typedef enum RequestType {
|
|||
REQUEST_TYPE_SET_LINK_BOND, /* Setting bond configs. */
|
||||
REQUEST_TYPE_SET_LINK_BRIDGE, /* Setting bridge configs. */
|
||||
REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, /* Setting bridge VLAN configs. */
|
||||
REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN, /* Removing bridge VLAN configs. */
|
||||
REQUEST_TYPE_SET_LINK_CAN, /* Setting CAN interface configs. */
|
||||
REQUEST_TYPE_SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */
|
||||
REQUEST_TYPE_SET_LINK_GROUP, /* Setting interface group. */
|
||||
|
|
|
@ -103,6 +103,19 @@ static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Requ
|
|||
}
|
||||
|
||||
static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
link->bridge_vlan_set = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int link_del_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) {
|
||||
return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL);
|
||||
}
|
||||
|
||||
|
@ -326,29 +339,14 @@ static int link_configure_fill_message(
|
|||
return r;
|
||||
break;
|
||||
case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN:
|
||||
r = sd_rtnl_message_link_set_family(req, AF_BRIDGE);
|
||||
r = bridge_vlan_set_message(link, req, /* is_set = */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_open_container(req, IFLA_AF_SPEC);
|
||||
break;
|
||||
case REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN:
|
||||
r = bridge_vlan_set_message(link, req, /* is_set = */ false);
|
||||
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_vlan_append_info(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_close_container(req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
case REQUEST_TYPE_SET_LINK_CAN:
|
||||
r = can_set_netlink_message(link, req);
|
||||
|
@ -430,6 +428,8 @@ static int link_configure(Link *link, Request *req) {
|
|||
r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->master_ifindex);
|
||||
else if (IN_SET(req->type, REQUEST_TYPE_SET_LINK_CAN, REQUEST_TYPE_SET_LINK_IPOIB))
|
||||
r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex);
|
||||
else if (req->type == REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN)
|
||||
r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_DELLINK, link->ifindex);
|
||||
else
|
||||
r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex);
|
||||
if (r < 0)
|
||||
|
@ -480,9 +480,11 @@ static int link_is_ready_to_set_link(Link *link, Request *req) {
|
|||
|
||||
if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge"))
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN:
|
||||
return link->bridge_vlan_set;
|
||||
|
||||
case REQUEST_TYPE_SET_LINK_CAN:
|
||||
/* Do not check link->set_flgas_messages here, as it is ok even if link->flags
|
||||
* is outdated, and checking the counter causes a deadlock. */
|
||||
|
@ -704,10 +706,14 @@ int link_request_to_set_bridge(Link *link) {
|
|||
}
|
||||
|
||||
int link_request_to_set_bridge_vlan(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
|
||||
if (!link->network->use_br_vlan)
|
||||
/* If nothing configured, use the default vlan ID. */
|
||||
if (memeqzero(link->network->bridge_vlan_bitmap, BRIDGE_VLAN_BITMAP_LEN * sizeof(uint32_t)) &&
|
||||
link->network->bridge_vlan_pvid == BRIDGE_VLAN_KEEP_PVID)
|
||||
return 0;
|
||||
|
||||
if (!link->network->bridge && !streq_ptr(link->kind, "bridge")) {
|
||||
|
@ -723,9 +729,21 @@ int link_request_to_set_bridge_vlan(Link *link) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN,
|
||||
link_set_bridge_vlan_handler,
|
||||
NULL);
|
||||
link->bridge_vlan_set = false;
|
||||
|
||||
r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN,
|
||||
link_set_bridge_vlan_handler,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = link_request_set_link(link, REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN,
|
||||
link_del_bridge_vlan_handler,
|
||||
NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_request_to_set_can(Link *link) {
|
||||
|
|
|
@ -6,4 +6,8 @@ Name=bridge99
|
|||
IPv6AcceptRA=false
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=4060-4094
|
||||
PVID=1020
|
||||
VLAN=1018-1023
|
||||
VLAN=1200-1210
|
||||
EgressUntagged=1022-1025
|
||||
EgressUntagged=1203-1208
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=
|
||||
VLAN=
|
||||
EgressUntagged=
|
||||
|
||||
PVID=2020
|
||||
VLAN=2018-2023
|
||||
VLAN=2200-2210
|
||||
EgressUntagged=2022-2025
|
||||
EgressUntagged=2203-2208
|
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=
|
||||
VLAN=
|
||||
EgressUntagged=
|
||||
|
||||
PVID=2020
|
||||
VLAN=2018-2023
|
||||
EgressUntagged=2022-2025
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=no
|
||||
VLAN=
|
||||
EgressUntagged=
|
|
@ -7,4 +7,8 @@ IPv6AcceptRA=no
|
|||
Bridge=bridge99
|
||||
|
||||
[BridgeVLAN]
|
||||
VLAN=4064-4094
|
||||
PVID=1010
|
||||
VLAN=1008-1013
|
||||
VLAN=1100-1110
|
||||
EgressUntagged=1012-1015
|
||||
EgressUntagged=1103-1108
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=
|
||||
VLAN=
|
||||
EgressUntagged=
|
||||
|
||||
PVID=2010
|
||||
VLAN=2008-2013
|
||||
VLAN=2100-2110
|
||||
EgressUntagged=2012-2015
|
||||
EgressUntagged=2103-2108
|
|
@ -0,0 +1,9 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=
|
||||
VLAN=
|
||||
EgressUntagged=
|
||||
|
||||
PVID=2010
|
||||
VLAN=2008-2013
|
||||
EgressUntagged=2012-2015
|
|
@ -0,0 +1,5 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[BridgeVLAN]
|
||||
PVID=no
|
||||
VLAN=
|
||||
EgressUntagged=
|
|
@ -4422,23 +4422,116 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities):
|
|||
|
||||
def test_bridge_vlan(self):
|
||||
copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave.network',
|
||||
'26-bridge.netdev', '26-bridge-vlan-master.network')
|
||||
'26-bridge.netdev', '26-bridge-vlan-master.network',
|
||||
copy_dropins=False)
|
||||
start_networkd()
|
||||
self.wait_online(['test1:enslaved', 'bridge99:degraded'])
|
||||
|
||||
output = check_output('bridge vlan show dev test1')
|
||||
print(output)
|
||||
self.assertNotRegex(output, '4063')
|
||||
for i in range(4064, 4095):
|
||||
self.assertRegex(output, f'{i}')
|
||||
self.assertNotRegex(output, '4095')
|
||||
# check if the default VID is removed
|
||||
self.assertNotIn('1 Egress Untagged', output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 1010:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(1012, 1016) or i in range(1103, 1109):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(1008, 1014) or i in range(1100, 1111):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
output = check_output('bridge vlan show dev bridge99')
|
||||
print(output)
|
||||
self.assertNotRegex(output, '4059')
|
||||
for i in range(4060, 4095):
|
||||
self.assertRegex(output, f'{i}')
|
||||
self.assertNotRegex(output, '4095')
|
||||
# check if the default VID is removed
|
||||
self.assertNotIn('1 Egress Untagged', output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 1020:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(1022, 1026) or i in range(1203, 1209):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(1018, 1024) or i in range(1200, 1211):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
# Change vlan IDs
|
||||
copy_network_unit('26-bridge-vlan-slave.network.d/10-override.conf',
|
||||
'26-bridge-vlan-master.network.d/10-override.conf')
|
||||
networkctl_reload()
|
||||
self.wait_online(['test1:enslaved', 'bridge99:degraded'])
|
||||
|
||||
output = check_output('bridge vlan show dev test1')
|
||||
print(output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 2010:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(2012, 2016) or i in range(2103, 2109):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(2008, 2014) or i in range(2100, 2111):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
output = check_output('bridge vlan show dev bridge99')
|
||||
print(output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 2020:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(2022, 2026) or i in range(2203, 2209):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(2018, 2024) or i in range(2200, 2211):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
# Remove several vlan IDs
|
||||
copy_network_unit('26-bridge-vlan-slave.network.d/20-override.conf',
|
||||
'26-bridge-vlan-master.network.d/20-override.conf')
|
||||
networkctl_reload()
|
||||
self.wait_online(['test1:enslaved', 'bridge99:degraded'])
|
||||
|
||||
output = check_output('bridge vlan show dev test1')
|
||||
print(output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 2010:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(2012, 2016):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(2008, 2014):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
output = check_output('bridge vlan show dev bridge99')
|
||||
print(output)
|
||||
for i in range(1000, 3000):
|
||||
if i == 2020:
|
||||
self.assertIn(f'{i} PVID', output)
|
||||
elif i in range(2022, 2026):
|
||||
self.assertIn(f'{i} Egress Untagged', output)
|
||||
elif i in range(2018, 2024):
|
||||
self.assertIn(f'{i}', output)
|
||||
else:
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
# Remove all vlan IDs
|
||||
copy_network_unit('26-bridge-vlan-slave.network.d/30-override.conf',
|
||||
'26-bridge-vlan-master.network.d/30-override.conf')
|
||||
networkctl_reload()
|
||||
self.wait_online(['test1:enslaved', 'bridge99:degraded'])
|
||||
|
||||
output = check_output('bridge vlan show dev test1')
|
||||
print(output)
|
||||
self.assertNotIn('PVID', output)
|
||||
for i in range(1000, 3000):
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
output = check_output('bridge vlan show dev bridge99')
|
||||
print(output)
|
||||
self.assertNotIn('PVID', output)
|
||||
for i in range(1000, 3000):
|
||||
self.assertNotIn(f'{i}', output)
|
||||
|
||||
def test_bridge_vlan_issue_20373(self):
|
||||
copy_network_unit('11-dummy.netdev', '26-bridge-vlan-slave-issue-20373.network',
|
||||
|
|
Loading…
Reference in a new issue