Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
networkd: Add bridge port priority setting #5545
Conversation
|
I've tested this successfully works as intended on Ubuntu development release (zesty 17.04) |
martinpitt
requested changes
Mar 7, 2017
LGTM, thanks! But this could do with a test case in test/networkd-test.py. I suppose the priority can be verified through bridge link show or sysfs?
martinpitt
added
the
network
label
Mar 7, 2017
|
@martinpitt there are no bridge tests in test/networkd-test.py do you want me to create interface(s) and add them into a bridge to test these? |
|
@xnox: Ah right (seems we seriously lack bridge tests then). But that should be straightforward to add, so why not start with this feature. Are you generally able to run those? Unless you use networkd, they should be safe to run on your laptop, otherwise you can run them in lxd or an autopkgtest VM (Debian's systemd package also runs it as autopkgtest). |
|
@martinpitt I don't think the new bridge tests need to be part of this merge proposal. It seems like bridge test for networkd-test.py deserve a separate merge proposal. |
xnox
referenced this pull request
Mar 7, 2017
Closed
networkd-test.py should test Bridge and Bridge port features of networkd #5550
| @@ -1325,6 +1325,11 @@ static int link_set_bridge(Link *link) { | ||
| if (r < 0) | ||
| return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); | ||
| } | ||
| + if (link->network->priority != 0) { |
xnox
Mar 10, 2017
Contributor
If I am reading the kernel source code right, the default priority is 32, so I could set 32 as the default value in the gperf . Then change this condition and only set priority when it's not 32? Or e.g. always set it? (But then default priority definition effectively moves from kernel to systemd)
xnox
Mar 13, 2017
Contributor
Actually using an invalid value by default makes sense. Thus I now set priority at 128, which means don't update the priority such that whichever priority the device is at, it would stick. This is similar to using 0 in the path_cost, as 0 is an invalid setting for the path_cost.
ssahani
Mar 13, 2017
Contributor
That ok as we already have such settings #define DEFAULT_TNL_HOP_LIMIT 64.
Default priority 32768 .
sudo ip link add name bridge_name type bridge
$ ip -d link show bridge_name | grep priority
bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.0:0:0:0:0:0 designated_root 8000.0:0:0:0:0:0 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 0.00 vlan_default_pvid 1 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4 mcast_hash_max 512 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1
ssahani
Mar 13, 2017
Contributor
The default as it looks 32768
ip -d link show bridge_name
8: bridge_name: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 6a:67:73:86:30:e2 brd ff:ff:ff:ff:ff:ff promiscuity 0
bridge forward_delay 1500 hello_time 200 max_age 2000 ageing_time 30000 stp_state 0 priority 32768 vlan_filtering 0 vlan_protocol 802.1Q bridge_id 8000.0:0:0:0:0:0 designated_root 8000.0:0:0:0:0:0 root_port 0 root_path_cost 0 topology_change 0 topology_change_detected 0 hello_timer 0.00 tcn_timer 0.00 topology_change_timer 0.00 gc_timer 0.00 vlan_default_pvid 1 group_fwd_mask 0 group_address 01:80:c2:00:00:00 mcast_snooping 1 mcast_router 1 mcast_query_use_ifaddr 0 mcast_querier 0 mcast_hash_elasticity 4 mcast_hash_max 512 mcast_last_member_count 2 mcast_startup_query_count 2 mcast_last_member_interval 100 mcast_membership_interval 26000 mcast_querier_interval 25500 mcast_query_interval 12500 mcast_query_response_interval 1000 mcast_startup_query_interval 3125 nf_call_iptables 0 nf_call_ip6tables 0 nf_call_arptables 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1
Please use #define DEFAULT_ABC 100
xnox
Mar 15, 2017
Contributor
@ssahani that is Bridge's priority. I'm working on Bridge Port's priority which is 32 with $ ip -d link show eth0 in the line prefixed "bridge_slave". Please see updated testsuite. Note, previously systemd would use [BridgePort] section in the .network file to define bridge port settings, but that was renamed to just [Bridge]. The sysfs file for it is /sys/class/net/port1/brport/priority and 128 is an out of range value for it.
|
@martinpitt I have addressed your request for a testcase which is now part of this merge proposal. |
martinpitt
requested changes
Mar 20, 2017
Looks great, thanks for adding those! I have a couple of nitpicks, but the biggest issue is that the test seems to have a race condition because it doesn't wait for the bridge to become online?
| @@ -1325,6 +1325,11 @@ static int link_set_bridge(Link *link) { | ||
| if (r < 0) | ||
| return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); | ||
| } | ||
| + if (link->network->priority != 128) { |
martinpitt
Mar 20, 2017
Contributor
Please replace the magic 128 with a macro like LINK_PRIORITY_INVALID.
| @@ -165,6 +165,7 @@ static int network_load_one(Manager *manager, const char *filename) { | ||
| network->use_bpdu = true; | ||
| network->allow_port_to_be_root = true; | ||
| network->unicast_flood = true; | ||
| + network->priority = 128; |
| with open(dropin_path, 'w') as dropin: | ||
| dropin.write(contents) | ||
| self.addCleanup(os.remove, dropin_path) | ||
| + def read_attr(self, link, attribute): | ||
| + """Read a link attributed from the sysfs.""" | ||
| + self.assert_link_states(**{link:'managed'}) |
martinpitt
Mar 20, 2017
Contributor
assert_link_states(link="managed") is much more natural and cleaner to read.
xnox
Mar 27, 2017
Contributor
actually no, I cannot use "nice" syntax. As I don't want to pass {"link":"managed"} kwarg, but i want to pass {*link: "managed"} kwarg, e.g. when read_attr("eth0", "foo") is passed, I want to call assert_link_states(eth0="managed"), not assert_link_states(link="managed").
| + def read_attr(self, link, attribute): | ||
| + """Read a link attributed from the sysfs.""" | ||
| + self.assert_link_states(**{link:'managed'}) | ||
| + with open('/'.join(['/sys/class/net', link, attribute])) as f: |
| +DNS=192.168.250.1 | ||
| +Address=192.168.250.33/24 | ||
| +Gateway=192.168.250.1''') | ||
| + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) |
martinpitt
Mar 20, 2017
Contributor
None of the tests call NETWORKD_WAIT_ONLINE, so how is that not racy?
xnox
Mar 27, 2017
Contributor
All of them do indirectly...
They call read_attr, which always calls to assert_link_states, which calls NETWORKD_WAIT_ONLINE
martinpitt
Mar 31, 2017
Contributor
OK. Can you please add this as a comment to read_attr()'s docstring, as it's not really evident at first sight? Thanks!
| + self.assert_link_states( | ||
| + port1='managed', | ||
| + port2='managed', | ||
| + mybridge='managed') |
martinpitt
added
the
reviewed/needs-rework
label
Mar 20, 2017
|
Pushed updates; and rebutted one comment. The comments above were misplaced a bit. Still need to retest the updated code. |
poettering
requested changes
Mar 30, 2017
a few notes.
(yeah, it's a bit unfair, as the Cost= field doesn't get all this right either, but we really should fix that too, and get it right for Priority= from the beginning.)
(Bonus points if you fix the Cost= type chaos too btw... ;-))
| + <listitem> | ||
| + <para>Sets the "priority" of sending packets on this interface. | ||
| + Each port in a bridge may have a different priority which is used | ||
| + to decide which link to use.</para> |
poettering
Mar 30, 2017
Owner
please document here that this an integer, which range is permissible and whether the higher priority is referred to by higher or lower numbers.
poettering
Mar 30, 2017
Owner
(extra bonus points if you add the same for Cost=, where this was forgotten...)
| @@ -125,6 +125,7 @@ Bridge.HairPin, config_parse_bool, | ||
| Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave) | ||
| Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root) | ||
| Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) | ||
| +Bridge.Priority, config_parse_unsigned, 0, offsetof(Network, priority) |
| @@ -164,6 +164,7 @@ struct Network { | ||
| bool allow_port_to_be_root; | ||
| bool unicast_flood; | ||
| unsigned cost; | ||
| + unsigned priority; |
poettering
Mar 30, 2017
Owner
hmm, you define that as "unsigned" here (i.e. 32bit), but the netlink type appears to be 16bit only. Hence please use uint16_t here too, so that we use the same and correct type all the way
poettering
Mar 30, 2017
Owner
(and yeah, "cost" appears broken too, the netlink type appears to be uint32_t, and not unsigned, and we should use uint32_t here hence too...)
xnox
Apr 11, 2017
Contributor
.... and despite netlink type uint16_t, the actual bridge port priority valid values are 0..63. And brctl manpage is a lie.
|
patch looks pretty OK to me, except for the type issues, see comments. I'll leave the review of the python test code to @martinpitt, he's our python test guru! ;-) |
martinpitt
approved these changes
Mar 31, 2017
Tests look good to me, aside from the read_attr docstring. Please fix that along with Lennart's review points, then this should be golden. Thanks!
| with open(dropin_path, 'w') as dropin: | ||
| dropin.write(contents) | ||
| self.addCleanup(os.remove, dropin_path) | ||
| + def read_attr(self, link, attribute): | ||
| + """Read a link attributed from the sysfs.""" | ||
| + self.assert_link_states(**{link:'managed'}) |
martinpitt
Mar 20, 2017
Contributor
assert_link_states(link="managed") is much more natural and cleaner to read.
xnox
Mar 27, 2017
Contributor
actually no, I cannot use "nice" syntax. As I don't want to pass {"link":"managed"} kwarg, but i want to pass {*link: "managed"} kwarg, e.g. when read_attr("eth0", "foo") is passed, I want to call assert_link_states(eth0="managed"), not assert_link_states(link="managed").
| +DNS=192.168.250.1 | ||
| +Address=192.168.250.33/24 | ||
| +Gateway=192.168.250.1''') | ||
| + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) |
martinpitt
Mar 20, 2017
Contributor
None of the tests call NETWORKD_WAIT_ONLINE, so how is that not racy?
xnox
Mar 27, 2017
Contributor
All of them do indirectly...
They call read_attr, which always calls to assert_link_states, which calls NETWORKD_WAIT_ONLINE
martinpitt
Mar 31, 2017
Contributor
OK. Can you please add this as a comment to read_attr()'s docstring, as it's not really evident at first sight? Thanks!
|
I think I have addressed all the comments from the last round of review now. |
|
Thanks @xnox for the updates! @poettering's and my comments are addressed, tests are green. |
martinpitt
merged commit b56be29
into
systemd:master
Apr 11, 2017
| @@ -119,12 +119,13 @@ DHCPServer.EmitTimezone, config_parse_bool, | ||
| DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) | ||
| DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) | ||
| DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size) | ||
| -Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) | ||
| +Bridge.Cost, config_parse_uint32, 0, offsetof(Network, cost) |
poettering
Apr 12, 2017
Owner
uh, this is problematic. You also have to change the type in the Network structure now... The config_parse_xxx() call always should match the type used. Meaning: if there's a variable of type "uint32_t" you should use config_parse_uint32 and if there's one of type "unsigned" you should use config_parse_unsigned... Hence, please fix the type here too...
Yes, on all archs we support uint32_t and unsigned are the same size, but still, we should always use the appropriate types through the entire pipeline
xnox
Apr 18, 2017
Contributor
But I have changed offsetof(Network, cost) in src/network/networkd-network.h whilst doing so. No further actions needed here, then?
- unsigned cost;
+ uint32_t cost;
+ uint16_t priority;
| Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu) | ||
| Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin) | ||
| Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave) | ||
| Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root) | ||
| Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) | ||
| +Bridge.Priority, config_parse_uint16, 0, offsetof(Network, priority) |
poettering
Apr 12, 2017
Owner
If the priority value only as a small permitted range, then please provide a smal config_parse_bridge_priority() call that does what config_parse_uint16 does, but also filters out the invalid range...
xnox
Apr 18, 2017
Contributor
I was pondering that, such that logs will print that invalid values have been specified.
xnox commentedMar 6, 2017
Allow setting bridge port priority in the Bridge section of the network file,
similar to e.g. bridge port path cost setting.