$bdescr) { if (substr(get_real_interface($bif), 0, 3) == "gre") { unset($ifacelist[$bif]); } } if (is_numericint($_GET['id'])) { $id = $_GET['id']; } if (isset($_POST['id']) && is_numericint($_POST['id'])) { $id = $_POST['id']; } if (isset($id) && $a_bridges[$id]) { $pconfig['enablestp'] = isset($a_bridges[$id]['enablestp']); $pconfig['descr'] = $a_bridges[$id]['descr']; $pconfig['bridgeif'] = $a_bridges[$id]['bridgeif']; $pconfig['members'] = $a_bridges[$id]['members']; $pconfig['maxaddr'] = $a_bridges[$id]['maxaddr']; $pconfig['timeout'] = $a_bridges[$id]['timeout']; $pconfig['maxage'] = $a_bridges[$id]['maxage']; $pconfig['fwdelay'] = $a_bridges[$id]['fwdelay']; $pconfig['hellotime'] = $a_bridges[$id]['hellotime']; $pconfig['priority'] = $a_bridges[$id]['priority']; $pconfig['proto'] = $a_bridges[$id]['proto']; $pconfig['holdcnt'] = $a_bridges[$id]['holdcnt']; if (!empty($a_bridges[$id]['ifpriority'])) { $pconfig['ifpriority'] = explode(",", $a_bridges[$id]['ifpriority']); $ifpriority = array(); foreach ($pconfig['ifpriority'] as $cfg) { list ($key, $value) = explode(":", $cfg); $embprioritycfg[$key] = $value; foreach ($embprioritycfg as $key => $value) { $ifpriority[$key] = $value; } } $pconfig['ifpriority'] = $ifpriority; } if (!empty($a_bridges[$id]['ifpathcost'])) { $pconfig['ifpathcost'] = explode(",", $a_bridges[$id]['ifpathcost']); $ifpathcost = array(); foreach ($pconfig['ifpathcost'] as $cfg) { list ($key, $value) = explode(":", $cfg); $embpathcfg[$key] = $value; foreach ($embpathcfg as $key => $value) { $ifpathcost[$key] = $value; } } $pconfig['ifpathcost'] = $ifpathcost; } if (isset($a_bridges[$id]['static'])) { $pconfig['static'] = $a_bridges[$id]['static']; } if (isset($a_bridges[$id]['private'])) { $pconfig['private'] = $a_bridges[$id]['private']; } if (isset($a_bridges[$id]['stp'])) { $pconfig['stp'] = $a_bridges[$id]['stp']; } if (isset($a_bridges[$id]['span'])) { $pconfig['span'] = $a_bridges[$id]['span']; } if (isset($a_bridges[$id]['edge'])) { $pconfig['edge'] = $a_bridges[$id]['edge']; } if (isset($a_bridges[$id]['autoedge'])) { $pconfig['autoedge'] = $a_bridges[$id]['autoedge']; } if (isset($a_bridges[$id]['ptp'])) { $pconfig['ptp'] = $a_bridges[$id]['ptp']; } if (isset($a_bridges[$id]['autoptp'])) { $pconfig['autoptp'] = $a_bridges[$id]['autoptp']; } } if ($_POST) { unset($input_errors); $pconfig = $_POST; /* input validation */ $reqdfields = explode(" ", "members"); $reqdfieldsn = array(gettext("Member Interfaces")); do_input_validation($_POST, $reqdfields, $reqdfieldsn, $input_errors); if ($_POST['maxage'] && !is_numericint($_POST['maxage'])) { $input_errors[] = gettext("Maxage needs to be an integer between 6 and 40."); } if ($_POST['maxaddr'] && !is_numericint($_POST['maxaddr'])) { $input_errors[] = gettext("Maxaddr needs to be an integer."); } if ($_POST['timeout'] && !is_numericint($_POST['timeout'])) { $input_errors[] = gettext("Timeout needs to be an integer."); } if ($_POST['fwdelay'] && !is_numericint($_POST['fwdelay'])) { $input_errors[] = gettext("Forward Delay needs to be an integer between 4 and 30."); } if ($_POST['hellotime'] && !is_numericint($_POST['hellotime'])) { $input_errors[] = gettext("Hello time for STP needs to be an integer between 1 and 2."); } if ($_POST['priority'] && !is_numericint($_POST['priority'])) { $input_errors[] = gettext("Priority for STP needs to be an integer between 0 and 61440."); } if ($_POST['holdcnt'] && !is_numericint($_POST['holdcnt'])) { $input_errors[] = gettext("Transmit Hold Count for STP needs to be an integer between 1 and 10."); } foreach ($ifacelist as $ifn => $ifdescr) { if ($_POST[$ifn] <> "" && !is_numericint($_POST[$ifn])) { $input_errors[] = sprintf(gettext("%s interface priority for STP needs to be an integer between 0 and 240."), $ifdescr); } } $i = 0; foreach ($ifacelist as $ifn => $ifdescr) { if ($_POST["{$ifn}{$i}"] <> "" && !is_numeric($_POST["{$ifn}{$i}"])) { $input_errors[] = sprintf(gettext("%s interface path cost for STP needs to be an integer between 1 and 200000000."), $ifdescr); } $i++; } if (!is_array($_POST['members']) || count($_POST['members']) < 1) { $input_errors[] = gettext("At least one member interface must be selected for a bridge."); } if (is_array($_POST['static'])) { foreach ($_POST['static'] as $ifstatic) { if (is_array($_POST['members']) && !in_array($ifstatic, $_POST['members'])) { $input_errors[] = gettext("Sticky interface ($ifstatic) is not part of the bridge. Remove the sticky interface to continue."); } } $pconfig['static'] = implode(',', $_POST['static']); } if (is_array($_POST['private'])) { foreach ($_POST['private'] as $ifprivate) { if (is_array($_POST['members']) && !in_array($ifprivate, $_POST['members'])) { $input_errors[] = gettext("Private interface ($ifprivate) is not part of the bridge. Remove the private interface to continue."); } } $pconfig['private'] = implode(',', $_POST['private']); } if (is_array($_POST['stp'])) { foreach ($_POST['stp'] as $ifstp) { if (is_array($_POST['members']) && !in_array($ifstp, $_POST['members'])) { $input_errors[] = gettext("STP interface ($ifstp) is not part of the bridge. Remove the STP interface to continue."); } } $pconfig['stp'] = implode(',', $_POST['stp']); } if (is_array($_POST['span'])) { $pconfig['span'] = implode(',', $_POST['span']); } if (is_array($_POST['edge'])) { foreach ($_POST['edge'] as $ifedge) { if (is_array($_POST['members']) && !in_array($ifedge, $_POST['members'])) { $input_errors[] = gettext("Edge interface ($ifedge) is not part of the bridge. Remove the edge interface to continue."); } } $pconfig['edge'] = implode(',', $_POST['edge']); } if (is_array($_POST['autoedge'])) { foreach ($_POST['autoedge'] as $ifautoedge) { if (is_array($_POST['members']) && !in_array($ifautoedge, $_POST['members'])) { $input_errors[] = gettext("Auto Edge interface ($ifautoedge) is not part of the bridge. Remove the auto edge interface to continue."); } } $pconfig['autoedge'] = implode(',', $_POST['autoedge']); } if (is_array($_POST['ptp'])) { foreach ($_POST['ptp'] as $ifptp) { if (is_array($_POST['members']) && !in_array($ifptp, $_POST['members'])) { $input_errors[] = gettext("PTP interface ($ifptp) is not part of the bridge. Remove the PTP interface to continue."); } } $pconfig['ptp'] = implode(',', $_POST['ptp']); } if (is_array($_POST['autoptp'])) { foreach ($_POST['autoptp'] as $ifautoptp) { if (is_array($_POST['members']) && !in_array($ifautoptp, $_POST['members'])) { $input_errors[] = gettext("Auto PTP interface ($ifautoptp) is not part of the bridge. Remove the auto PTP interface to continue."); } } $pconfig['autoptp'] = implode(',', $_POST['autoptp']); } if (is_array($_POST['members'])) { foreach ($_POST['members'] as $ifmembers) { if (empty($config['interfaces'][$ifmembers])) { $input_errors[] = gettext("A member interface passed does not exist in configuration"); } if (substr($config['interfaces'][$ifmembers]['if'], 0, 6) == "bridge") { $input_errors[] = gettext("A bridge interface cannot be a member of a bridge."); } if (is_array($config['interfaces'][$ifmembers]['wireless']) && $config['interfaces'][$ifmembers]['wireless']['mode'] != "hostap") { $input_errors[] = gettext("Bridging a wireless interface is only possible in hostap mode."); } if (is_array($_POST['span']) && in_array($ifmembers, $_POST['span'])) { $input_errors[] = gettext("Span interface ($ifmembers) cannot be part of the bridge. Remove the span interface from bridge members to continue."); } foreach ($a_bridges as $a_bridge) { if ($_POST['bridgeif'] === $a_bridge['bridgeif']) { continue; } $a_members = explode(',', $a_bridge['members']); foreach ($a_members as $a_member) { if ($ifmembers === $a_member) { $input_errors[] = sprintf(gettext("%s is part of another bridge. Remove the interface from bridge members to continue."), $ifmembers); } } } } $pconfig['members'] = implode(',', $_POST['members']); } if (!$input_errors) { $bridge = array(); $bridge['members'] = implode(',', $_POST['members']); $bridge['enablestp'] = $_POST['enablestp'] ? true : false; $bridge['descr'] = $_POST['descr']; $bridge['maxaddr'] = $_POST['maxaddr']; $bridge['timeout'] = $_POST['timeout']; $bridge['maxage'] = $_POST['maxage']; $bridge['fwdelay'] = $_POST['fwdelay']; $bridge['hellotime'] = $_POST['hellotime']; $bridge['priority'] = $_POST['priority']; $bridge['proto'] = $_POST['proto']; $bridge['holdcnt'] = $_POST['holdcnt']; $i = 0; $ifpriority = ""; $ifpathcost = ""; foreach ($ifacelist as $ifn => $ifdescr) { if ($_POST[$ifn] <> "") { if ($i > 0) { $ifpriority .= ","; } $ifpriority .= $ifn.":".$_POST[$ifn]; } if ($_POST["{$ifn}0"] <> "") { if ($i > 0) { $ifpathcost .= ","; } $ifpathcost .= $ifn.":".$_POST["{$ifn}0"]; } $i++; } $bridge['ifpriority'] = $ifpriority; $bridge['ifpathcost'] = $ifpathcost; if (isset($_POST['static'])) { $bridge['static'] = implode(',', $_POST['static']); } if (isset($_POST['private'])) { $bridge['private'] = implode(',', $_POST['private']); } if (isset($_POST['stp'])) { $bridge['stp'] = implode(',', $_POST['stp']); } if (isset($_POST['span'])) { $bridge['span'] = implode(',', $_POST['span']); } if (isset($_POST['edge'])) { $bridge['edge'] = implode(',', $_POST['edge']); } if (isset($_POST['autoedge'])) { $bridge['autoedge'] = implode(',', $_POST['autoedge']); } if (isset($_POST['ptp'])) { $bridge['ptp'] = implode(',', $_POST['ptp']); } if (isset($_POST['autoptp'])) { $bridge['autoptp'] = implode(',', $_POST['autoptp']); } $bridge['bridgeif'] = $_POST['bridgeif']; interface_bridge_configure($bridge); if ($bridge['bridgeif'] == "" || !stristr($bridge['bridgeif'], "bridge")) { $input_errors[] = gettext("Error occurred creating interface, please retry."); } else { if (isset($id) && $a_bridges[$id]) { $a_bridges[$id] = $bridge; } else { $a_bridges[] = $bridge; } write_config(); $confif = convert_real_interface_to_friendly_interface_name($bridge['bridgeif']); if ($confif <> "") { interface_configure($confif); } header("Location: interfaces_bridge.php"); exit; } } } // port list with the exception of assigned bridge interfaces to prevent invalid configs function build_port_list($selecton) { global $config, $ifacelist; $portlist = array('list' => array(), 'selected' => array()); foreach ($ifacelist as $ifn => $ifdescr) { if (substr($config['interfaces'][$ifn]['if'], 0, 6) != "bridge") { $portlist['list'][$ifn] = $ifdescr; if (in_array($ifn, explode(',', $selecton))) { array_push($portlist['selected'], $ifn); } } } return($portlist); } $pgtitle = array(gettext("Interfaces"), gettext("Bridges"), gettext("Edit")); $shortcut_section = "interfaces"; include("head.inc"); if ($input_errors) { print_input_errors($input_errors); } $form = new Form(); $section = new Form_Section('Bridge Configuration'); $memberslist = build_port_list($pconfig['members']); $section->addInput(new Form_Select( 'members', 'Member Interfaces', $memberslist['selected'], $memberslist['list'], true // Allow multiples ))->setHelp('Interfaces participating in the bridge.'); $section->addInput(new Form_Input( 'descr', 'Description', 'text', $pconfig['descr'] )); // Advanced Additional options $btnadv = new Form_Button( 'btnadvopts', 'Display Advanced', null, 'fa-cog' ); $btnadv->setAttribute('type','button')->addClass('btn-info btn-sm'); $section->addInput(new Form_StaticText( 'Advanced Options', $btnadv )); $form->add($section); $section = new Form_Section('Advanced Configuration'); $section->addClass('adnlopts'); $section->addInput(new Form_Input( 'maxaddr', 'Cache Size', 'text', $pconfig['maxaddr'] ))->setHelp('Set the size of the bridge address cache. The default is 2000 entries.'); $section->addInput(new Form_Input( 'timeout', 'Cache expire time', 'text', $pconfig['timeout'] ))->setHelp('Set the timeout of address cache entries to this number of seconds. If seconds is zero, then address cache entries will not be expired. The default is 1200 seconds.'); $spanlist = build_port_list($pconfig['span']); $section->addInput(new Form_Select( 'span', 'Span Port', $spanlist['selected'], $spanlist['list'], true ))->setHelp('Add the interface named by interface as a span port on the bridge. Span ports transmit a copy of every frame received by the bridge. ' . 'This is most useful for snooping a bridged network passively on another host connected to one of the span ports of the bridge.
' . '%sThe span interface cannot be part of the bridge member interfaces.%s', ['', '']); $edgelist = build_port_list($pconfig['edge']); $section->addInput(new Form_Select( 'edge', 'Edge Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Set interface as an edge port. An edge port connects directly to end stations and cannot create bridging loops in the network; this allows it to transition straight to forwarding.'); $edgelist = build_port_list($pconfig['autoedge']); $section->addInput(new Form_Select( 'autoedge', 'Auto Edge Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Allow interface to automatically detect edge status. This is the default for all interfaces added to a bridge.' . '%sThis will disable the autoedge status of interfaces. %s', ['', '']); $edgelist = build_port_list($pconfig['ptp']); $section->addInput(new Form_Select( 'ptp', 'PTP Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Set the interface as a point-to-point link. This is required for straight transitions to forwarding and should be enabled on a direct link to another RSTP-capable switch.'); $edgelist = build_port_list($pconfig['autoptp']); $section->addInput(new Form_Select( 'autoptp', 'Auto PTP Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Automatically detect the point-to-point status on interface by checking the full duplex link status. This is the default for interfaces added to the bridge.' . '%sThe interfaces selected here will be removed from default autoedge status. %s', ['', '']); $edgelist = build_port_list($pconfig['static']); $section->addInput(new Form_Select( 'static', 'Sticky Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Mark an interface as a "sticky" interface. Dynamically learned address entries are treated as static once entered into the cache. ' . 'Sticky entries are never aged out of the cache or replaced, even if the address is seen on a different interface.'); $edgelist = build_port_list($pconfig['private']); $section->addInput(new Form_Select( 'private', 'Private Ports', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Mark an interface as a "private" interface. A private interface does not forward any traffic to any other port that is also a private interface. '); // STP section // ToDo: - Should disable spanning tree section when not checked $section->addInput(new Form_Checkbox( 'enablestp', 'Enable RSTP/STP', null, $pconfig['enablestp'] )); // Show the spanning tree section $form->add($section); $section = new Form_Section('RSTP/STP'); $section->addClass('adnlopts'); $section->addInput(new Form_Select( 'proto', 'Protocol', $pconfig['proto'], array('rstp' => 'RSTP', 'stp' => 'STP') ))->setHelp('Protocol used for spanning tree.'); $edgelist = build_port_list($pconfig['stp']); $section->addInput(new Form_Select( 'stp', 'STP Interfaces', $edgelist['selected'], $edgelist['list'], true ))->setHelp('Enable Spanning Tree Protocol on interface. The if_bridge(4) driver has support for the IEEE 802.1D Spanning Tree Protocol (STP). ' . 'STP is used to detect and remove loops in a network topology.'); $section->addInput(new Form_Input( 'maxage', 'Valid time', 'number', $pconfig['maxage'], ['placeholder' => 20, 'min' => 6, 'max' => 40] ))->setHelp('Set the time that a Spanning Tree Protocol configuration is valid. The default is 20 seconds. The minimum is 6 seconds and the maximum is 40 seconds.'); $section->addInput(new Form_Input( 'fwdelay', 'Forward time', 'number', $pconfig['fwdelay'], ['placeholder' => 15, 'min' => 4, 'max' => 30] ))->setHelp('Set the time that must pass before an interface begins forwarding packets when Spanning Tree is enabled. The default is 15 seconds. The minimum is 4 seconds and the maximum is 30 seconds. '); $section->addInput(new Form_Input( 'hellotime', 'Hello time', 'number', $pconfig['hellotime'], ['placeholder' => 2, 'min' => 1, 'max' => 2, 'step' => '0.1'] ))->setHelp('Set the time in seconds between broadcasting of Spanning Tree Protocol configuration messages. The hello time may only be changed when operating in legacy STP mode. ' . 'The default is 2 seconds. The minimum is 1 second and the maximum is 2 seconds.'); $section->addInput(new Form_Input( 'priority', 'Priority', 'number', $pconfig['priority'], ['placeholder' => 32768, 'min' => 0, 'max' => 61440] ))->setHelp('Set the bridge priority for Spanning Tree. The default is 32768. The minimum is 0 and the maximum is 61440. '); $section->addInput(new Form_Input( 'holdcnt', 'Hold Count', 'number', $pconfig['holdcnt'], ['placeholder' => 6, 'min' => 1, 'max' => 10] ))->setHelp('Set the transmit hold count for Spanning Tree. This is the number of packets transmitted before being rate limited. The default is 6. The minimum is 1 and the maximum is 10.'); foreach ($ifacelist as $ifn => $ifdescr) { $section->addInput(new Form_Input( $ifn, $ifdescr . ' Priority', 'number', $pconfig['ifpriority'][$ifn], ['placeholder' => 128, 'min' => 0, 'max' => 240, 'step' => 16] ))->setHelp('Set the Spanning Tree priority of interface to value. The default is 128. The minimum is 0 and the maximum is 240. Increments of 16.'); } $i = 0; foreach ($ifacelist as $ifn => $ifdescr) { $section->addInput(new Form_Input( $ifn . 0, $ifdescr . ' Path cost', 'number', $pconfig['ifpathcost'][$ifn], [ 'placeholder' => 0, 'min' => 1, 'max' => 200000000] ))->setHelp('Set the Spanning Tree path cost of interface to value. The default is calculated from the link speed. '. 'To change a previously selected path cost back to automatic, set the cost to 0. The minimum is 1 and the maximum is 200000000.'); $i++; } $section->addInput(new Form_Input( 'bridgeif', null, 'hidden', $pconfig['bridgeif'] )); if (isset($id) && $a_bridges[$id]) { $section->addInput(new Form_Input( 'id', null, 'hidden', $id )); } $form->add($section); print($form); ?>