diff --git a/src/etc/inc/interfaces.inc b/src/etc/inc/interfaces.inc index f73c8dd8f..f28dc2d4f 100644 --- a/src/etc/inc/interfaces.inc +++ b/src/etc/inc/interfaces.inc @@ -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']); diff --git a/src/etc/inc/interfaces.lib.inc b/src/etc/inc/interfaces.lib.inc index 0a165369d..e56bba260 100644 --- a/src/etc/inc/interfaces.lib.inc +++ b/src/etc/inc/interfaces.lib.inc @@ -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); diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml index 141f28f99..de90f954d 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml +++ b/src/opnsense/mvc/app/controllers/OPNsense/Interfaces/forms/dialogLagg.xml @@ -17,6 +17,13 @@ dropdown The protocol to use, please refer to the documentation for a detailed explanation of the various types available + + lagg.primary_member + + dropdown + + This interface will be added first in the lagg making it the primary one. + lagg.lacp_fast_timeout diff --git a/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.php b/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.php index bd8e397dc..ea242b391 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.php +++ b/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.php @@ -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; } diff --git a/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.xml b/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.xml index 251f86adb..5dce29295 100644 --- a/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.xml +++ b/src/opnsense/mvc/app/models/OPNsense/Interfaces/Lagg.xml @@ -19,6 +19,8 @@ Y At least one valid member is required + + Y lacp