diff --git a/doc/netplan.md b/doc/netplan.md index 728c26a..b6497a9 100644 --- a/doc/netplan.md +++ b/doc/netplan.md @@ -262,6 +262,12 @@ Properties for device type ``bridges:`` priority. The bridge with the higher priority will be elected as the root bridge. + ``port-priority`` (scalar) + : Set the port priority to . The priority value is + an unsigned 8-bit quantity (a number between ``0`` and ``255``), + and has no dimension. This metric is used in the designated port and + root port selection algorithms. + ``forward-delay`` (scalar) : Specify the period of time the bridge will remain in Listening and Learning states before getting to the Forwarding state. This value diff --git a/src/networkd.c b/src/networkd.c index 73444e3..376aebf 100644 --- a/src/networkd.c +++ b/src/networkd.c @@ -261,8 +261,12 @@ write_network_file(net_definition* def, const char* rootdir, const char* path) if (def->bridge) { g_string_append_printf(s, "Bridge=%s\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n", def->bridge); + if (def->bridge_params.path_cost || def->bridge_params.port_priority) + g_string_append_printf(s, "\n[Bridge]\n"); if (def->bridge_params.path_cost) - g_string_append_printf(s, "\n[Bridge]\nCost=%u\n", def->bridge_params.path_cost); + g_string_append_printf(s, "Cost=%u\n", def->bridge_params.path_cost); + if (def->bridge_params.port_priority) + g_string_append_printf(s, "Priority=%u\n", def->bridge_params.port_priority); } if (def->bond) { g_string_append_printf(s, "Bond=%s\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n", def->bond); diff --git a/src/parse.c b/src/parse.c index 56ea9b6..8c1d8b9 100644 --- a/src/parse.c +++ b/src/parse.c @@ -767,9 +767,45 @@ handle_bridge_path_cost(yaml_document_t* doc, yaml_node_t* node, const void* dat return TRUE; } +static gboolean +handle_bridge_port_priority(yaml_document_t* doc, yaml_node_t* node, const void* data, GError** error) +{ + for (yaml_node_pair_t* entry = node->data.mapping.pairs.start; entry < node->data.mapping.pairs.top; entry++) { + yaml_node_t* key, *value; + guint v; + gchar* endptr; + net_definition *component; + guint* ref_ptr; + + key = yaml_document_get_node(doc, entry->key); + assert_type(key, YAML_SCALAR_NODE); + value = yaml_document_get_node(doc, entry->value); + assert_type(value, YAML_SCALAR_NODE); + + component = g_hash_table_lookup(netdefs, scalar(key)); + if (!component) { + add_missing_node(key); + } else { + ref_ptr = ((guint*) ((void*) component + GPOINTER_TO_UINT(data))); + if (*ref_ptr) + return yaml_error(node, error, "%s: interface %s already has a port priority of %u", + cur_netdef->id, scalar(key), *ref_ptr); + + v = g_ascii_strtoull(scalar(value), &endptr, 10); + if (*endptr != '\0' || v > G_MAXINT8) + return yaml_error(node, error, "invalid unsigned int 8-bit value %s", scalar(value)); + + g_debug("%s: adding port '%s' of priority: %d", cur_netdef->id, scalar(key), v); + + *ref_ptr = v; + } + } + return TRUE; +} const mapping_entry_handler bridge_params_handlers[] = { {"ageing-time", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.ageing_time)}, {"priority", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.priority)}, + {"port-priority", YAML_MAPPING_NODE, handle_bridge_port_priority, NULL, netdef_offset(bridge_params.port_priority)}, {"forward-delay", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.forward_delay)}, {"hello-time", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.hello_time)}, {"max-age", YAML_SCALAR_NODE, handle_netdef_guint, NULL, netdef_offset(bridge_params.max_age)}, diff --git a/src/parse.h b/src/parse.h index 14bd719..fe05a71 100644 --- a/src/parse.h +++ b/src/parse.h @@ -128,6 +128,7 @@ typedef struct net_definition { struct { guint ageing_time; guint priority; + guint port_priority; guint forward_delay; guint hello_time; guint max_age; diff --git a/tests/generate.py b/tests/generate.py index b3b202f..303f5f5 100755 --- a/tests/generate.py +++ b/tests/generate.py @@ -977,6 +977,8 @@ unmanaged-devices+=interface-name:eth42,interface-name:eth43,interface-name:mybr stp: true path-cost: eno1: 70 + port-priority: + eno1: 14 dhcp4: true''') self.assert_networkd({'br0.netdev': '[NetDev]\nName=br0\nKind=bridge\n\n' @@ -989,7 +991,7 @@ unmanaged-devices+=interface-name:eth42,interface-name:eth43,interface-name:mybr 'br0.network': ND_DHCP4 % 'br0', 'eno1.network': '[Match]\nName=eno1\n\n' '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n\n' - '[Bridge]\nCost=70\n', + '[Bridge]\nCost=70\nPriority=14\n', 'switchports.network': '[Match]\nDriver=yayroute\n\n' '[Network]\nBridge=br0\nLinkLocalAddressing=no\nIPv6AcceptRA=no\n'}) @@ -2407,6 +2409,7 @@ master=br0 [bridge-port] path-cost=70 + [ethernet] wake-on-lan=0