Interfaces: Other Types: LAGG - support a primary interface in failover mode, closes https://github.com/opnsense/core/issues/7306

- cleanup model validation a bit while here
- fix a minor glitch in legacy_interfaces_details() which lost laggport on non lacp variants.
This commit is contained in:
Ad Schellevis 2024-03-09 18:31:56 +01:00
parent c94f8fc968
commit f037dc01e2
5 changed files with 47 additions and 22 deletions

View File

@ -411,6 +411,10 @@ function _interfaces_lagg_configure($lagg)
$interface_stats = legacy_interfaces_details();
$members = explode(',', $lagg['members']);
if (!empty($lagg['primary_member'])) {
/* place primary member as first member */
$members = array_unique(array_merge([$lagg['primary_member']], $members));
}
if (empty($interface_stats[$lagg['laggif']])) {
legacy_interface_create($lagg['laggif']);

View File

@ -416,13 +416,16 @@ function legacy_interfaces_details($intf = null)
$result[$current_interface]['laggstatistics']['active ports'] = trim(explode(":", $next_line)[1]);
$next_line = $ifconfig_data[$lineid + 2];
$result[$current_interface]['laggstatistics']['flapping'] = trim(explode(":", $next_line)[1]);
} elseif (preg_match("/laggport: (.*)\Wflags=\d+<(.*)> state=\d+<(.*)>$/", $line, $matches)) {
} elseif (
preg_match("/laggport: (.*)\Wflags=\d+<(.*)> state=\d+<(.*)>$/", $line, $matches) ||
preg_match("/laggport: (.*)\Wflags=\d+<(.*)>.*/", $line, $matches)
) {
if (empty($result[$current_interface]['laggport'])) {
$result[$current_interface]['laggport'] = [];
}
$result[$current_interface]['laggport'][trim($matches[1])] = [
"flags" => explode(",", strtolower($matches[2])),
"state" => explode(",", strtolower($matches[3])),
"state" => isset($matches[3]) ? explode(",", strtolower($matches[3])) : [],
];
} elseif (strpos($line, "\tgroups: ") !== false) {
array_shift($line_parts);

View File

@ -17,6 +17,13 @@
<type>dropdown</type>
<help>The protocol to use, please refer to the documentation for a detailed explanation of the various types available</help>
</field>
<field>
<id>lagg.primary_member</id>
<label>Primary interface</label>
<type>dropdown</type>
<style>selectpicker proto proto_failover</style>
<help>This interface will be added first in the lagg making it the primary one.</help>
</field>
<field>
<id>lagg.lacp_fast_timeout</id>
<label>Fast timeout</label>

View File

@ -55,28 +55,37 @@ class Lagg extends BaseModel
}
}
}
foreach ($this->getFlatNodes() as $key => $node) {
if ($validateFullModel || $node->isFieldChanged()) {
if ($node->getParentNode()->getInternalXMLTagName() === 'lagg') {
$uuid = $node->getParentNode()->getAttributes()['uuid'];
if ($node->getInternalXMLTagName() == 'members') {
$tmp = [];
foreach (explode(',', (string)$node) as $intf) {
if (!empty($members[$intf]) && count($members[$intf]) > 1) {
$tmp[] = $intf;
}
}
if (!empty($tmp)) {
$messages->appendMessage(
new Message(
sprintf(gettext('Members %s are already used in other laggs.'), implode(',', $tmp)),
$key
)
);
}
}
foreach ($this->lagg->iterateItems() as $node) {
if (!$validateFullModel && !$node->isFieldChanged()) {
continue;
}
$uuid = $node->getAttributes()['uuid'];
$key = $node->__reference;
$members = explode(',', (string)$node->members);
$tmp = [];
foreach ($members as $intf) {
if (!empty($members[$intf]) && count($members[$intf]) > 1) {
$tmp[] = $intf;
}
}
if (!empty($tmp)) {
$messages->appendMessage(
new Message(
sprintf(gettext('Members %s are already used in other laggs.'), implode(',', $tmp)),
$key . '.members'
)
);
}
if (!empty((string)$node->primary_member) && !in_array((string)$node->primary_member, $members)) {
$messages->appendMessage(
new Message(
sprintf(gettext('Primary member %s not in member list.'), (string)$node->primary_member),
$key . '.primary_member'
)
);
}
}
return $messages;
}

View File

@ -19,6 +19,8 @@
<Multiple>Y</Multiple>
<ValidationMessage>At least one valid member is required</ValidationMessage>
</members>
<primary_member type=".\LaggInterfaceField">
</primary_member>
<proto type="OptionField">
<Required>Y</Required>
<Default>lacp</Default>