Interfaces: Other Types: VLAN - refactor to MVC framework detaching configuration using configd while. In preparation for https://github.com/opnsense/core/issues/5560

This commit is contained in:
Ad Schellevis 2022-02-22 15:53:08 +01:00
parent 892ab932a6
commit 88c27bfe4c
15 changed files with 515 additions and 411 deletions

View File

@ -0,0 +1,133 @@
<?php
/*
* Copyright (C) 2022 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces\Api;
use OPNsense\Core\Backend;
use OPNsense\Core\Config;
use OPNsense\Base\UserException;
use OPNsense\Base\ApiMutableModelControllerBase;
class VlanSettingsController extends ApiMutableModelControllerBase
{
protected static $internalModelName = 'vlan';
protected static $internalModelClass = 'OPNsense\Interfaces\Vlan';
private function generateVlanIfName()
{
$tmp = $this->request->getPost("vlan");
return "{$tmp['if']}_vlan{$tmp['tag']}";
}
private function interfaceAssigned($if)
{
$configHandle = Config::getInstance()->object();
if (!empty($configHandle->interfaces)) {
foreach ($configHandle->interfaces->children() as $ifname => $node) {
if ((string)$node->if == $if) {
return true;
}
}
}
return false;
}
public function searchItemAction()
{
return $this->searchBase("vlan", ['vlanif','if','tag','pcp','descr'], "vlanif");
}
public function setItemAction($uuid)
{
$node = $this->getModel()->getNodeByReference('vlan.' . $uuid);
$old_vlanif = $node != null ? (string)$node->vlanif : null;
$new_vlanif = $this->generateVlanIfName();
if ($old_vlanif != null && $old_vlanif != $new_vlanif && $this->interfaceAssigned($old_vlanif)) {
$tmp = $this->request->getPost("vlan");
if ($tmp['tag'] != (string)$node->tag) {
$result = [
"result" => "failed",
"validations" => [
"vlan.tag" => gettext("Interface is assigned and you cannot change the VLAN tag while assigned.")
]
];
} else {
$result = [
"result" => "failed",
"validations" => [
"vlan.if" => gettext("Interface is assigned and you cannot change the parent while assigned.")
]
];
}
} else {
$result = $this->setBase("vlan", "vlan", $uuid, ["vlanif" => $new_vlanif]);
// store interface name for apply action
if ($result['result'] != 'failed' && $old_vlanif != $new_vlanif) {
file_put_contents("/tmp/.vlans.removed", "{$old_vlanif}\n", FILE_APPEND|LOCK_EX);
}
}
return $result;
}
public function addItemAction()
{
return $this->addBase("vlan", "vlan", [
"vlanif" => $this->generateVlanIfName()
]);
}
public function getItemAction($uuid = null)
{
return $this->getBase("vlan", "vlan", $uuid);
}
public function delItemAction($uuid)
{
$node = $this->getModel()->getNodeByReference('vlan.' . $uuid);
$old_vlanif = $node != null ? (string)$node->vlanif : null;
if ($old_vlanif != null && $this->interfaceAssigned($old_vlanif)) {
throw new UserException(gettext("This VLAN cannot be deleted because it is assigned as an interface."));
} else {
$result = $this->delBase("vlan", $uuid);
// store interface name for apply action
if ($result['result'] != 'failed') {
file_put_contents("/tmp/.vlans.removed", "{$old_vlanif}\n", FILE_APPEND|LOCK_EX);
}
return $result;
}
}
public function reconfigureAction()
{
$result = array("status" => "failed");
if ($this->request->isPost()) {
$result['status'] = strtolower(trim((new Backend())->configdRun('interface vlan configure')));
}
return $result;
}
}

View File

@ -0,0 +1,38 @@
<?php
/*
* Copyright (C) 2022 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces;
class VlanController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->pick('OPNsense/Interface/vlan');
$this->view->formDialogVlan = $this->getForm("dialogVlan");
}
}

View File

@ -0,0 +1,31 @@
<form>
<field>
<id>vlan.vlanif</id>
<label>deviceId</label>
<type>info</type>
</field>
<field>
<id>vlan.if</id>
<label>Parent interface</label>
<type>dropdown</type>
<help>Only VLAN capable interfaces will be shown.</help>
</field>
<field>
<id>vlan.tag</id>
<label>VLAN tag</label>
<type>text</type>
<help>802.1Q VLAN tag (between 1 and 4094)</help>
</field>
<field>
<id>vlan.pcp</id>
<label>VLAN priority</label>
<type>dropdown</type>
<help>802.1Q VLAN PCP (priority code point)</help>
</field>
<field>
<id>vlan.descr</id>
<label>Description</label>
<type>text</type>
<help>You may enter a description here for your reference (not parsed).</help>
</field>
</form>

View File

@ -410,18 +410,6 @@
<pattern>interfaces_ppps_edit.php*</pattern>
</patterns>
</page-interfaces-ppps-edit>
<page-interfaces-vlan>
<name>Interfaces: VLAN</name>
<patterns>
<pattern>interfaces_vlan.php*</pattern>
</patterns>
</page-interfaces-vlan>
<page-interfaces-vlan-edit>
<name>Interfaces: VLAN: Edit</name>
<patterns>
<pattern>interfaces_vlan_edit.php*</pattern>
</patterns>
</page-interfaces-vlan-edit>
<page-interfaces>
<name>Interfaces: WAN</name>
<patterns>

View File

@ -138,9 +138,6 @@
<LAGG url="/interfaces_lagg.php">
<Edit url="/interfaces_lagg_edit.php*" visibility="hidden"/>
</LAGG>
<VLAN url="/interfaces_vlan.php">
<Edit url="/interfaces_vlan_edit.php*" visibility="hidden"/>
</VLAN>
</Types>
<Diagnostics order="970" cssClass="fa fa-medkit fa-fw">
<DNSLookup VisibleName="DNS Lookup" url="/diag_dns.php">

View File

@ -13,4 +13,11 @@
<pattern>api/interfaces/loopback</pattern>
</patterns>
</page-interfaces-loopback>
<page-interfaces-vlan-edit>
<name>Interfaces: VLAN</name>
<patterns>
<pattern>ui/interfaces/vlan</pattern>
<pattern>api/interfaces/vlan</pattern>
</patterns>
</page-interfaces-vlan-edit>
</acl>

View File

@ -0,0 +1,75 @@
<?php
/**
* Copyright (C) 2022 Deciso B.V.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OPNsense\Interfaces\FieldTypes;
use OPNsense\Base\FieldTypes\BaseListField;
use OPNsense\Core\Backend;
use OPNsense\Core\Config;
class VlanInterfaceField extends BaseListField
{
private static $interface_devices = null;
protected function actionPostLoadingEvent()
{
if (self::$interface_devices === null) {
$configHandle = Config::getInstance()->object();
$ifnames = [];
if (!empty($configHandle->interfaces)) {
foreach ($configHandle->interfaces->children() as $ifname => $node) {
$ifnames[(string)$node->if] = !empty((string)$node->descr) ? (string)$node->descr : $key;
}
}
self::$interface_devices = [];
$ifconfig = json_decode((new Backend())->configdRun('interface list ifconfig'), true);
if (!empty($ifconfig)) {
foreach ($ifconfig as $ifname => $details) {
// XXX: skip same interface types as legacy, may need to revise later
if (strpos($ifname, "_vlan") > 1 || strpos($ifname, "lo") === 0 || strpos($ifname, "enc") === 0 ||
strpos($ifname, "pflog") === 0 || strpos($ifname, "pfsync") === 0 ||
strpos($ifname, "bridge") === 0 ||
strpos($ifname, "gre") === 0 || strpos($ifname, "gif") === 0 || strpos($ifname, "ipsec") === 0
) {
continue;
}
self::$interface_devices[$ifname] = sprintf(
"%s (%s) [%s]",
$ifname,
$details['macaddr'],
!empty($ifnames[$ifname]) ? $ifnames[$ifname] : ""
);
}
}
}
$this->internalOptionList = self::$interface_devices;
return parent::actionPostLoadingEvent();
}
}

View File

@ -3,6 +3,7 @@
<Types>
<VXLAN url="/ui/interfaces/vxlan"/>
<Loopback url="/ui/interfaces/loopback"/>
<VLAN url="/ui/interfaces/vlan"/>
</Types>
</Interfaces>
</menu>

View File

@ -0,0 +1,35 @@
<?php
/*
* Copyright (C) 2022 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Interfaces;
use OPNsense\Base\BaseModel;
class Vlan extends BaseModel
{
}

View File

@ -0,0 +1,45 @@
<model>
<mount>//vlans</mount>
<version>1.0.0</version>
<description>
VLAN configuration
</description>
<items>
<vlan type="ArrayField">
<if type=".\VlanInterfaceField">
<Required>Y</Required>
</if>
<tag type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>4094</MaximumValue>
<Required>Y</Required>
</tag>
<pcp type="OptionField">
<Required>Y</Required>
<default>0</default>
<OptionValues>
<pcp1 value="1">Background (1, lowest)</pcp1>
<pcp0 value="0">Best Effort (0, default)</pcp0>
<pcp2 value="2">Excellent Effort (2)</pcp2>
<pcp3 value="3">Critical Applications (3)</pcp3>
<pcp4 value="4">Video (4)</pcp4>
<pcp5 value="5">Voice (5)</pcp5>
<pcp6 value="6">Internetwork Control (6)</pcp6>
<pcp7 value="7">Network Control (7, highest)</pcp7>
</OptionValues>
</pcp>
<descr type="TextField">
<Required>N</Required>
</descr>
<vlanif type="TextField">
<Required>Y</Required>
<Constraints>
<check001>
<ValidationMessage>The interface name should be unique.</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</vlanif>
</vlan>
</items>
</model>

View File

@ -0,0 +1,55 @@
<script>
$( document ).ready(function() {
$("#grid-vlans").UIBootgrid(
{ search:'/api/interfaces/vlan_settings/searchItem/',
get:'/api/interfaces/vlan_settings/getItem/',
set:'/api/interfaces/vlan_settings/setItem/',
add:'/api/interfaces/vlan_settings/addItem/',
del:'/api/interfaces/vlan_settings/delItem/'
}
);
$("#reconfigureAct").SimpleActionButton();
});
</script>
<div class="tab-content content-box">
<table id="grid-vlans" class="table table-condensed table-hover table-striped" data-editDialog="DialogVlan" data-editAlert="VlanChangeMessage">
<thead>
<tr>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="if" data-type="string">{{ lang._('Parent Interface') }}</th>
<th data-column-id="vlanif" data-type="string" data-visible="false">{{ lang._('Interface') }}</th>
<th data-column-id="tag" data-type="string">{{ lang._('Tag') }}</th>
<th data-column-id="pcp" data-type="string">{{ lang._('PCP') }}</th>
<th data-column-id="descr" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-primary"><span class="fa fa-fw fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-fw fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
<div class="col-md-12">
<div id="VlanChangeMessage" class="alert alert-info" style="display: none" role="alert">
{{ lang._('After changing settings, please remember to apply them with the button below') }}
</div>
<hr/>
<button class="btn btn-primary" id="reconfigureAct"
data-endpoint='/api/interfaces/vlan_settings/reconfigure'
data-label="{{ lang._('Apply') }}"
data-error-title="{{ lang._('Error reconfiguring vlan') }}"
type="button"
></button>
<br/><br/>
</div>
</div>
{{ partial("layout_partials/base_dialog",['fields':formDialogVlan,'id':'DialogVlan','label':lang._('Edit Vlan')])}}

View File

@ -0,0 +1,90 @@
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2022 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("config.inc");
require_once("filter.inc");
require_once("interfaces.inc");
require_once("util.inc");
// gather all relevant vlan's (new/updated and removed) into a single list
$all_vlans = [];
$vfilename = "/tmp/.vlans.removed";
if (file_exists($vfilename) && filesize($vfilename) > 0) {
$handle = fopen($vfilename, "r+");
if (flock($handle, LOCK_EX)) {
fseek($handle, 0);
foreach (explode("\n", fread($handle, filesize($vfilename))) as $line) {
if (!isset($all_vlans[$line]) && trim($line) != "") {
$all_vlans[$line] = [];
}
}
fseek($handle, 0);
ftruncate($handle, 0);
flock($handle, LOCK_UN);
}
}
// merge configured vlans
if (!empty($config['vlans']['vlan'])) {
foreach ($config['vlans']['vlan'] as $vlan) {
$all_vlans[$vlan['vlanif']] = $vlan;
}
}
// handle existing vlan's
foreach (legacy_interfaces_details() as $ifname => $ifdetails) {
if (empty($ifdetails['vlan'])) {
continue;
}
if (isset($all_vlans[$ifname])){
$vlan = $all_vlans[$ifname];
$cvlan = $ifdetails['vlan'];
if (empty($vlan)) {
// option 1: removed vlan
legacy_interface_destroy($ifname);
} elseif ($vlan['pcp'] != $cvlan['pcp']) {
// option 2: pcp changed, which can be altered instantly
exec('/sbin/ifconfig ' . escapeshellarg($vlan['vlanif']) . ' vlanpcp ' . escapeshellarg($vlan['pcp']). ' 2>&1', $out, $ret);
} elseif ($vlan['tag'] != $cvlan['tag'] || $vlan['if'] != $cvlan['parent']){
// option 3: changed vlan, recreate with appropriate settings
// XXX: legacy code used interface_configure() in these cases, but since you can't change a tag or a parent
// for an assigned interface. At the moment that doesn't seem to make much sense
interface_vlan_configure($vlan);
}
unset($all_vlans[$ifname]);
}
}
// configure new
foreach ($all_vlans as $ifname => $vlan) {
if (!empty($vlan)) {
interface_vlan_configure($vlan);
}
}
ifgroup_setup();

View File

@ -115,6 +115,11 @@ command: /usr/local/sbin/pluginctl -c vxlan_prepare
message: Reconfiguring vxlan
type: script
[vlan.configure]
command: /usr/local/opnsense/scripts/interfaces/reconfigure_vlans.php
message: Reconfiguring vlan
type: script
[loopback.configure]
command: /usr/local/sbin/pluginctl -c loopback_prepare
message: Reconfiguring loopbacks

View File

@ -1,145 +0,0 @@
<?php
/*
* Copyright (C) 2014-2015 Deciso B.V.
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("guiconfig.inc");
require_once("interfaces.inc");
$a_vlans = &config_read_array('vlans', 'vlan');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input_errors = array();
if (!empty($a_vlans[$_POST['id']])) {
$id = $_POST['id'];
}
if (!empty($_POST['action']) && $_POST['action'] == "del" && isset($id)) {
if (is_interface_assigned($a_vlans[$id]['vlanif'])) {
$input_errors[] = gettext("This VLAN cannot be deleted because it is assigned as an interface.");
} else {
if (does_interface_exist($a_vlans[$id]['vlanif'])) {
legacy_interface_destroy($a_vlans[$id]['vlanif']);
}
unset($a_vlans[$id]);
write_config();
header(url_safe('Location: /interfaces_vlan.php'));
exit;
}
}
}
include("head.inc");
legacy_html_escape_form_data($a_vlans);
?>
<body>
<script>
$( document ).ready(function() {
// link delete buttons
$(".act_delete").click(function(event){
event.preventDefault();
var id = $(this).data("id");
// delete single
BootstrapDialog.show({
type:BootstrapDialog.TYPE_DANGER,
title: "<?= gettext("VLAN");?>",
message: "<?=gettext("Do you really want to delete this VLAN?");?>",
buttons: [{
label: "<?= gettext("No");?>",
action: function(dialogRef) {
dialogRef.close();
}}, {
label: "<?= gettext("Yes");?>",
action: function(dialogRef) {
$("#id").val(id);
$("#action").val("del");
$("#iform").submit()
}
}]
});
});
});
</script>
<?php include("fbegin.inc"); ?>
<section class="page-content-main">
<div class="container-fluid">
<div class="row">
<?php if (isset($input_errors) && count($input_errors) > 0) print_input_errors($input_errors); ?>
<section class="col-xs-12">
<div class="tab-content content-box col-xs-12">
<form method="post" name="iform" id="iform">
<input type="hidden" id="action" name="action" value="">
<input type="hidden" id="id" name="id" value="">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th><?=gettext("Interface");?></th>
<th><?=gettext("Tag");?></th>
<th><?=gettext("PCP");?></th>
<th><?=gettext("Description");?></th>
<th class="text-nowrap">
<a href="interfaces_vlan_edit.php" class="btn btn-primary btn-xs" data-toggle="tooltip" title="<?= html_safe(gettext('Add')) ?>">
<i class="fa fa-plus fa-fw"></i>
</a>
</th>
</tr>
</thead>
<tbody>
<?php
$i = 0;
foreach ($a_vlans as $vlan): ?>
<tr>
<td><?=$vlan['if'];?></td>
<td><?=$vlan['tag'];?></td>
<td><?= isset($vlan['pcp']) ? $vlan['pcp'] : 0 ?></td>
<td><?=$vlan['descr'];?></td>
<td class="text-nowrap">
<a href="interfaces_vlan_edit.php?id=<?=$i;?>" class="btn btn-xs btn-default" data-toggle="tooltip" title="<?= html_safe(gettext('Edit')) ?>">
<i class="fa fa-pencil fa-fw"></i>
</a>
<button title="<?= html_safe(gettext('Delete')) ?>" data-toggle="tooltip" data-id="<?=$i;?>" class="btn btn-default btn-xs act_delete" type="submit">
<i class="fa fa-trash fa-fw"></i>
</button>
</td>
</tr>
<?php
$i++;
endforeach; ?>
</tbody>
</table>
</div>
</form>
</div>
</section>
</div>
</div>
</section>
<?php include("foot.inc"); ?>

View File

@ -1,251 +0,0 @@
<?php
/*
* Copyright (C) 2014-2016 Deciso B.V.
* Copyright (C) 2003-2004 Manuel Kasper <mk@neon1.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once("guiconfig.inc");
require_once("system.inc");
require_once("interfaces.inc");
require_once("filter.inc");
$a_vlans = &config_read_array('vlans', 'vlan');
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
// read form data
if (!empty($a_vlans[$_GET['id']])) {
$id = $_GET['id'];
}
$pconfig['if'] = isset($a_vlans[$id]['if']) ? $a_vlans[$id]['if'] : null;
$pconfig['vlanif'] = isset($a_vlans[$id]['vlanif']) ? $a_vlans[$id]['vlanif'] : null;
$pconfig['tag'] = isset($a_vlans[$id]['tag']) ? $a_vlans[$id]['tag'] : null;
$pconfig['pcp'] = isset($a_vlans[$id]['pcp']) ? $a_vlans[$id]['pcp'] : 0;
$pconfig['descr'] = isset($a_vlans[$id]['descr']) ? $a_vlans[$id]['descr'] : null;
} elseif ($_SERVER['REQUEST_METHOD'] === 'POST') {
// validate / save form data
if (!empty($a_vlans[$_POST['id']])) {
$id = $_POST['id'];
}
$input_errors = [];
$pconfig = $_POST;
/* input validation */
$reqdfields = explode(" ", "if tag");
$reqdfieldsn = [gettext('Parent interface'), gettext('VLAN tag')];
do_input_validation($pconfig, $reqdfields, $reqdfieldsn, $input_errors);
if ($pconfig['tag'] && (!is_numericint($pconfig['tag']) || ($pconfig['tag'] < '1') || ($pconfig['tag'] > '4094'))) {
$input_errors[] = gettext("The VLAN tag must be an integer between 1 and 4094.");
}
if (isset($pconfig['pcp']) && (!is_numericint($pconfig['pcp']) || $pconfig['pcp'] < 0 || $pconfig['pcp'] > 7)) {
$input_errors[] = gettext("The VLAN priority must be an integer between 0 and 7.");
}
if (!does_interface_exist($pconfig['if'])) {
$input_errors[] = gettext("Interface supplied as parent is invalid");
}
if (isset($id) && $pconfig['tag'] && $pconfig['tag'] != $a_vlans[$id]['tag']) {
if (!empty($a_vlans[$id]['vlanif']) && convert_real_interface_to_friendly_interface_name($a_vlans[$id]['vlanif']) != NULL) {
$input_errors[] = gettext("Interface is assigned and you cannot change the VLAN tag while assigned.");
}
}
foreach ($a_vlans as $vlan) {
if (isset($id) && $a_vlans[$id] === $vlan) {
continue;
}
if (($vlan['if'] == $pconfig['if']) && ($vlan['tag'] == $pconfig['tag'])) {
$input_errors[] = sprintf(gettext("A VLAN with the tag %s is already defined on this interface."), $vlan['tag']);
break;
}
}
if (count($input_errors) == 0) {
$confif = "";
$vlan = [];
$vlan['if'] = $pconfig['if'];
$vlan['tag'] = $pconfig['tag'];
$vlan['pcp'] = $pconfig['pcp'];
$vlan['descr'] = $pconfig['descr'];
$vlan['vlanif'] = "{$pconfig['if']}_vlan{$pconfig['tag']}";
if (isset($id)) {
if (($a_vlans[$id]['if'] != $pconfig['if']) || ($a_vlans[$id]['tag'] != $pconfig['tag']) || ($a_vlans[$id]['pcp'] != $pconfig['pcp'])) {
$confif = convert_real_interface_to_friendly_interface_name($a_vlans[$id]['vlanif']);
legacy_interface_destroy($a_vlans[$id]['vlanif']);
if ($confif != '') {
$config['interfaces'][$confif]['if'] = $vlan['vlanif'];
}
}
} else {
/*
* Since VLAN name is calculated we do not need to fetch one from the
* system. However, we would still like to know if the system can create
* another VLAN if it is being added like is done for other devices.
* Eventually we want to change VLAN device names to a simpler "vlanX" style.
*/
$vlan['vlanif'] = legacy_interface_create('vlan', $vlan['vlanif']); /* XXX find another strategy */
}
if (empty($vlan['vlanif']) || strpos($vlan['vlanif'], '_vlan') === false) {
$input_errors[] = gettext("Error occurred creating interface, please retry.");
} else {
if (isset($id)) {
$a_vlans[$id] = $vlan;
} else {
$a_vlans[] = $vlan;
}
write_config();
interface_vlan_configure($vlan);
ifgroup_setup();
if ($confif != '') {
interface_configure(false, $confif);
}
header(url_safe('Location: /interfaces_vlan.php'));
exit;
}
}
}
include("head.inc");
legacy_html_escape_form_data($pconfig);
?>
<body>
<?php include("fbegin.inc"); ?>
<section class="page-content-main">
<div class="container-fluid">
<div class="row">
<?php if (isset($input_errors) && count($input_errors) > 0) print_input_errors($input_errors); ?>
<section class="col-xs-12">
<div class="content-box">
<div class="table-responsive">
<form method="post" name="iform" id="iform">
<table class="table table-striped opnsense_standard_table_form">
<thead>
<tr>
<td style="width:22%"><strong><?=gettext("Interface VLAN Edit");?></strong></td>
<td style="width:78%; text-align:right">
<small><?=gettext("full help"); ?> </small>
<i class="fa fa-toggle-off text-danger" style="cursor: pointer;" id="show_all_help_page"></i>
&nbsp;
</td>
</tr>
</thead>
<tbody>
<tr>
<td><a id="help_for_if" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Parent interface");?></td>
<td>
<select name="if" class="selectpicker">
<?php
$all_interfaces = legacy_config_get_interfaces(['virtual' => false]);
$all_interface_data = legacy_interfaces_details();
foreach ($all_interfaces as $intf) {
if (!empty($intf['if']) && !empty($all_interface_data[$intf['if']])) {
$all_interface_data[$intf['if']]['descr'] = $intf['descr'];
}
}
foreach ($all_interface_data as $ifn => $ifinfo):
if (strpos($ifn, "_vlan") > 1 || strpos($ifn, "lo") === 0 || strpos($ifn, "enc") === 0 ||
strpos($ifn, "pflog") === 0 || strpos($ifn, "pfsync") === 0 || strpos($ifn, "bridge") === 0 ||
strpos($ifn, "gre") === 0 || strpos($ifn, "gif") === 0 || strpos($ifn, "ipsec") === 0) {
continue;
}?>
<option value="<?=$ifn;?>" <?=$ifn == $pconfig['if'] ? " selected=\"selected\"" : "";?>>
<?=htmlspecialchars($ifn);?>
( <?= !empty($ifinfo['macaddr']) ? $ifinfo['macaddr'] :"" ;?> )
<?php
if (!empty($ifinfo['descr'])):?>
[<?=htmlspecialchars($ifinfo['descr']);?>]
<?php
endif;?>
</option>
<?php
endforeach;?>
</select>
<div class="hidden" data-for="help_for_if">
<?=gettext("Only VLAN capable interfaces will be shown.");?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_tag" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("VLAN tag");?></td>
<td>
<input name="tag" type="text" value="<?=$pconfig['tag'];?>" />
<div class="hidden" data-for="help_for_tag">
<?=gettext("802.1Q VLAN tag (between 1 and 4094)");?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_pcp" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("VLAN priority");?></td>
<td>
<select name="pcp">
<?php foreach (interfaces_vlan_priorities() as $pcp => $priority): ?>
<option value="<?=$pcp;?>"<?=($pconfig['pcp'] == $pcp ? ' selected="selected"' : '');?>><?=htmlspecialchars($priority);?></option>
<?php endforeach ?>
</select>
<div class="hidden" data-for="help_for_pcp">
<?=gettext('802.1Q VLAN PCP (priority code point)');?>
</div>
</td>
</tr>
<tr>
<td><a id="help_for_descr" href="#" class="showhelp"><i class="fa fa-info-circle"></i></a> <?=gettext("Description"); ?></td>
<td>
<input name="descr" type="text" value="<?=$pconfig['descr'];?>" />
<div class="hidden" data-for="help_for_descr">
<?=gettext("You may enter a description here for your reference (not parsed).");?>
</div>
</td>
</tr>
<tr>
<td style="width:22%">&nbsp;</td>
<td style="width:78%">
<input type="hidden" name="vlanif" value="<?=$pconfig['vlanif']; ?>" />
<input name="Submit" type="submit" class="btn btn-primary" value="<?=html_safe(gettext('Save'));?>" />
<input type="button" class="btn btn-default" value="<?=html_safe(gettext('Cancel'));?>" onclick="window.location.href='/interfaces_vlan.php'" />
<?php if (isset($id)): ?>
<input name="id" type="hidden" value="<?=$id;?>" />
<?php endif; ?>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
</section>
</div>
</div>
</section>
<?php include("foot.inc"); ?>