net/frr: merge version 0.0.1 from master

This commit is contained in:
Franco Fichtner 2017-11-30 07:48:50 +01:00
parent 6592f43720
commit e1d89951f3
67 changed files with 23388 additions and 0 deletions

8
net/frr/Makefile Normal file
View file

@ -0,0 +1,8 @@
PLUGIN_NAME= frr
PLUGIN_VERSION= 0.0.1
PLUGIN_COMMENT= FRR Routing Suite
PLUGIN_DEPENDS= frr ruby
PLUGIN_MAINTAINER= franz.fabian.94@gmail.com
PLUGIN_DEVEL= YES
.include "../../Mk/plugins.mk"

3
net/frr/pkg-descr Normal file
View file

@ -0,0 +1,3 @@
FRRouting (FRR) is an IP routing protocol suite for Linux and Unix platforms
which includes protocol daemons for BGP, IS-IS, OSPF and RIP. FRR has its roots
in the Quagga project.

View file

@ -0,0 +1,86 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
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.
*/
function ospfd_enabled()
{
$model = new \OPNsense\Quagga\OSPF();
if ((string)$model->enabled == '1') {
return true;
}
return false;
}
function frr_firewall($fw)
{
if (ospfd_enabled()) {
$ospf = new \OPNsense\Quagga\OSPF();
foreach ($ospf->networks->network->__items as $network) {
if ((string)$network->enabled == '1') {
$fw->registerFilterRule(
1, /* priority */
array(
'ipprotocol' => 'inet',
'protocol' => 'ospf',
'statetype' => 'keep',
'label' => 'Pass OSPF (autogenerated)',
'from' => $network->ipaddr . '/' . $network->netmask,
'to' => '224.0.0.0/4',
'direction' => 'in',
'type' => 'pass',
'disablereplyto' => 1,
'quick' => true
),
null
);
}
}
}
}
function frr_services()
{
global $config;
$services = array();
if (isset($config['OPNsense']['quagga']['general']['enabled']) && $config['OPNsense']['quagga']['general']['enabled'] == 1) {
$services[] = array(
'description' => gettext('Quagga is a deamon to add support of various routing protocols.'),
'configd' => array(
'restart' => array('quagga restart'),
'start' => array('quagga start'),
'stop' => array('quagga stop'),
),
'name' => 'quagga',
'pidfile' => '/var/run/quagga/zebra.pid'
);
}
return $services;
}

View file

@ -0,0 +1,506 @@
<?php
/**
* Copyright (C) 2015 - 2017 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* Copyright (C) 2017 Michael Muenz
*
* 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\Quagga\Api;
use \OPNsense\Quagga\BGP;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class BgpController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'BGP';
static protected $internalModelClass = '\OPNsense\Quagga\BGP';
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlBGP = new BGP();
$result['bgp'] = $mdlBGP->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlBGP = new BGP();
$mdlBGP->setNodes($this->request->getPost("bgp"));
// perform validation
$valMsgs = $mdlBGP->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["bgp.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
public function searchNeighborAction()
{
$this->sessionClose();
$mdlBGP = $this->getModel();
$grid = new UIModelGrid($mdlBGP->neighbors->neighbor);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "address", "remoteas", "updatesource", "nexthopself", "defaultoriginate", "linkedPrefixlistIn", "linkedPrefixlistOut", "linkedRoutemapIn", "linkedRoutemapOut" )
);
}
public function getNeighborAction($uuid = null)
{
$mdlBGP = $this->getModel();
if ($uuid != null) {
$node = $mdlBGP->getNodeByReference('neighbors.neighbor.' . $uuid);
if ($node != null) {
// return node
return array("neighbor" => $node->getNodes());
}
} else {
$node = $mdlBGP->neighbors->neighbor->add();
return array("neighbor" => $node->getNodes());
}
return array();
}
public function addNeighborAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("neighbor")) {
$result = array("result" => "failed", "validations" => array());
$mdlBGP = $this->getModel();
$node = $mdlBGP->neighbors->neighbor->Add();
$node->setNodes($this->request->getPost("neighbor"));
$valMsgs = $mdlBGP->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "neighbor", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
unset($result['validations']);
// save config if validated correctly
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delNeighborAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlBGP = $this->getModel();
if ($uuid != null) {
if ($mdlBGP->neighbors->neighbor->del($uuid)) {
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setNeighborAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("neighbor")) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference('neighbors.neighbor.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$neighborInfo = $this->request->getPost("neighbor");
$node->setNodes($neighborInfo);
$valMsgs = $mdlNeighbor->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "neighbor", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function searchAspathAction()
{
$this->sessionClose();
$mdlBGP = $this->getModel();
$grid = new UIModelGrid($mdlBGP->aspaths->aspath);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "number", "action", "as" )
);
}
public function getAspathAction($uuid = null)
{
$mdlBGP = $this->getModel();
if ($uuid != null) {
$node = $mdlBGP->getNodeByReference('aspaths.aspath.' . $uuid);
if ($node != null) {
// return node
return array("aspath" => $node->getNodes());
}
} else {
$node = $mdlBGP->aspaths->aspath->add();
return array("aspath" => $node->getNodes());
}
return array();
}
public function addAspathAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("aspath")) {
$result = array("result" => "failed", "validations" => array());
$mdlBGP = $this->getModel();
$node = $mdlBGP->aspaths->aspath->Add();
$node->setNodes($this->request->getPost("aspath"));
$valMsgs = $mdlBGP->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "aspath", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delAspathAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlBGP = $this->getModel();
if ($uuid != null) {
if ($mdlBGP->aspaths->aspath->del($uuid)) {
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setAspathAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("aspath")) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference('aspaths.aspath.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$aspathInfo = $this->request->getPost("aspath");
$node->setNodes($aspathInfo);
$valMsgs = $mdlNeighbor->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "aspath", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function searchPrefixlistAction()
{
$this->sessionClose();
$mdlBGP = $this->getModel();
$grid = new UIModelGrid($mdlBGP->prefixlists->prefixlist);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "seqnumber", "action", "network" )
);
}
public function getPrefixlistAction($uuid = null)
{
$mdlBGP = $this->getModel();
if ($uuid != null) {
$node = $mdlBGP->getNodeByReference('prefixlists.prefixlist.' . $uuid);
if ($node != null) {
// return node
return array("prefixlist" => $node->getNodes());
}
} else {
$node = $mdlBGP->prefixlists->prefixlist->add();
return array("prefixlist" => $node->getNodes());
}
return array();
}
public function addPrefixlistAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("prefixlist")) {
$result = array("result" => "failed", "validations" => array());
$mdlBGP = $this->getModel();
$node = $mdlBGP->prefixlists->prefixlist->Add();
$node->setNodes($this->request->getPost("prefixlist"));
$valMsgs = $mdlBGP->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "prefixlist", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delPrefixlistAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlBGP = $this->getModel();
if ($uuid != null) {
if ($mdlBGP->prefixlists->prefixlist->del($uuid)) {
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setPrefixlistAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("prefixlist")) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference('prefixlists.prefixlist.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$prefixlistInfo = $this->request->getPost("prefixlist");
$node->setNodes($prefixlistInfo);
$valMsgs = $mdlNeighbor->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "prefixlist", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function searchRoutemapAction()
{
$this->sessionClose();
$mdlBGP = $this->getModel();
$grid = new UIModelGrid($mdlBGP->routemaps->routemap);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "action", "id", "match", "set" )
);
}
public function getRoutemapAction($uuid = null)
{
$mdlBGP = $this->getModel();
if ($uuid != null) {
$node = $mdlBGP->getNodeByReference('routemaps.routemap.' . $uuid);
if ($node != null) {
// return node
return array("routemap" => $node->getNodes());
}
} else {
$node = $mdlBGP->routemaps->routemap->add();
return array("routemap" => $node->getNodes());
}
return array();
}
public function addRoutemapAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("routemap")) {
$result = array("result" => "failed", "validations" => array());
$mdlBGP = $this->getModel();
$node = $mdlBGP->routemaps->routemap->Add();
$node->setNodes($this->request->getPost("routemap"));
$valMsgs = $mdlBGP->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "routemap", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delRoutemapAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlBGP = $this->getModel();
if ($uuid != null) {
if ($mdlBGP->routemaps->routemap->del($uuid)) {
$mdlBGP->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setRoutemapAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("routemap")) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference('routemaps.routemap.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$routemapInfo = $this->request->getPost("routemap");
$node->setNodes($routemapInfo);
$valMsgs = $mdlNeighbor->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "routemap", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function toggle_handler($uuid, $elements, $element)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference($elements . '.'. $element .'.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == "1") {
$result['result'] = "Disabled";
$node->enabled = "0";
} else {
$result['result'] = "Enabled";
$node->enabled = "1";
}
// if item has toggled, serialize to config and save
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleNeighborAction($uuid)
{
return $this->toggle_handler($uuid, 'neighbors', 'neighbor');
}
public function toggleAspathAction($uuid)
{
return $this->toggle_handler($uuid, 'aspaths', 'aspath');
}
public function togglePrefixlistAction($uuid)
{
return $this->toggle_handler($uuid, 'prefixlists', 'prefixlist');
}
public function toggleRoutemapAction($uuid)
{
return $this->toggle_handler($uuid, 'routemaps', 'routemap');
}
}

View file

@ -0,0 +1,139 @@
<?php
/**
* Copyright (C) 2017 Frank Wall
* Copyright (C) 2017 Michael Muenz
*
* 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\Quagga\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Backend;
use \OPNsense\Core\Config;
/**
* Class DiagnosticsController
* @package OPNsense\Quagga
*/
class DiagnosticsController extends ApiControllerBase
{
/**
* show ip bgp
* @return array
*/
public function showipbgpAction()
{
$backend = new Backend();
$response = json_decode(trim($backend->configdRun("quagga diag-bgp2")));
return array("response" => $response);
}
/**
* show ip bgp summary
* @return array
*/
public function showipbgpsummaryAction()
{
$backend = new Backend();
$response = $backend->configdRun("quagga diag-bgp summary");
return array("response" => $response);
}
public function showrunningconfigAction()
{
$backend = new Backend();
$response = $backend->configdRun("quagga general-runningconfig");
return array("response" => $response);
}
private function get_ospf_information($name)
{
$backend = new Backend();
return array("response" => json_decode(trim($backend->configdRun("quagga ospf-$name"))));
}
private function get_ospf3_information($name)
{
$backend = new Backend();
return array("response" => json_decode(trim($backend->configdRun("quagga ospfv3-$name"))));
}
// OSPFv2
public function ospfoverviewAction()
{
return $this->get_ospf_information('overview');
}
public function ospfneighborAction()
{
return $this->get_ospf_information('neighbor');
}
public function ospfrouteAction()
{
return $this->get_ospf_information('route');
}
public function ospfdatabaseAction()
{
return $this->get_ospf_information('database');
}
public function ospfinterfaceAction()
{
return $this->get_ospf_information('interface');
}
// OSPFv3
public function ospfv3overviewAction()
{
return $this->get_ospf3_information('overview');
}
public function ospfv3neighborAction()
{
return $this->get_ospf3_information('neighbor');
}
public function ospfv3routeAction()
{
return $this->get_ospf3_information('route');
}
public function ospfv3databaseAction()
{
return $this->get_ospf3_information('database');
}
public function ospfv3interfaceAction()
{
return $this->get_ospf3_information('interface');
}
// General
private function get_general_information($name)
{
$backend = new Backend();
return array("response" => json_decode(trim($backend->configdRun("quagga general-$name")), true));
}
public function generalroutesAction()
{
return $this->get_general_information('routes');
}
public function logAction()
{
return $this->get_general_information('log')['response']['general_log'];
}
public function generalroutes6Action()
{
return $this->get_general_information('routes6');
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* Copyright (C) 2015 - 2017 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
*
* 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\Quagga\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Quagga\General;
use \OPNsense\Core\Config;
class GeneralController extends ApiControllerBase
{
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlGeneral = new General();
$result['general'] = $mdlGeneral->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlGeneral = new General();
$mdlGeneral->setNodes($this->request->getPost("general"));
// perform validation
$valMsgs = $mdlGeneral->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlGeneral->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
}

View file

@ -0,0 +1,196 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* Copyright (C) 2017 Michael Muenz
* 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\Quagga\Api;
use \OPNsense\Quagga\OSPF6;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class Ospf6settingsController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'OSPF6';
static protected $internalModelClass = '\OPNsense\Quagga\OSPF6';
public function getAction()
{
$result = array();
if ($this->request->isGet()) {
$mdlospf6 = new OSPF6();
$result['ospf6'] = $mdlospf6->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlospf6 = new OSPF6();
$mdlospf6->setNodes($this->request->getPost("ospf6"));
// perform validation
$valMsgs = $mdlospf6->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlospf6->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
/////////////////////////////////////////////////////////////////////
public function searchInterfaceAction()
{
$this->sessionClose();
$mdlOSPF6 = $this->getModel();
$grid = new UIModelGrid($mdlOSPF6->interfaces->interface);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "interfacename", "area", "networktype")
);
}
public function getInterfaceAction($uuid = null)
{
$mdlOSPF6 = $this->getModel();
if ($uuid != null) {
$node = $mdlOSPF6->getNodeByReference('interfaces.interface.' . $uuid);
if ($node != null) {
// return node
return array("interface" => $node->getNodes());
}
} else {
$node = $mdlOSPF6->interfaces->interface->add();
return array("interface" => $node->getNodes());
}
return array();
}
public function addInterfaceAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("interface")) {
$result = array("result" => "failed", "validations" => array());
$mdlOSPF6 = $this->getModel();
$node = $mdlOSPF6->interfaces->interface->Add();
$node->setNodes($this->request->getPost("interface"));
$valMsgs = $mdlOSPF6->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "interface", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlOSPF6->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delInterfaceAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlOSPF6 = $this->getModel();
if ($uuid != null) {
if ($mdlOSPF6->interfaces->interface->del($uuid)) {
$mdlOSPF6->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setInterfaceAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("interface")) {
$mdlNetwork = $this->getModel();
if ($uuid != null) {
$node = $mdlNetwork->getNodeByReference('interfaces.interface.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$interfaceInfo = $this->request->getPost("interface");
$node->setNodes($interfaceInfo);
$valMsgs = $mdlNetwork->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "interface", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNetwork->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function toggle_handler($uuid, $elements, $element)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlNetwork = $this->getModel();
if ($uuid != null) {
$node = $mdlNetwork->getNodeByReference($elements . '.'. $element .'.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == "1") {
$result['result'] = "Disabled";
$node->enabled = "0";
} else {
$result['result'] = "Enabled";
$node->enabled = "1";
}
// if item has toggled, serialize to config and save
$mdlNetwork->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleInterfaceAction($uuid)
{
return $this->toggle_handler($uuid, 'interfaces', 'interface');
}
}

View file

@ -0,0 +1,408 @@
<?php
/*
* Copyright (C) 2015-2017 Deciso B.V.
* Copyright (C) 2015 Jos Schellevis
* Copyright (C) 2017 Fabian Franz
* 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\Quagga\Api;
use \OPNsense\Quagga\OSPF;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
class OspfsettingsController extends ApiMutableModelControllerBase
{
static protected $internalModelName = 'OSPF';
static protected $internalModelClass = '\OPNsense\Quagga\OSPF';
public function getAction()
{
$result = array();
if ($this->request->isGet()) {
$mdlospf = new OSPF();
$result['ospf'] = $mdlospf->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlospf = new OSPF();
$mdlospf->setNodes($this->request->getPost("ospf"));
// perform validation
$valMsgs = $mdlospf->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["general.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlospf->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
/////////////////////////////////////////////////////////////////////
public function searchNetworkAction()
{
$this->sessionClose();
$mdlOSPF = $this->getModel();
$grid = new UIModelGrid($mdlOSPF->networks->network);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "ipaddr", "netmask", "area")
);
}
public function searchInterfaceAction()
{
$this->sessionClose();
$mdlOSPF = $this->getModel();
$grid = new UIModelGrid($mdlOSPF->interfaces->interface);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "interfacename", "networktype", "authtype", "area")
);
}
public function searchPrefixlistAction()
{
$this->sessionClose();
$mdlOSPF = $this->getModel();
$grid = new UIModelGrid($mdlOSPF->prefixlists->prefixlist);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "seqnumber", "action", "network" )
);
}
public function getNetworkAction($uuid = null)
{
$mdlOSPF = $this->getModel();
if ($uuid != null) {
$node = $mdlOSPF->getNodeByReference('networks.network.' . $uuid);
if ($node != null) {
// return node
return array("network" => $node->getNodes());
}
} else {
$node = $mdlOSPF->networks->network->add();
return array("network" => $node->getNodes());
}
return array();
}
public function getInterfaceAction($uuid = null)
{
$mdlOSPF = $this->getModel();
if ($uuid != null) {
$node = $mdlOSPF->getNodeByReference('interfaces.interface.' . $uuid);
if ($node != null) {
// return node
return array("interface" => $node->getNodes());
}
} else {
$node = $mdlOSPF->interfaces->interface->add();
return array("interface" => $node->getNodes());
}
return array();
}
public function getPrefixlistAction($uuid = null)
{
$mdlOSPF = $this->getModel();
if ($uuid != null) {
$node = $mdlOSPF->getNodeByReference('prefixlists.prefixlist.' . $uuid);
if ($node != null) {
// return node
return array("prefixlist" => $node->getNodes());
}
} else {
$node = $mdlOSPF->prefixlists->prefixlist->add();
return array("prefixlist" => $node->getNodes());
}
return array();
}
public function addNetworkAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("network")) {
$result = array("result" => "failed", "validations" => array());
$mdlOSPF = $this->getModel();
$node = $mdlOSPF->networks->network->Add();
$node->setNodes($this->request->getPost("network"));
$valMsgs = $mdlOSPF->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "network", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function addInterfaceAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("interface")) {
$result = array("result" => "failed", "validations" => array());
$mdlOSPF = $this->getModel();
$node = $mdlOSPF->interfaces->interface->Add();
$node->setNodes($this->request->getPost("interface"));
$valMsgs = $mdlOSPF->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "interface", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function addPrefixlistAction()
{
$result = array("result" => "failed");
if ($this->request->isPost() && $this->request->hasPost("prefixlist")) {
$result = array("result" => "failed", "validations" => array());
$mdlOSPF = $this->getModel();
$node = $mdlOSPF->prefixlists->prefixlist->Add();
$node->setNodes($this->request->getPost("prefixlist"));
$valMsgs = $mdlOSPF->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "prefixlist", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
unset($result['validations']);
$result["result"] = "saved";
}
}
return $result;
}
public function delNetworkAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlOSPF = $this->getModel();
if ($uuid != null) {
if ($mdlOSPF->networks->network->del($uuid)) {
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function delInterfaceAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlOSPF = $this->getModel();
if ($uuid != null) {
if ($mdlOSPF->interfaces->interface->del($uuid)) {
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function delPrefixlistAction($uuid)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlOSPF = $this->getModel();
if ($uuid != null) {
if ($mdlOSPF->prefixlists->prefixlist->del($uuid)) {
$mdlOSPF->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
}
public function setNetworkAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("network")) {
$mdlNetwork = $this->getModel();
if ($uuid != null) {
$node = $mdlNetwork->getNodeByReference('networks.network.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$networkInfo = $this->request->getPost("network");
$node->setNodes($networkInfo);
$valMsgs = $mdlNetwork->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "network", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNetwork->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function setInterfaceAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("interface")) {
$mdlNetwork = $this->getModel();
if ($uuid != null) {
$node = $mdlNetwork->getNodeByReference('interfaces.interface.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$interfaceInfo = $this->request->getPost("interface");
$node->setNodes($interfaceInfo);
$valMsgs = $mdlNetwork->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "interface", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNetwork->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function setPrefixlistAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("prefixlist")) {
$mdlNeighbor = $this->getModel();
if ($uuid != null) {
$node = $mdlNeighbor->getNodeByReference('prefixlists.prefixlist.' . $uuid);
if ($node != null) {
$result = array("result" => "failed", "validations" => array());
$prefixlistInfo = $this->request->getPost("prefixlist");
$node->setNodes($prefixlistInfo);
$valMsgs = $mdlNeighbor->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "prefixlist", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdlNeighbor->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
}
}
return array("result" => "failed");
}
public function toggle_handler($uuid, $elements, $element)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlNetwork = $this->getModel();
if ($uuid != null) {
$node = $mdlNetwork->getNodeByReference($elements . '.'. $element .'.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == "1") {
$result['result'] = "Disabled";
$node->enabled = "0";
} else {
$result['result'] = "Enabled";
$node->enabled = "1";
}
// if item has toggled, serialize to config and save
$mdlNetwork->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
}
public function toggleNetworkAction($uuid)
{
return $this->toggle_handler($uuid, 'networks', 'network');
}
public function toggleInterfaceAction($uuid)
{
return $this->toggle_handler($uuid, 'interfaces', 'interface');
}
public function togglePrefixlistAction($uuid)
{
return $this->toggle_handler($uuid, 'prefixlists', 'prefixlist');
}
}

View file

@ -0,0 +1,75 @@
<?php
/**
* Copyright (C) 2015 - 2017 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
*
* 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\Quagga\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Quagga\RIP;
use \OPNsense\Core\Config;
class RipController extends ApiControllerBase
{
public function getAction()
{
// define list of configurable settings
$result = array();
if ($this->request->isGet()) {
$mdlRIP = new RIP();
$result['rip'] = $mdlRIP->getNodes();
}
return $result;
}
public function setAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
// load model and update with provided data
$mdlRIP = new RIP();
$mdlRIP->setNodes($this->request->getPost("rip"));
// perform validation
$valMsgs = $mdlRIP->performValidation();
foreach ($valMsgs as $field => $msg) {
if (!array_key_exists("validations", $result)) {
$result["validations"] = array();
}
$result["validations"]["rip.".$msg->getField()] = $msg->getMessage();
}
// serialize model to config and save
if ($valMsgs->count() == 0) {
$mdlRIP->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "saved";
}
}
return $result;
}
}

View file

@ -0,0 +1,150 @@
<?php
/**
* Copyright (C) 2015 - 2017 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
*
* 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\Quagga\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Backend;
use \OPNsense\Quagga\General;
/**
* Class ServiceController
* @package OPNsense\Quagga
*/
class ServiceController extends ApiControllerBase
{
/**
* start quagga service and reload filter rules to pass OSPF
* before the bogon filter kills the routing protocol packets
* @return array
*/
public function startAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga start');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* stop quagga service
* @return array
*/
public function stopAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga stop');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* restart quagga service
* @return array
*/
public function restartAction()
{
if ($this->request->isPost()) {
$backend = new Backend();
$response = $backend->configdRun('quagga restart');
$backend->configdRun('filter reload');
return array('response' => $response);
} else {
return array('response' => array());
}
}
/**
* retrieve status of quagga
* @return array
* @throws \Exception
*/
public function statusAction()
{
$backend = new Backend();
$mdlGeneral = new General();
$response = $backend->configdRun('quagga status');
if (strpos($response, 'not running') > 0) {
if ($mdlGeneral->enabled->__toString() == 1) {
$status = 'stopped';
} else {
$status = 'disabled';
}
} elseif (strpos($response, 'is running') > 0) {
$status = 'running';
} elseif ($mdlGeneral->enabled->__toString() == 0) {
$status = 'disabled';
} else {
$status = 'unknown';
}
return array('status' => $status);
}
/**
* reconfigure quagga, generate config and reload
*/
public function reconfigureAction()
{
if ($this->request->isPost()) {
// close session for long running action
$this->sessionClose();
$mdlGeneral = new General();
$backend = new Backend();
$runStatus = $this->statusAction();
// stop quagga if it is running or not
$this->stopAction();
// generate template
$backend->configdRun('template reload OPNsense/Quagga');
// (res)start daemon
if ($mdlGeneral->enabled->__toString() == 1) {
$this->startAction();
}
return array('status' => 'ok');
} else {
return array('status' => 'failed');
}
}
}

View file

@ -0,0 +1,39 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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\Quagga;
class BgpController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("BGP Settings");
$this->view->bgpForm = $this->getForm("bgp");
$this->view->formDialogEditBGPNeighbor = $this->getForm("dialogEditBGPNeighbor");
$this->view->formDialogEditBGPASPaths = $this->getForm("dialogEditBGPASPath");
$this->view->formDialogEditBGPPrefixLists = $this->getForm("dialogEditBGPPrefixLists");
$this->view->formDialogEditBGPRouteMaps = $this->getForm("dialogEditBGPRouteMaps");
$this->view->pick('OPNsense/Quagga/bgp');
}
}

View file

@ -0,0 +1,55 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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\Quagga;
class DiagnosticsController extends \OPNsense\Base\IndexController
{
public function bgpAction()
{
$this->view->title = gettext("Diagnostics: BGP");
$this->view->diagnosticsForm = $this->getForm("diagnostics");
$this->view->pick('OPNsense/Quagga/diagnosticsbgp');
}
public function ospfAction()
{
$this->view->title = gettext("Diagnostics: OSPF");
$this->view->pick('OPNsense/Quagga/diagnosticsospf');
}
public function ospfv3Action()
{
$this->view->title = gettext("Diagnostics: OSPFv3");
$this->view->pick('OPNsense/Quagga/diagnosticsospfv3');
}
public function generalAction()
{
$this->view->title = gettext("Diagnostics: General");
$this->view->pick('OPNsense/Quagga/diagnosticsgeneral');
}
public function logAction()
{
$this->view->title = gettext("Diagnostics: Log");
$this->view->pick('OPNsense/Quagga/log');
}
}

View file

@ -0,0 +1,38 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
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\Quagga;
class GeneralController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("Routing-Settings");
$this->view->generalForm = $this->getForm("general");
$this->view->pick('OPNsense/Quagga/general');
}
}

View file

@ -0,0 +1,38 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
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\Quagga;
class IsisController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("IS-IS-Settings");
$this->view->generalForm = $this->getForm("isis");
$this->view->pick('OPNsense/Quagga/isis');
}
}

View file

@ -0,0 +1,36 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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\Quagga;
class Ospf6Controller extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("OSPFv3 Settings");
$this->view->ospf6Form = $this->getForm("ospf6");
$this->view->formDialogEditInterface = $this->getForm("dialogEditOSPF6Interface");
$this->view->pick('OPNsense/Quagga/ospf6');
}
}

View file

@ -0,0 +1,41 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
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\Quagga;
class OspfController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("OSPF Settings");
$this->view->generalForm = $this->getForm("ospf");
$this->view->formDialogEditNetwork = $this->getForm("dialogEditOSPFNetwork");
$this->view->formDialogEditInterface = $this->getForm("dialogEditOSPFInterface");
$this->view->formDialogEditPrefixLists = $this->getForm("dialogEditOSPFPrefixLists");
$this->view->pick('OPNsense/Quagga/ospf');
}
}

View file

@ -0,0 +1,38 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
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\Quagga;
class RipController extends \OPNsense\Base\IndexController
{
public function indexAction()
{
$this->view->title = gettext("RIP Settings");
$this->view->ripForm = $this->getForm("rip");
$this->view->pick('OPNsense/Quagga/rip');
}
}

View file

@ -0,0 +1,30 @@
<form>
<field>
<id>bgp.enabled</id>
<label>enable</label>
<type>checkbox</type>
<help>This will activate the bgp service.</help>
</field>
<field>
<id>bgp.asnumber</id>
<label>BGP AS Number</label>
<type>text</type>
<help>Your AS Number here</help>
</field>
<field>
<id>bgp.networks</id>
<label>Network</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>Select the network to advertise, you have to set a Null route via System -> Routes</help>
</field>
<field>
<id>bgp.redistribute</id>
<label>Route Redistribution</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select other routing sources, which should be redistributed to the other nodes.]]></help>
<hint>Type or select a route source.</hint>
</field>
</form>

View file

@ -0,0 +1,8 @@
<form>
<field>
<id>diagnostics.bgpneighbor</id>
<label>BGP Neighbor</label>
<type>text</type>
<hint>One of the neighbor IPs</hint>
</field>
</form>

View file

@ -0,0 +1,26 @@
<form>
<field>
<id>aspath.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable / Disable</help>
</field>
<field>
<id>aspath.number</id>
<label>Number</label>
<type>text</type>
<help>The ACL rule number (10-99); keep in mind that there are no sequence numbers with AS-Path lists. When you want to add a new line between you have to completely remove the ACL!</help>
</field>
<field>
<id>aspath.action</id>
<label>Action</label>
<type>select_multiple</type>
<help>Set permit for match or deny to negate the rule.</help>
</field>
<field>
<id>aspath.as</id>
<label>AS</label>
<type>text</type>
<help>The AS pattern you want to match, regexp allowed (e.g. .$ or _1$). It's not validated so please be careful!</help>
</field>
</form>

View file

@ -0,0 +1,59 @@
<form>
<field>
<id>neighbor.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
</field>
<field>
<id>neighbor.address</id>
<label>Peer-IP</label>
<type>text</type>
<help>Specify the IP of your neighbor.</help>
</field>
<field>
<id>neighbor.remoteas</id>
<label>Remote AS</label>
<type>text</type>
<help>Neighbor AS.</help>
</field>
<field>
<id>neighbor.updatesource</id>
<label>Update-Source Interface</label>
<type>select_multiple</type>
<help>Physical name of the interface facing the peer</help>
</field>
<field>
<id>neighbor.nexthopself</id>
<label>Next-Hop-Self</label>
<type>checkbox</type>
</field>
<field>
<id>neighbor.defaultoriginate</id>
<label>Send Defaultroute</label>
<type>checkbox</type>
</field>
<field>
<id>neighbor.linkedPrefixlistIn</id>
<label>Prefix-List In</label>
<type>dropdown</type>
<help>Prefix-List for inbound direction</help>
</field>
<field>
<id>neighbor.linkedPrefixlistOut</id>
<label>Prefix-List Out</label>
<type>dropdown</type>
<help>Prefix-List for outbound direction</help>
</field>
<field>
<id>neighbor.linkedRoutemapIn</id>
<label>Route-Map In</label>
<type>dropdown</type>
<help>Route-Map for inbound direction</help>
</field>
<field>
<id>neighbor.linkedRoutemapOut</id>
<label>Route-Map Out</label>
<type>dropdown</type>
<help>Route-Map for outbound direction</help>
</field>
</form>

View file

@ -0,0 +1,32 @@
<form>
<field>
<id>prefixlist.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable / Disable</help>
</field>
<field>
<id>prefixlist.name</id>
<label>Name</label>
<type>text</type>
<help>The name of your Prefix-List, please choose one near to the result you want to achieve.</help>
</field>
<field>
<id>prefixlist.seqnumber</id>
<label>Number</label>
<type>text</type>
<help>The ACL sequence number (10-99)</help>
</field>
<field>
<id>prefixlist.action</id>
<label>Action</label>
<type>select_multiple</type>
<help>Set permit for match or deny to negate the rule.</help>
</field>
<field>
<id>prefixlist.network</id>
<label>Network</label>
<type>text</type>
<help>The network pattern you want to match. You can also add "ge" or "le" additions after the network statement. It's not validated so please be careful!</help>
</field>
</form>

View file

@ -0,0 +1,40 @@
<form>
<field>
<id>routemap.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable / Disable</help>
</field>
<field>
<id>routemap.name</id>
<label>Name</label>
<type>text</type>
<help>Route-map name to match and set your patterns, it will be enabled via the neigbor configuration.</help>
</field>
<field>
<id>routemap.action</id>
<label>Action</label>
<type>select_multiple</type>
<help>Set permit for match or deny to negate the rule.</help>
</field>
<field>
<id>routemap.id</id>
<label>ID</label>
<type>text</type>
<help>Route-map ID between 10 and 99. Be aware that the sorting will be done under the hood, so when you add an entry between it get's to the right position</help>
</field>
<field>
<id>routemap.match</id>
<label>AS-Path List</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help>Select the AS-Path list</help>
</field>
<field>
<id>routemap.set</id>
<label>Set</label>
<type>text</type>
<help>Free text field for your set, please be careful! You can set e.g. "local-prefernce 300" or "community 1:1" (http://www.nongnu.org/quagga/docs/docs-multi/Route-Map-Set-Command.html#Route-Map-Set-Command)</help>
</field>
</form>

View file

@ -0,0 +1,55 @@
<form>
<field>
<id>interface.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
</field>
<field>
<id>interface.interfacename</id>
<label>Interface</label>
<style>tokenize</style>
<type>select_multiple</type>
<help>Select an interface where this settings apply to.</help>
</field>
<field>
<id>interface.area</id>
<label>Area</label>
<type>text</type>
<help>Area in wildcard mask style like 0.0.0.0 and no decimal 0</help>
</field>
<field>
<id>interface.cost</id>
<label>Cost</label>
<type>text</type>
</field>
<field>
<id>interface.hellointerval</id>
<label>Hello Interval</label>
<type>text</type>
</field>
<field>
<id>interface.deadinterval</id>
<label>Dead Interval</label>
<type>text</type>
</field>
<field>
<id>interface.retransmitinterval</id>
<label>Retransmission Interval</label>
<type>text</type>
</field>
<field>
<id>interface.transmitdelay</id>
<label>Retransmission Delay</label>
<type>text</type>
</field>
<field>
<id>interface.priority</id>
<label>Priority</label>
<type>text</type>
</field>
<field>
<id>interface.networktype</id>
<label>Network Type</label>
<type>select_multiple</type>
</field>
</form>

View file

@ -0,0 +1,59 @@
<form>
<field>
<id>interface.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
</field>
<field>
<id>interface.interfacename</id>
<label>Interface</label>
<style>tokenize</style>
<type>select_multiple</type>
<help>Select an interface where this settings apply to.</help>
</field>
<field>
<id>interface.authtype</id>
<label>Authentication Type</label>
<type>select_multiple</type>
</field>
<field>
<id>interface.authkey</id>
<label>Authentication Key</label>
<type>text</type>
</field>
<field>
<id>interface.cost</id>
<label>Cost</label>
<type>text</type>
</field>
<field>
<id>interface.hellointerval</id>
<label>Hello Interval</label>
<type>text</type>
</field>
<field>
<id>interface.deadinterval</id>
<label>Dead Interval</label>
<type>text</type>
</field>
<field>
<id>interface.retransmitinterval</id>
<label>Retransmission Interval</label>
<type>text</type>
</field>
<field>
<id>interface.transmitdelay</id>
<label>Retransmission Delay</label>
<type>text</type>
</field>
<field>
<id>interface.priority</id>
<label>Priority</label>
<type>text</type>
</field>
<field>
<id>interface.networktype</id>
<label>Network Type</label>
<type>select_multiple</type>
</field>
</form>

View file

@ -0,0 +1,35 @@
<form>
<field>
<id>network.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
</field>
<field>
<id>network.ipaddr</id>
<label>Network Address</label>
<type>text</type>
</field>
<field>
<id>network.netmask</id>
<label>Network Mask</label>
<type>text</type>
</field>
<field>
<id>network.area</id>
<label>Area</label>
<type>text</type>
<help>Area in wildcard mask style like 0.0.0.0 and no decimal 0</help>
</field>
<field>
<id>network.linkedPrefixlistIn</id>
<label>Prefix-List In</label>
<type>dropdown</type>
<help>Prefix-List for inbound direction</help>
</field>
<field>
<id>network.linkedPrefixlistOut</id>
<label>Prefix-List Out</label>
<type>dropdown</type>
<help>Prefix-List for outbound direction</help>
</field>
</form>

View file

@ -0,0 +1,32 @@
<form>
<field>
<id>prefixlist.enabled</id>
<label>Enabled</label>
<type>checkbox</type>
<help>Enable / Disable</help>
</field>
<field>
<id>prefixlist.name</id>
<label>Name</label>
<type>text</type>
<help>The name of your Prefix-List, please choose one near to the result you want to achieve.</help>
</field>
<field>
<id>prefixlist.seqnumber</id>
<label>Number</label>
<type>text</type>
<help>The ACL sequence number (10-99)</help>
</field>
<field>
<id>prefixlist.action</id>
<label>Action</label>
<type>select_multiple</type>
<help>Set permit for match or deny to negate the rule.</help>
</field>
<field>
<id>prefixlist.network</id>
<label>Network</label>
<type>text</type>
<help>The network pattern you want to match. It's not validated so please be careful!</help>
</field>
</form>

View file

@ -0,0 +1,32 @@
<form>
<field>
<id>general.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>This will activate the routing service.</help>
</field>
<field>
<id>general.enablelogfile</id>
<label>Create a logfile</label>
<type>checkbox</type>
<help>If you check this, a log file will be written to disk.</help>
</field>
<field>
<id>general.logfilelevel</id>
<label>Logfile level</label>
<type>dropdown</type>
<help>This is the detail level of the log. A higher level means more data is logged.</help>
</field>
<field>
<id>general.enablesyslog</id>
<label>Send log messages to syslog</label>
<type>checkbox</type>
<help>Syslog is a service which is made to collect log messages from different software and maybe to a central logging server. Check this box if you have such a setup.</help>
</field>
<field>
<id>general.sysloglevel</id>
<label>Syslog level</label>
<type>dropdown</type>
<help>This is the detail level of the log. A higher level means more data is logged.</help>
</field>
</form>

View file

@ -0,0 +1,8 @@
<form>
<field>
<id>routing.isis.general.Enabled</id>
<label>enable</label>
<type>checkbox</type>
<help>This will activate the isis service.</help>
</field>
</form>

View file

@ -0,0 +1,44 @@
<form>
<field>
<id>ospf.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>This will activate the OSPF service if routing protocols are enabled in "General".</help>
</field>
<field>
<id>ospf.routerid</id>
<label>Router ID</label>
<type>text</type>
<advanced>true</advanced>
<help>If you have a CARP setup, you may want to configure a router id in case of a conflict.</help>
</field>
<field>
<id>ospf.passiveinterfaces</id>
<label>Passive Interfaces</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select the interfaces, where no OSPF packets should be sent to.]]></help>
<hint>Type or select interface.</hint>
</field>
<field>
<id>ospf.redistribute</id>
<label>Route Redistribution</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select other routing sources, which should be redistributed to the other nodes.]]></help>
<hint>Type or select a route source.</hint>
</field>
<field>
<id>ospf.originate</id>
<label>Advertise Default Gateway</label>
<type>checkbox</type>
<help>This will send the information that we have a default gateway.</help>
</field>
<field>
<id>ospf.originatealways</id>
<label>Always Advertise Default Gateway</label>
<type>checkbox</type>
<help>This will send the information that we have a default gateway, regardless of if it is available.</help>
</field>
</form>

View file

@ -0,0 +1,22 @@
<form>
<field>
<id>ospf6.enabled</id>
<label>Enable</label>
<type>checkbox</type>
<help>This will activate the OSPFv3 service if routing protocols are enabled in "General".</help>
</field>
<field>
<id>ospf6.redistribute</id>
<label>Route Redistribution</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select other routing sources, which should be redistributed to the other nodes.]]></help>
<hint>Type or select a route source.</hint>
</field>
<field>
<id>ospf6.routerid</id>
<label>Router ID</label>
<type>text</type>
<help>Router ID as IPv4 Address</help>
</field>
</form>

View file

@ -0,0 +1,38 @@
<form>
<field>
<id>rip.enabled</id>
<label>enable</label>
<type>checkbox</type>
<help>This will activate the RIP service if the support of routing protocols is enabled in "General".</help>
</field>
<field>
<id>rip.version</id>
<label>Version</label>
<type>text</type>
<help>Choose your RIP version (1 or 2). 1 is classful, 2 supports CIDR.</help>
</field>
<field>
<id>rip.passiveinterfaces</id>
<label>Passive Interfaces</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select the interfaces, where no RIP packets should be sent to.]]></help>
<hint>Type or select interface.</hint>
</field>
<field>
<id>rip.redistribute</id>
<label>Route Redistribution</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[Select other routing sources, which should be redistributed to the other nodes.]]></help>
<hint>Type or select a route source.</hint>
</field>
<field>
<id>rip.networks</id>
<label>Networks</label>
<style>tokenize</style>
<type>select_multiple</type>
<allownew>true</allownew>
<help>Enter your networks in CIDR notation like 127.0.0.0/8.</help>
</field>
</form>

View file

@ -0,0 +1,9 @@
<acl>
<page-routing>
<name>Routing</name>
<patterns>
<pattern>ui/quagga/*</pattern>
<pattern>api/quagga/*</pattern>
</patterns>
</page-routing>
</acl>

View file

@ -0,0 +1,30 @@
<?php
namespace OPNsense\Quagga;
use OPNsense\Base\BaseModel;
/*
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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.
*/
class BGP extends BaseModel
{
}

View file

@ -0,0 +1,220 @@
<model>
<mount>//OPNsense/quagga/bgp</mount>
<description>BGP Routing configuration</description>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<asnumber type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>4294967295</MaximumValue>
</asnumber>
<networks type="CSVListField">
<default></default>
<Required>N</Required>
<mask>/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2},)*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})$/</mask>
</networks>
<redistribute type="OptionField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<OptionValues>
<babel>Babel routing protocol (Babel)</babel>
<ospf>Open Shortest Path First (OSPF)</ospf>
<connected>Connected routes (directly attached subnet or host)</connected>
<isis>Intermediate System to Intermediate System (IS-IS)</isis>
<kernel>Kernel routes (not installed via the zebra RIB)</kernel>
<rip>Routing Information Protocol (RIP)</rip>
<static>Statically configured routes</static>
</OptionValues>
</redistribute>
<neighbors>
<neighbor type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<address type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</address>
<remoteas type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>4294967295</MaximumValue>
</remoteas>
<updatesource type="InterfaceField">
<default></default>
<Required>N</Required>
<multiple>N</multiple>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</updatesource>
<nexthopself type="BooleanField">
<default>0</default>
<Required>N</Required>
</nexthopself>
<defaultoriginate type="BooleanField">
<default>0</default>
<Required>N</Required>
</defaultoriginate>
<linkedPrefixlistIn type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.bgp</source>
<items>prefixlists.prefixlist</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Prefix-List item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedPrefixlistIn>
<linkedPrefixlistOut type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.bgp</source>
<items>prefixlists.prefixlist</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Prefix-List item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedPrefixlistOut>
<linkedRoutemapIn type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.bgp</source>
<items>routemaps.routemap</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Route-Map item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedRoutemapIn>
<linkedRoutemapOut type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.bgp</source>
<items>routemaps.routemap</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Route-Map item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedRoutemapOut>
</neighbor>
</neighbors>
<aspaths>
<aspath type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<number type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>10</MinimumValue>
<MaximumValue>99</MaximumValue>
</number>
<action type="OptionField">
<default></default>
<Required>Y</Required>
<OptionValues>
<permit>Permit</permit>
<deny>Deny</deny>
</OptionValues>
</action>
<as type="TextField">
<default></default>
<Required>Y</Required>
</as>
</aspath>
</aspaths>
<prefixlists>
<prefixlist type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<default></default>
<Required>Y</Required>
</name>
<seqnumber type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>10</MinimumValue>
<MaximumValue>99</MaximumValue>
</seqnumber>
<action type="OptionField">
<default></default>
<Required>Y</Required>
<OptionValues>
<permit>Permit</permit>
<deny>Deny</deny>
</OptionValues>
</action>
<network type="TextField">
<default></default>
<Required>Y</Required>
</network>
</prefixlist>
</prefixlists>
<routemaps>
<routemap type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<default></default>
<Required>Y</Required>
</name>
<action type="OptionField">
<default></default>
<Required>Y</Required>
<OptionValues>
<permit>Permit</permit>
<deny>Deny</deny>
</OptionValues>
</action>
<id type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>10</MinimumValue>
<MaximumValue>99</MaximumValue>
</id>
<match type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.bgp</source>
<items>aspaths.aspath</items>
<display>number</display>
</template>
</Model>
<ValidationMessage>Related item not found</ValidationMessage>
<Multiple>Y</Multiple>
<Required>N</Required>
</match>
<set type="TextField">
<default></default>
<Required>Y</Required>
</set>
</routemap>
</routemaps>
</items>
</model>

View file

@ -0,0 +1,34 @@
<?php
namespace OPNsense\Quagga;
use OPNsense\Base\BaseModel;
/*
Copyright (C) 2017 Fabian Franz
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.
*/
class General extends BaseModel
{
}

View file

@ -0,0 +1,48 @@
<model>
<mount>//OPNsense/quagga/general</mount>
<description>Quagga Routing configuration</description>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<enablelogfile type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enablelogfile>
<logfilelevel type="OptionField">
<Required>Y</Required>
<multiple>N</multiple>
<default>notifications</default>
<OptionValues>
<critical>Critical</critical>
<emergencies>Emergencies</emergencies>
<errors>Errors</errors>
<alerts>Alerts</alerts>
<warnings>Warnings</warnings>
<notifications>Notifications</notifications>
<informational>Informational</informational>
<debugging>Debugging</debugging>
</OptionValues>
</logfilelevel>
<enablesyslog type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enablesyslog>
<sysloglevel type="OptionField">
<Required>Y</Required>
<multiple>N</multiple>
<default>notifications</default>
<OptionValues>
<critical>Critical</critical>
<emergencies>Emergencies</emergencies>
<errors>Errors</errors>
<alerts>Alerts</alerts>
<warnings>Warnings</warnings>
<notifications>Notifications</notifications>
<informational>Informational</informational>
<debugging>Debugging</debugging>
</OptionValues>
</sysloglevel>
</items>
</model>

View file

@ -0,0 +1,17 @@
<menu>
<Routing cssClass="fa fa-map-signs" order="45">
<General VisibleName="General" cssClass="fa fa-cog fa-fw" url="/ui/quagga/general/index" order="1"/>
<RIP VisibleName="RIP" cssClass="fa fa-expand fa-fw" url="/ui/quagga/rip/index" order="10" />
<OSPF VisibleName="OSPF" cssClass="fa fa-map fa-fw" url="/ui/quagga/ospf/index" order="20" />
<OSPFv3 VisibleName="OSPFv3" cssClass="fa fa-map fa-fw" url="/ui/quagga/ospf6/index" order="25" />
<!--<ISIS VisibleName="IS-IS" cssClass="fa fa-bolt fa-fw" url="/ui/quagga/isis/index" order="30" />-->
<BGP VisibleName="BGPv4" cssClass="fa fa-globe fa-fw" url="/ui/quagga/bgp/index" order="40" />
<Diagnostics VisibleName="Diagnostics" cssClass="fa fa-medkit fa-fw" order="50">
<General VisibleName="General" url="/ui/quagga/diagnostics/general" order="1" />
<OSPF VisibleName="OSPF" url="/ui/quagga/diagnostics/ospf" order="20" />
<OSPFv3 VisibleName="OSPFv3" url="/ui/quagga/diagnostics/ospfv3" order="25" />
<BGP VisibleName="BGPv4" url="/ui/quagga/diagnostics/bgp" order="40" />
<LOG VisibleName="Log" url="/ui/quagga/diagnostics/log" order="100" />
</Diagnostics>
</Routing>
</menu>

View file

@ -0,0 +1,34 @@
<?php
namespace OPNsense\Quagga;
use OPNsense\Base\BaseModel;
/*
Copyright (C) 2017 Fabian Franz
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.
*/
class OSPF extends BaseModel
{
}

View file

@ -0,0 +1,206 @@
<model>
<mount>//OPNsense/quagga/ospf</mount>
<description>OSPF Routing configuration</description>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<routerid type="TextField">
<default></default>
<Required>N</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</routerid>
<originate type="BooleanField">
<default>0</default>
<Required>Y</Required>
</originate>
<originatealways type="BooleanField">
<default>0</default>
<Required>Y</Required>
</originatealways>
<passiveinterfaces type="InterfaceField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</passiveinterfaces>
<redistribute type="OptionField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<OptionValues>
<bgp>Border Gateway Protocol (BGP)</bgp>
<connected>Connected routes (directly attached subnet or host)</connected>
<kernel>Kernel routes (not installed via the zebra RIB)</kernel>
<rip>Routing Information Protocol (RIP)</rip>
<static>Statically configured routes</static>
</OptionValues>
</redistribute>
<networks>
<network type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<ipaddr type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</ipaddr>
<area type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</area>
<netmask type="IntegerField">
<default>24</default>
<MinimumValue>0</MinimumValue>
<Required>Y</Required>
<MaximumValue>32</MaximumValue>
<ValidationMessage>Network mask must be between 0 and 32.</ValidationMessage>
</netmask>
<linkedPrefixlistIn type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.ospf</source>
<items>prefixlists.prefixlist</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Prefix-List item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedPrefixlistIn>
<linkedPrefixlistOut type="ModelRelationField">
<Model>
<template>
<source>OPNsense.quagga.ospf</source>
<items>prefixlists.prefixlist</items>
<display>name</display>
<group>name</group>
</template>
</Model>
<ValidationMessage>Related Prefix-List item not found</ValidationMessage>
<Multiple>N</Multiple>
<Required>N</Required>
</linkedPrefixlistOut>
</network>
</networks>
<interfaces>
<interface type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<interfacename type="InterfaceField">
<Required>N</Required>
<multiple>N</multiple>
<default></default>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</interfacename>
<authtype type="OptionField">
<Required>N</Required>
<multiple>N</multiple>
<default></default>
<OptionValues>
<message-digest>MD5</message-digest>
</OptionValues>
</authtype>
<authkey type="TextField">
<default></default>
<Required>N</Required>
<mask>/^\S+$/</mask>
</authkey>
<cost type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Cost must be between 0 and 4294967295.</ValidationMessage>
</cost>
<hellointerval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Hello interval must be between 0 and 4294967295.</ValidationMessage>
</hellointerval>
<deadinterval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Dead interval must be between 0 and 4294967295.</ValidationMessage>
</deadinterval>
<retransmitinterval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Retransmit interval must be between 0 and 4294967295.</ValidationMessage>
</retransmitinterval>
<transmitdelay type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Transmit delay must be between 0 and 4294967295.</ValidationMessage>
</transmitdelay>
<priority type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Priority must be between 0 and 4294967295.</ValidationMessage>
</priority>
<networktype type="OptionField">
<Required>N</Required>
<multiple>N</multiple>
<default></default>
<OptionValues>
<broadcast>Broadcast multi-access network</broadcast>
<non-broadcast>NBMA network</non-broadcast>
<point-to-multipoint>Point-to-multipoint network</point-to-multipoint>
<point-to-point>Point-to-point network</point-to-point>
</OptionValues>
</networktype>
</interface>
</interfaces>
<prefixlists>
<prefixlist type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<default></default>
<Required>Y</Required>
</name>
<seqnumber type="IntegerField">
<default></default>
<Required>Y</Required>
<MinimumValue>10</MinimumValue>
<MaximumValue>99</MaximumValue>
</seqnumber>
<action type="OptionField">
<default></default>
<Required>Y</Required>
<OptionValues>
<permit>Permit</permit>
<deny>Deny</deny>
</OptionValues>
</action>
<network type="TextField">
<default></default>
<Required>Y</Required>
</network>
</prefixlist>
</prefixlists>
</items>
</model>

View file

@ -0,0 +1,30 @@
<?php
/*
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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\Quagga;
use OPNsense\Base\BaseModel;
class OSPF6 extends BaseModel
{
}

View file

@ -0,0 +1,98 @@
<model>
<mount>//OPNsense/quagga/ospf6</mount>
<description>OSPFv3 Routing configuration</description>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<redistribute type="OptionField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<OptionValues>
<connected>Connected routes (directly attached subnet or host)</connected>
<static>Statically configured routes</static>
</OptionValues>
</redistribute>
<routerid type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</routerid>
<interfaces>
<interface type="ArrayField">
<enabled type="BooleanField">
<default>1</default>
<Required>Y</Required>
</enabled>
<interfacename type="InterfaceField">
<Required>N</Required>
<multiple>N</multiple>
<default></default>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</interfacename>
<area type="TextField">
<default></default>
<Required>Y</Required>
<mask>/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/</mask>
</area>
<cost type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Cost must be between 0 and 4294967295.</ValidationMessage>
</cost>
<hellointerval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Hello interval must be between 0 and 4294967295.</ValidationMessage>
</hellointerval>
<deadinterval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Dead interval must be between 0 and 4294967295.</ValidationMessage>
</deadinterval>
<retransmitinterval type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Retransmit interval must be between 0 and 4294967295.</ValidationMessage>
</retransmitinterval>
<transmitdelay type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Transmit delay must be between 0 and 4294967295.</ValidationMessage>
</transmitdelay>
<priority type="IntegerField">
<default></default>
<MinimumValue>0</MinimumValue>
<Required>N</Required>
<MaximumValue>4294967295</MaximumValue>
<ValidationMessage>Priority must be between 0 and 4294967295.</ValidationMessage>
</priority>
<networktype type="OptionField">
<Required>N</Required>
<multiple>N</multiple>
<default></default>
<OptionValues>
<broadcast>Broadcast multi-access network</broadcast>
<non-broadcast>NBMA network</non-broadcast>
<point-to-multipoint>Point-to-multipoint network</point-to-multipoint>
<point-to-point>Point-to-point network</point-to-point>
</OptionValues>
</networktype>
</interface>
</interfaces>
</items>
</model>

View file

@ -0,0 +1,34 @@
<?php
namespace OPNsense\Quagga;
use OPNsense\Base\BaseModel;
/*
Copyright (C) 2017 Fabian Franz
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.
*/
class RIP extends BaseModel
{
}

View file

@ -0,0 +1,45 @@
<model>
<mount>//OPNsense/quagga/rip</mount>
<description>RIP Routing configuration</description>
<items>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<version type="IntegerField">
<MinimumValue>1</MinimumValue>
<MaximumValue>2</MaximumValue>
<default>2</default>
<Required>Y</Required>
</version>
<networks type="CSVListField">
<default></default>
<Required>Y</Required>
<mask>/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2},)*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\/\d{1,2})$/</mask>
</networks>
<passiveinterfaces type="InterfaceField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<filters>
<enable>/^(?!0).*$/</enable>
</filters>
</passiveinterfaces>
<redistribute type="OptionField">
<Required>N</Required>
<multiple>Y</multiple>
<default></default>
<OptionValues>
<babel>Babel routing protocol (Babel)</babel>
<bgp>Border Gateway Protocol (BGP)</bgp>
<connected>Connected routes (directly attached subnet or host)</connected>
<isis>Intermediate System to Intermediate System (IS-IS)</isis>
<kernel>Kernel routes (not installed via the zebra RIB)</kernel>
<pim>Protocol Independent Multicast (PIM)</pim>
<ospf>Open Shortest Path First (OSPF)</ospf>
<static>Statically configured routes</static>
</OptionValues>
</redistribute>
</items>
</model>

View file

@ -0,0 +1,226 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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.
#}
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#neighbors">{{ lang._('Neighbors') }}</a></li>
<li><a data-toggle="tab" href="#aspaths">{{ lang._('AS Path Lists') }}</a></li>
<li><a data-toggle="tab" href="#prefixlists">{{ lang._('Prefix Lists') }}</a></li>
<li><a data-toggle="tab" href="#routemaps">{{ lang._('Route Maps') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':bgpForm,'id':'frm_bgp_settings'])}}
<hr />
<div class="col-md-12">
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
</div>
</div>
<div id="neighbors" class="tab-pane fade in">
<table id="grid-neighbors" class="table table-responsive" data-editDialog="DialogEditBGPNeighbor">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="address" data-type="string" data-visible="true">{{ lang._('Neighbor Address') }}</th>
<th data-column-id="remoteas" data-type="string" data-visible="true">{{ lang._('Remote AS') }}</th>
<th data-column-id="updatesource" data-type="string" data-visible="true">{{ lang._('Update Source Address') }}</th>
<th data-column-id="nexthopself" data-type="string" data-formatter="rowtoggle">{{ lang._('Next Hop Self') }}</th>
<th data-column-id="defaultoriginate" data-type="string" data-formatter="rowtoggle">{{ lang._('Default Originate') }}</th>
<th data-column-id="linkedPrefixlistIn" data-type="string" data-visible="true">{{ lang._('Prefix List inbound') }}</th>
<th data-column-id="linkedPrefixlistOut" data-type="string" data-visible="true">{{ lang._('Prefix List outbound') }}</th>
<th data-column-id="linkedRoutemapIn" data-type="string" data-visible="true">{{ lang._('Route Map inbound') }}</th>
<th data-column-id="linkedRoutemapOut" data-type="string" data-visible="true">{{ lang._('Route Map outbound') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
<div id="aspaths" class="tab-pane fade in">
<table id="grid-aspaths" class="table table-responsive" data-editDialog="DialogEditBGPASPaths">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle" data-sortable="false">{{ lang._('Enabled') }}</th>
<th data-column-id="number" data-type="string" data-visible="true" data-sortable="true">{{ lang._('Number') }}</th>
<th data-column-id="action" data-type="string" data-visible="true" data-sortable="false">{{ lang._('Action') }}</th>
<th data-column-id="as" data-type="string" data-visible="true" data-sortable="false">{{ lang._('AS Number') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
<div id="prefixlists" class="tab-pane fade in">
<table id="grid-prefixlists" class="table table-responsive" data-editDialog="DialogEditBGPPrefixLists">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle" data-sortable="false">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true" data-sortable="true">{{ lang._('Name') }}</th>
<th data-column-id="seqnumber" data-type="string" data-visible="true" data-sortable="true">{{ lang._('Secquence Number') }}</th>
<th data-column-id="action" data-type="string" data-visible="true" data-sortable="false">{{ lang._('Action') }}</th>
<th data-column-id="network" data-type="string" data-visible="true" data-sortable="false">{{ lang._('Network') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
<div id="routemaps" class="tab-pane fade in">
<table id="grid-routemaps" class="table table-responsive" data-editDialog="DialogEditBGPRouteMaps">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true">{{ lang._('Name') }}</th>
<th data-column-id="action" data-type="string" data-visible="true">{{ lang._('Action') }}</th>
<th data-column-id="id" data-type="string" data-visible="true">{{ lang._('ID') }}</th>
<th data-column-id="match" data-type="string" data-visible="true">{{ lang._('AS Path List') }}</th>
<th data-column-id="set" data-type="string" data-visible="true">{{ lang._('Set') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
var data_get_map = {'frm_bgp_settings':"/api/quagga/bgp/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/bgp/set",formid='frm_bgp_settings',callback_ok=function(){
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
$("#grid-neighbors").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchNeighbor',
'get':'/api/quagga/bgp/getNeighbor/',
'set':'/api/quagga/bgp/setNeighbor/',
'add':'/api/quagga/bgp/addNeighbor/',
'del':'/api/quagga/bgp/delNeighbor/',
'toggle':'/api/quagga/bgp/toggleNeighbor/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-aspaths").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchAspath',
'get':'/api/quagga/bgp/getAspath/',
'set':'/api/quagga/bgp/setAspath/',
'add':'/api/quagga/bgp/addAspath/',
'del':'/api/quagga/bgp/delAspath/',
'toggle':'/api/quagga/bgp/toggleAspath/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-prefixlists").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchPrefixlist',
'get':'/api/quagga/bgp/getPrefixlist/',
'set':'/api/quagga/bgp/setPrefixlist/',
'add':'/api/quagga/bgp/addPrefixlist/',
'del':'/api/quagga/bgp/delPrefixlist/',
'toggle':'/api/quagga/bgp/togglePrefixlist/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-routemaps").UIBootgrid(
{ 'search':'/api/quagga/bgp/searchRoutemap',
'get':'/api/quagga/bgp/getRoutemap/',
'set':'/api/quagga/bgp/setRoutemap/',
'add':'/api/quagga/bgp/addRoutemap/',
'del':'/api/quagga/bgp/delRoutemap/',
'toggle':'/api/quagga/bgp/toggleRoutemap/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPNeighbor,'id':'DialogEditBGPNeighbor','label':lang._('Edit Neighbor')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPASPaths,'id':'DialogEditBGPASPaths','label':lang._('Edit AS Paths')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPPrefixLists,'id':'DialogEditBGPPrefixLists','label':lang._('Edit Prefix Lists')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditBGPRouteMaps,'id':'DialogEditBGPRouteMaps','label':lang._('Edit Route Maps')])}}

View file

@ -0,0 +1,115 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
Copyright (C) 2017 Michael Muenz
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.
#}
{#
{{ partial("layout_partials/base_form",['fields':diagnosticsForm,'id':'frm_diagnostics_settings'])}}
#}
<script type="text/x-template" id="overviewtpl">
<table>
<tr>
<td>{{ lang._('Table Version') }}</td>
<td><%= bgp_overview['table_version'] %></td>
</tr>
<tr>
<td>{{ lang._('Local Router ID') }}</td>
<td><%= bgp_overview['local_router_id'] %></td>
</tr>
</table>
<table>
<thead>
<tr>
<th>{{ lang._('Status') }}</th>
<th>{{ lang._('Network') }}</th>
<th>{{ lang._('Next Hop') }}</th>
<th>{{ lang._('Metric') }}</th>
<th>{{ lang._('LocPrf') }}</th>
<th>{{ lang._('Weight') }}</th>
<th>{{ lang._('Path') }}</th>
</tr>
</thead>
<tbody>
<% _.each(bgp_overview['output'], function (row) { %>
<tr>
<td>
<% _.each(row['status'], function(element) { %>
<abbr title="<%= translate(element['dn']) %>"><%= element['abb'] %></abbr>
<% }) %>
</td>
<td><%= row['Network'] %></td>
<td><%= row['Next Hop'] %></td>
<td><%= row['Metric'] %></td>
<td><%= row['LocPrf'] %></td>
<td><%= row['Weight'] %></td>
<td>
<% _.each(row['Path'], function(element) { %>
<abbr title="<%= translate(element['dn']) %>"><%= element['abb'] %></abbr>
<% }) %>
</td>
</tr>
<% }); %>
</tbody>
</table>
</script>
<script type="text/javascript" src="/ui/js/quagga/lodash.js"></script>
<script type="text/javascript">
function translate(x) {
return x;
}
$(document).ready(function() {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
ajaxCall(url="/api/quagga/diagnostics/showipbgp", sendData={}, callback=function(data,status) {
content = _.template($('#overviewtpl').html())(data['response'])
$('#overview').html(content)
});
ajaxCall(url="/api/quagga/diagnostics/showipbgpsummary", sendData={}, callback=function(data,status) {
$("#summarycontent").text(data['response']);
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#overview">{{ lang._('Overview') }}</a></li>
<li><a data-toggle="tab" href="#summary">{{ lang._('Summary') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="overview" class="tab-pane fade in active">
{{ lang._('loading...') }}
</div>
<div id="summary" class="tab-pane fade in">
<pre id="summarycontent"></pre>
</div>
</div>

View file

@ -0,0 +1,132 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
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.
#}
<script type="text/javascript" src="/ui/js/quagga/lodash.js"></script>
<script type="text/x-template" id="routestpl">
<table>
<thead>
<tr>
<th data-column-id="code" data-type="raw">{{ lang._('Code') }}</th>
<th data-column-id="network" data-type="string">{{ lang._('Network') }}</th>
<th data-column-id="ad" data-type="numeric">{{ lang._('Administrative Distance') }}</th>
<th data-column-id="metric" data-type="numeric">{{ lang._('Metric') }}</th>
<th data-column-id="interface" data-type="string">{{ lang._('Interface') }}</th>
<th data-column-id="time" data-type="string">{{ lang._('Time') }}</th>
</tr>
</thead>
<tbody>
<% _.each(general_routes, function(entry) { %>
<tr>
<td>
<% _.each(entry['code'], function(code) { %>
<abbr title="<%= translate(code['long']) %>"><%= (code['short']) %></abbr>
<% }); %>
</td>
<td><%= entry['network'] %></td>
<td><%= entry['ad'] %></td>
<td><%= entry['metric'] %></td>
<td><%= entry['interface'] %></td>
<td><%= entry['time'] %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
<script type="text/javascript">
function translate(content) {
tr = {};
tr['kernel route'] = '{{ lang._('Kernel Route') }}';
tr['FIB route'] = '{{ lang._('FIB Route') }}';
tr['connected'] = '{{ lang._('Connected') }}';
tr['selected route'] = '{{ lang._('Selected Route') }}';
tr['OSPF'] = '{{ lang._('OSPF') }}';
tr['RIP'] = '{{ lang._('RIP') }}';
tr['BGP'] = '{{ lang._('BGP') }}';
if (_.has(tr,content))
{
return tr[content];
}
else
{
return content;
}
}
dataconverters = {
boolean: {
from: function (value) { return (value == 'true') || (value == true); },
to: function (value) { return checkmark(value) }
},
raw: {
from: function (value) {
console.log(value)
return value
},
to: function (value) {
console.log(value);
return value
}
}
}
$(document).ready(function() {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status'])
});
ajaxCall(url="/api/quagga/diagnostics/generalroutes", sendData={}, callback=function(data,status) {
content = _.template($('#routestpl').html())(data['response'])
$('#routing').html(content)
//$('#routing table').bootgrid({converters: dataconverters})
});
ajaxCall(url="/api/quagga/diagnostics/generalroutes6", sendData={}, callback=function(data,status) {
content = _.template($('#routestpl').html())({general_routes: data['response']['general_routes6']})
$('#routing6').html(content)
//$('#routing6 table').bootgrid({converters: dataconverters})
});
ajaxCall(url="/api/quagga/diagnostics/showrunningconfig", sendData={}, callback=function(data,status) {
$("#runningconfig").text(data['response']);
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#routing">{{ lang._('IPv4 Routes') }}</a></li>
<li><a data-toggle="tab" href="#routing6">{{ lang._('IPv6 Routes') }}</a></li>
<li><a data-toggle="tab" href="#showrun">{{ lang._('Running Configuration') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="routing" class="tab-pane fade in active"></div>
<div id="routing6" class="tab-pane fade in"></div>
<div id="showrun" class="tab-pane fade in">
<pre id="runningconfig"></pre>
</div>
</div>

View file

@ -0,0 +1,484 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
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.
#}
<script type="text/x-template" id="overviewtpl">
<h2>{{ lang._('General') }}</h2>
<table class="table table-striped">
<tbody>
<tr>
<td>{{ lang._('RFC2328 Conform') }}</td>
<td><%= checkmark(ospf_overview['rfc2328_conform']) %></td>
</tr>
<tr>
<td>{{ lang._('ASBR') }}</td>
<td><%= checkmark(ospf_overview['asbr']) %></td>
</tr>
<tr>
<td>{{ lang._('Router ID') }}</td>
<td><%= ospf_overview['router_id'] %></td>
</tr>
<tr>
<td>{{ lang._('RFC1583 Compatibility') }}</td>
<td><%= checkmark(ospf_overview['rfc1583_compatibility']) %></td>
</tr>
<tr>
<td>{{ lang._('Opaque Capability') }}</td>
<td><%= checkmark(ospf_overview['opaque_capability']) %></td>
</tr>
<tr>
<td>{{ lang._('Initial SPF Scheduling Delay') }}</td>
<td><%= ospf_overview['initial_spf_scheduling_delay'] %></td>
</tr>
<tr>
<td>{{ lang._('Minimum Hold Time') }}</td>
<td><%= ospf_overview['hold_time']['min'] %> {{ lang._('Milliseconds') }}</td>
</tr>
<tr>
<td>{{ lang._('Maximum Hold Time') }}</td>
<td><%= ospf_overview['hold_time']['max'] %> {{ lang._('Milliseconds') }}</td>
</tr>
<tr>
<td>{{ lang._('Current Hold Time Multipier') }}</td>
<td><%= ospf_overview['current_hold_time_multipier'] %></td>
</tr>
<tr>
<td>{{ lang._('SPF Timer') }}</td>
<td><%= ospf_overview['spf_timer'] %></td>
</tr>
<tr>
<td>{{ lang._('Refresh Timer') }}</td>
<td><%= ospf_overview['refresh_timer'] %></td>
</tr>
<tr>
<td>{{ lang._('Areas Attached Count') }}</td>
<td><%= ospf_overview['areas_attached_count'] %></td>
</tr>
</tbody>
</table>
<h2>{{ lang._('Link State Area') }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>{{ lang._('Count') }}</th>
<th>{{ lang._('Checksum') }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>{{ lang._('External LSA') }}</td>
<td><%= ospf_overview['external_lsa']['count'] %></td>
<td><%= ospf_overview['external_lsa']['checksum'] %></td>
</tr>
<tr>
<td>{{ lang._('Opaque AS LSA') }}</td>
<td><%= ospf_overview['opaque_as_lsa']['count'] %></td>
<td><%= ospf_overview['opaque_as_lsa']['checksum'] %></td>
</tr>
</tbody>
</table>
<h2>{{ lang._('Areas') }}</h2>
<% if (ospf_overview['areas']) { %>
<% areas = ospf_overview['areas'] %>
<% _.each(_.keys(areas), function(areaname) { %>
<% area = areas[areaname] %>
<h3><%= areaname %></h3>
<table class="table table-striped">
<tbody>
<tr>
<td>{{ lang._('Interfaces: Total') }}</td>
<td><%= area['interfaces']['total'] %></td>
</tr>
<tr>
<td>{{ lang._('Interfaces: Active') }}</td>
<td><%= area['interfaces']['active'] %></td>
</tr>
<tr>
<td>{{ lang._('Fully Adjacent Neighbor Count') }}</td>
<td><%= area['fully_adjacent_neighbor_count'] %></td>
</tr>
<tr>
<td>{{ lang._('SPF Execution Count') }}</td>
<td><%= area['spf_exec_count'] %></td>
</tr>
</tbody>
</table>
<table class="table table-striped">
<thead>
<tr>
<th></th>
<th>{{ lang._('Count') }}</th>
<th>{{ lang._('Checksum') }}</th>
</tr>
</thead>
<tbody>
<% _.each(_.keys(area['lsa']), function(lsaname) { %>
<% lsa = area['lsa'][lsaname] %>
<tr>
<td><%= translate(lsaname) %></td>
<td><%= lsa['count'] %></td>
<td><%= lsa['checksum'] %></td>
</tr>
<% }) %>
</tbody>
</table>
<% }) %>
<% } %>
</script>
<script type="text/x-template" id="databasetpl">
<% _.each(_.keys(ospf_database), function(router_id) { %>
<h1>{{ lang._('Router ID:')}} <%= router_id %></h1>
<hr />
<h2>{{ lang._('Router Link State Area') }}</h2>
<% _.each(_.keys(ospf_database[router_id]['router_link_state_area']), function(area) { %>
<h3>Area <%= area %></h3>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="linkid" data-type="string">{{ lang._('Link ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('ADV Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="string">{{ lang._('Sequence Number') }}</th>
<th data-column-id="cksum" data-type="string">{{ lang._('Checksum') }}</th>
<th data-column-id="linkcnt" data-type="numeric">{{ lang._('Link Count') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_database[router_id]['router_link_state_area'][area], function(entry) { %>
<tr>
<td><%= entry["Link ID"] %></td>
<td><%= entry["ADV Router"] %></td>
<td><%= entry["Age"] %></td>
<td><%= entry["Seq#"] %></td>
<td><%= entry["CkSum"] %></td>
<td><%= entry["Link count"] %></td>
</tr>
<% }); %>
</tbody>
</table>
<% }); %>
<h2>{{ lang._('Net Link State Area') }}</h2>
<% _.each(_.keys(ospf_database[router_id]['net_link_state_area']), function(area) { %>
<h3>{{ lang._('Area:') }} <%= area %></h3>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="linkid" data-type="string">{{ lang._('Link ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('ADV Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="string">{{ lang._('Sequence Number') }}</th>
<th data-column-id="cksum" data-type="string">{{ lang._('Checksum') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_database[router_id]['net_link_state_area'][area], function(entry) { %>
<tr>
<td><%= entry["Link ID"] %></td>
<td><%= entry["ADV Router"] %></td>
<td><%= entry["Age"] %></td>
<td><%= entry["Seq#"] %></td>
<td><%= entry["CkSum"] %></td>
</tr>
<% }); %>
</tbody>
</table>
<% }); %>
<h2>{{ lang._('External States') }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="linkid" data-type="string">{{ lang._('Link ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('ADV Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="string">{{ lang._('Sequence Number') }}</th>
<th data-column-id="chsum" data-type="string">{{ lang._('Checksum') }}</th>
<th data-column-id="route" data-type="string">{{ lang._('Route') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_database[router_id]['external_states'], function(entry) { %>
<tr>
<td><%= entry["Link ID"] %></td>
<td><%= entry["ADV Router"] %></td>
<td><%= entry["Age"] %></td>
<td><%= entry["Seq#"] %></td>
<td><%= entry["CkSum"] %></td>
<td><%= entry["Route"] %></td>
</tr>
<% }); %>
</tbody>
</table>
<% }); %>
</script>
<script type="text/x-template" id="routestpl">
<h2>{{ lang._('Network Routing Table') }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="network" data-type="string">{{ lang._('Network') }}</th>
<th data-column-id="cost" data-type="numeric">{{ lang._('Cost') }}</th>
<th data-column-id="area" data-type="numeric">{{ lang._('Area') }}</th>
<th data-column-id="via" data-type="string">{{ lang._('Via') }}</th>
<th data-column-id="viainterface" data-type="string">{{ lang._('Via interface') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_route['OSPF network routing table'], function(entry) { %>
<tr>
<td><%= entry["type"] %></td>
<td><%= entry["network"] %></td>
<td><%= entry["cost"] %></td>
<td><%= entry["area"] %></td>
<td><%= translate(entry["via"]) %></td>
<td><%= entry["via_interface"] %></td>
</tr>
<% }); %>
</tbody>
</table>
<h2>{{ lang._('Router Routing Table') }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="cost" data-type="numeric">{{ lang._('Cost') }}</th>
<th data-column-id="area" data-type="string">{{ lang._('Area') }}</th>
<th data-column-id="asbr" data-type="boolean">{{ lang._('ASBR') }}</th>
<th data-column-id="via" data-type="string">{{ lang._('Via') }}</th>
<th data-column-id="viainterface" data-type="string">{{ lang._('Via interface') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_route['OSPF router routing table'], function(entry) { %>
<tr>
<td><%= entry["type"] %></td>
<td><%= entry["cost"] %></td>
<td><%= entry["area"] %></td>
<td><%= entry["asbr"] %></td>
<td><%= translate(entry["via"]) %></td>
<td><%= entry["via_interface"] %></td>
</tr>
<% }); %>
</tbody>
</table>
<h2>{{ lang._('External Routing Table') }}</h2>
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="network" data-type="string">{{ lang._('Network') }}</th>
<th data-column-id="cost" data-type="string">{{ lang._('Cost') }}</th>
<th data-column-id="tag" data-type="string">{{ lang._('Tag') }}</th>
<th data-column-id="via" data-type="string">{{ lang._('Via') }}</th>
<th data-column-id="viainterface" data-type="string">{{ lang._('Via interface') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_route['OSPF external routing table'], function(entry) { %>
<tr>
<td><%= entry["type"] %></td>
<td><%= entry["network"] %></td>
<td><%= entry["cost"] %></td>
<td><%= entry["tag"] %></td>
<td><%= translate(entry["via"]) %></td>
<td><%= entry["via_interface"] %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
<script type="text/x-template" id="neighbortpl">
<table class="table table-striped">
<thead>
<tr>
<th data-column-id="neighborid" data-type="string">{{ lang._('Neighbor ID') }}</th>
<th data-column-id="priority" data-type="numeric">{{ lang._('Priority') }}</th>
<th data-column-id="state" data-type="string">{{ lang._('State') }}</th>
<th data-column-id="deadtime" data-type="string">{{ lang._('Dead Time') }}</th>
<th data-column-id="address" data-type="string">{{ lang._('Address') }}</th>
<th data-column-id="interface" data-type="string">{{ lang._('Interface') }}</th>
<th data-column-id="rxmtl" data-type="numeric">RXmtL</th>
<th data-column-id="rqstl" data-type="numeric">RqstL</th>
<th data-column-id="dbsml" data-type="numeric">DBsmL</th>
</tr>
</thead>
<tbody>
<% _.each(ospf_neighbors, function(entry) { %>
<tr>
<td><%= entry["Neighbor ID"] %></td>
<td><%= entry["Pri"] %></td>
<td><%= translate(entry["State"]) %></td>
<td><%= entry["Dead Time"] %></td>
<td><%= entry["Address"] %></td>
<td><%= entry["Interface"] %></td>
<td><%= entry["RXmtL"] %></td>
<td><%= entry["RqstL"] %></td>
<td><%= entry["DBsmL"] %></td>
</tr>
<% }); %>
</tbody>
</table>
</script>
<script type="text/x-template" id="interfacetpl">
<% _.each(_.keys(ospf_interface), function(interfacename) { %>
<% int = ospf_interface[interfacename] %>
<h2><%= interfacename %></h2>
<table class="table table-striped">
<tbody>
<% _.each(_.keys(int), function(propertyname) { %>
<tr>
<td><%= translate(propertyname) %></td>
<td>
<% if (int[propertyname] === false || int[propertyname] === true) { %>
<%= checkmark(int[propertyname]) %>
<% } else if (propertyname == 'intervals') { %>
{{ lang._('Hello Interval:') }} <%= int[propertyname]['hello'] %><br />
{{ lang._('Dead Interval:') }} <%= int[propertyname]['dead'] %><br />
{{ lang._('Wait Interval:') }} <%= int[propertyname]['wait'] %><br />
{{ lang._('Retransmit Interval:') }} <%= int[propertyname]['retransmit'] %>
<% } else { %>
<%= int[propertyname] %>
<% } %>
</td>
</tr>
<% }); %>
</tbody>
</table>
<% }) %>
</script>
<script type="text/javascript" src="/ui/js/quagga/lodash.js"></script>
<script>
function translate(data)
{
tr = []
tr['count'] = '{{ lang._('Count') }}'
tr['router'] = '{{ lang._('Router') }}'
tr['network'] = '{{ lang._('Network') }}'
tr['summary'] = '{{ lang._('Summary') }}'
tr['ASBR summary'] = '{{ lang._('ASBR summary') }}'
tr['NSSA'] = '{{ lang._('NSSA') }}'
tr['directly attached'] = '{{ lang._('Directly Attached') }}'
tr['Full/DR'] = '{{ lang._('Full (Designated Router)') }}'
tr['enabled'] = '{{ lang._('Enabled') }}'
tr['cost'] = '{{ lang._('Cost') }}'
tr['priority'] = '{{ lang._('Priority') }}'
tr['router_id'] = '{{ lang._('Router ID') }}'
tr['network_type'] = '{{ lang._('Network Type') }}'
tr['area'] = '{{ lang._('Area') }}'
tr['transmit_delay'] = '{{ lang._('Transmit Delay') }}'
tr['state'] = '{{ lang._('State') }}'
tr['broadcast'] = '{{ lang._('Broadcast') }}'
tr['mtu_mismatch_detection'] = '{{ lang._('MTU Mismatch Detection') }}'
tr['address'] = '{{ lang._('Address') }}'
tr['designated_router'] = '{{ lang._('Designated Router') }}'
tr['designated_router_interface_address'] = '{{ lang._('Designated Router Interface Address') }}'
tr['backup_designated_router'] = '{{ lang._('Backup Designated Router') }}'
tr['multicast_group_memberships'] = '{{ lang._('Multicast Group Memberships') }}'
tr['intervals'] = '{{ lang._('Intervals') }}'
tr['hello_due_in'] = '{{ lang._('Hello Due In') }}'
tr['neighbor_count'] = '{{ lang._('Neighbor Count') }}'
tr['adjacent_neighbor_count'] = '{{ lang._('Adjacent Neighbor Count') }}'
return _.has(tr,data) ? tr[data] : data
}
function checkmark(bin)
{
return "<i class=\"fa " + (bin ? "fa-check-square" : "fa-square") + " text-muted\"></i>";
}
dataconverters = {
boolean: {
from: function (value) { return (value == 'true') || (value == true); },
to: function (value) { return checkmark(value) }
},
raw: {
from: function (value) { return value },
to: function (value) { return value }
}
}
$(document).ready(function() {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status'])
});
ajaxCall(url="/api/quagga/diagnostics/ospfoverview", sendData={}, callback=function(data,status) {
content = _.template($('#overviewtpl').html())(data['response'])
$('#overview').html(content)
});
ajaxCall(url="/api/quagga/diagnostics/ospfdatabase", sendData={}, callback=function(data,status) {
content = _.template($('#databasetpl').html())(data['response'])
$('#database').html(content)
$('#database table').bootgrid()
});
ajaxCall(url="/api/quagga/diagnostics/ospfroute", sendData={}, callback=function(data,status) {
content = _.template($('#routestpl').html())(data['response'])
$('#routing').html(content)
$('#routing table').bootgrid({converters: dataconverters})
});
ajaxCall(url="/api/quagga/diagnostics/ospfneighbor", sendData={}, callback=function(data,status) {
content = _.template($('#neighbortpl').html())(data['response'])
$('#neighbor').html(content)
$('#neighbor table').bootgrid()
});
ajaxCall(url="/api/quagga/diagnostics/ospfinterface", sendData={}, callback=function(data,status) {
content = _.template($('#interfacetpl').html())(data['response'])
$('#interface').html(content)
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#overview">{{ lang._('Overview') }}</a></li>
<li><a data-toggle="tab" href="#routing">{{ lang._('Routing Table') }}</a></li>
<li><a data-toggle="tab" href="#database">{{ lang._('Database') }}</a></li>
<li><a data-toggle="tab" href="#neighbor">{{ lang._('Neighbor') }}</a></li>
<li><a data-toggle="tab" href="#interface">{{ lang._('Interface') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="overview" class="tab-pane fade in active">
</div>
<div id="routing" class="tab-pane fade in">
</div>
<div id="database" class="tab-pane fade in">
</div>
<div id="neighbor" class="tab-pane fade in">
</div>
<div id="interface" class="tab-pane fade in">
</div>
</div>

View file

@ -0,0 +1,384 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
Copyright (C) 2017 Fabian Franz
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.
#}
<script type="text/x-template" id="overviewtpl">
<h2>{{ lang._('General') }}</h2>
<table class="table table-striped">
<tbody>
<tr>
<td>{{ lang._('Router ID') }}</td>
<td><%= ospfv3_overview['router_id'] %></td>
</tr>
<tr>
<td>{{ lang._('Routing Process') }}</td>
<td><%= ospfv3_overview['routing_process'] %></td>
</tr>
<tr>
<td>{{ lang._('Running Time') }}</td>
<td><%= ospfv3_overview['running_time'] %></td>
</tr>
<tr>
<td>{{ lang._('Initial SPF scheduling delay') }}</td>
<td><%= ospfv3_overview['intital_spf_scheduling_delay'] %></td>
</tr>
<tr>
<td>{{ lang._('Hold Time') }}</td>
<td>
{{ lang._('Minimum Hold Time') }} <%= ospfv3_overview['hold_time']['min'] %><br/>
{{ lang._('Maximum Hold Time:') }} <%= ospfv3_overview['hold_time']['max'] %>
</td>
</tr>
<tr>
<td>{{ lang._('SPF timer') }}</td>
<td><%= ospfv3_overview['spf_timer'] %></td>
</tr>
<tr>
<td>{{ lang._('Number Of Scoped AS') }}</td>
<td><%= ospfv3_overview['number_as_scoped'] %></td>
</tr>
<tr>
<td>{{ lang._('Number Of Areas') }}</td>
<td><%= ospfv3_overview['number_of_areas'] %></td>
</tr>
</tbody>
</table>
<h2>{{ lang._('Areas') }}</h2>
<% if (ospfv3_overview['areas']) { %>
<% areas = ospfv3_overview['areas'] %>
<% _.each(_.keys(areas), function(areaname) { %>
<% area = areas[areaname] %>
<h3><%= areaname %></h3>
<table class="table table-striped">
<tbody>
<tr>
<td>{{ lang._('Number Of LSAs') }}</td>
<td><%= area['number_lsas'] %></td>
</tr>
<tr>
<td>{{ lang._('Interfaces') }}</td>
<td><%= _.join(area['interfaces'], ", ") %></td>
</tr>
</tbody>
</table>
<% }) %>
<% } %>
</script>
<script type="text/x-template" id="routestpl">
<table>
<thead>
<tr>
<th data-column-id="flags1" data-type="string">{{ lang._('Flags 1') }}</th>
<th data-column-id="flags2" data-type="string">{{ lang._('Flags 2') }}</th>
<th data-column-id="network" data-type="string">{{ lang._('Network') }}</th>
<th data-column-id="gateway" data-type="string">{{ lang._('Gateway') }}</th>
<th data-column-id="interface" data-type="string">{{ lang._('Interface') }}</th>
<th data-column-id="time" data-type="string">{{ lang._('Time') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospfv3_route, function (route) { %>
<tr>
<td><%= route['f1'] %></td>
<td><%= route['f2'] %></td>
<td><%= route['network'] %></td>
<td><%= route['gateway'] %></td>
<td><%= route['interface'] %></td>
<td><%= route['time'] %></td>
</tr>
<% }) %>
</tbody>
</table>
</script>
<script type="text/x-template" id="databasetpl">
<% if(ospfv3_database['scoped_link_db']) { %>
<h2>{{ lang._('Scoped Link Database') }}</h2>
<% _.each(_.keys(ospfv3_database['scoped_link_db']), function(areaname) { %>
<% area = ospfv3_database['scoped_link_db'][areaname] %>
<h3><% areaname %></h3>
<table>
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="lsid" data-type="string">{{ lang._('LS ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('Advertising Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="numeric">{{ lang._('Sequence Number') }}</th>
<th data-column-id="payload" data-type="string">{{ lang._('Payload') }}</th>
</tr>
</thead>
<tbody>
<% _.each(area, function(entry) { %>
<tr>
<td><%= entry['Type'] %></td>
<td><%= entry['LSId'] %></td>
<td><%= entry['AdvRouter'] %></td>
<td><%= entry['Age'] %></td>
<td><%= entry['SeqNum'] %></td>
<td><%= entry['Payload'] %></td>
</tr>
<% }) %>
</tbody>
</table>
<% }) %>
<% } %>
<% if(ospfv3_database['if_scoped_link_state']) { %>
<h2>{{ lang._('Interface Scoped Link Database') }}</h2>
<% _.each(_.keys(ospfv3_database['if_scoped_link_state']), function(intfname) { %>
<% intf = ospfv3_database['if_scoped_link_state'][intfname] %>
<% _.each(_.keys(intf), function(areaname) { %>
<% area = intf[areaname] %>
<h3><%= intfname %> / <%= areaname %></h3>
<table>
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="lsid" data-type="string">{{ lang._('LS ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('Advertising Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="numeric">{{ lang._('Sequence Number') }}</th>
<th data-column-id="payload" data-type="string">{{ lang._('Payload') }}</th>
</tr>
</thead>
<tbody>
<% _.each(area, function(entry) { %>
<tr>
<td><%= entry['Type'] %></td>
<td><%= entry['LSId'] %></td>
<td><%= entry['AdvRouter'] %></td>
<td><%= entry['Age'] %></td>
<td><%= entry['SeqNum'] %></td>
<td><%= entry['Payload'] %></td>
</tr>
<% }) %>
</tbody>
</table>
<% }) %>
<% }) %>
<% } %>
<% if (ospfv3_database['as_scoped']) { %>
<h2>{{ lang._('AS Scoped') }}</h2>
<table>
<thead>
<tr>
<th data-column-id="type" data-type="string">{{ lang._('Type') }}</th>
<th data-column-id="lsid" data-type="string">{{ lang._('LS ID') }}</th>
<th data-column-id="advrouter" data-type="string">{{ lang._('Advertising Router') }}</th>
<th data-column-id="age" data-type="numeric">{{ lang._('Age') }}</th>
<th data-column-id="seqnr" data-type="numeric">{{ lang._('Sequence Number') }}</th>
<th data-column-id="payload" data-type="string">{{ lang._('Payload') }}</th>
</tr>
</thead>
<tbody>
<% _.each(ospfv3_database['as_scoped'], function(entry) { %>
<tr>
<td><%= entry['Type'] %></td>
<td><%= entry['LSId'] %></td>
<td><%= entry['AdvRouter'] %></td>
<td><%= entry['Age'] %></td>
<td><%= entry['SeqNum'] %></td>
<td><%= entry['Payload'] %></td>
</tr>
<% }) %>
</tbody>
</table>
<% } %>
</script>
<script type="text/x-template" id="interfacetpl">
<% _.each(_.keys(ospfv3_interface), function(interfacename) { %>
<% int = ospfv3_interface[interfacename] %>
<h2><%= interfacename %></h2>
<table class="table table-striped">
<tbody>
<% _.each(_.keys(int), function(propertyname) { %>
<% if (propertyname != 'pending_lsas' ) { %>
<tr>
<td><%= translate(propertyname) %></td>
<td>
<% if (int[propertyname] === false || int[propertyname] === true) { %>
<%= checkmark(int[propertyname]) %>
<% } else if (propertyname == 'timers') { %>
{{ lang._('Hello Timer:') }} <%= int[propertyname]['hello'] %><br />
{{ lang._('Dead Timer:') }} <%= int[propertyname]['dead'] %><br />
{{ lang._('Wait Timer:') }} <%= int[propertyname]['wait'] %><br />
{{ lang._('Retransmit Timer:') }} <%= int[propertyname]['retransmit'] %>
<% } else if (propertyname == 'IPv6' || propertyname == 'IPv4') { %>
<%= _.join(int[propertyname],'<br />') %><br />
<% } else if (propertyname == 'area_cost') { %>
<% _.each(int[propertyname], function (ac) { %>
<%= ac['area'] %>: <%= ac['cost'] %><br />
<% }) %>
<% } else { %>
<%= translate(int[propertyname]) %>
<% } %>
</td>
</tr>
<% } else { %>
<% _.each(_.keys(int[propertyname]), function(lsa) { %>
<% mylsa = int[propertyname][lsa] %>
<tr>
<td><%= lsa %> {{ lang._('Time') }}</td>
<td><%= mylsa['time'] %> </td>
</tr>
<tr>
<td><%= lsa %> {{ lang._('Count') }}</td>
<td><%= mylsa['Count'] %> </td>
</tr>
<tr>
<td><%= lsa %> {{ lang._('Flags') }}</td>
<td><%= mylsa['flags'] %> </td>
</tr>
<% }) %>
<% } %>
<% }); %>
</tbody>
</table>
<% }) %>
</script>
<script type="text/javascript" src="/ui/js/quagga/lodash.js"></script>
<script>
function translate(data)
{
tr = []
tr['count'] = '{{ lang._('Count') }}'
tr['router'] = '{{ lang._('Router') }}'
tr['network'] = '{{ lang._('Network') }}'
tr['summary'] = '{{ lang._('Summary') }}'
tr['ASBR summary'] = '{{ lang._('ASBR summary') }}'
tr['NSSA'] = '{{ lang._('NSSA') }}'
tr['directly attached'] = '{{ lang._('Directly Attached') }}'
tr['Full/DR'] = '{{ lang._('Full (Designated Router)') }}'
tr['enabled'] = '{{ lang._('Enabled') }}'
tr['cost'] = '{{ lang._('Cost') }}'
tr['priority'] = '{{ lang._('Priority') }}'
tr['router_id'] = '{{ lang._('Router ID') }}'
tr['network_type'] = '{{ lang._('Network Type') }}'
tr['area'] = '{{ lang._('Area') }}'
tr['transmit_delay'] = '{{ lang._('Transmit Delay') }}'
tr['state'] = '{{ lang._('State') }}'
tr['broadcast'] = '{{ lang._('Broadcast') }}'
tr['mtu_mismatch_detection'] = '{{ lang._('MTU Mismatch Detection') }}'
tr['address'] = '{{ lang._('Address') }}'
tr['designated_router'] = '{{ lang._('Designated Router') }}'
tr['designated_router_interface_address'] = '{{ lang._('Designated Router Interface Address') }}'
tr['backup_designated_router'] = '{{ lang._('Backup Designated Router') }}'
tr['multicast_group_memberships'] = '{{ lang._('Multicast Group Memberships') }}'
tr['intervals'] = '{{ lang._('Intervals') }}'
tr['hello_due_in'] = '{{ lang._('Hello Due In') }}'
tr['neighbor_count'] = '{{ lang._('Neighbor Count') }}'
tr['adjacent_neighbor_count'] = '{{ lang._('Adjacent Neighbor Count') }}'
tr['timers'] = '{{ lang._('Timers') }}'
tr['number_if_scoped_lsas'] = '{{ lang._('Number Of Interface Scoped LSAs') }}'
tr['pending_lsas'] = '{{ lang._('Pending LSAs') }}'
tr['area_cost'] = '{{ lang._('Area Cost') }}'
tr['instance_id'] = '{{ lang._('Instance ID') }}'
tr['interface_mtu'] = '{{ lang._('Interface MTU') }}'
tr['type'] = '{{ lang._('Type') }}'
tr['id'] = '{{ lang._('ID') }}'
tr['up'] = '{{ lang._('Up') }}'
tr['DR'] = '{{ lang._('Designated Router') }}'
tr['BDR'] = '{{ lang._('Backup Designated Router') }}'
tr['BROADCAST'] = '{{ lang._('Broadcast') }}'
tr['UNKNOWN'] = '{{ lang._('Unknown') }}'
tr['POINTOPOINT'] = '{{ lang._('Point to Point') }}'
tr['LOOPBACK'] = '{{ lang._('Loopback') }}'
return _.has(tr,data) ? tr[data] : data
}
function checkmark(bin)
{
return "<i class=\"fa " + (bin ? "fa-check-square" : "fa-square") + " text-muted\"></i>";
}
dataconverters = {
boolean: {
from: function (value) { return (value == 'true') || (value == true); },
to: function (value) { return checkmark(value) }
},
raw: {
from: function (value) { return value },
to: function (value) { return value }
}
}
$(document).ready(function() {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status'])
});
ajaxCall(url="/api/quagga/diagnostics/ospfv3overview", sendData={}, callback=function(data,status) {
content = _.template($('#overviewtpl').html())(data['response'])
$('#overview').html(content)
});
ajaxCall(url="/api/quagga/diagnostics/ospfv3database", sendData={}, callback=function(data,status) {
content = _.template($('#databasetpl').html())(data['response'])
$('#database').html(content)
$('#database table').bootgrid()
});
ajaxCall(url="/api/quagga/diagnostics/ospfv3route", sendData={}, callback=function(data,status) {
content = _.template($('#routestpl').html())(data['response'])
$('#routing').html(content)
$('#routing table').bootgrid()
});
/*ajaxCall(url="/api/quagga/diagnostics/ospfv3neighbor", sendData={}, callback=function(data,status) {
content = _.template($('#neighbortpl').html())(data['response'])
$('#neighbor').html(content)
});*/
ajaxCall(url="/api/quagga/diagnostics/ospfv3interface", sendData={}, callback=function(data,status) {
content = _.template($('#interfacetpl').html())(data['response'])
$('#interface').html(content)
});
});
</script>
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#overview">{{ lang._('Overview') }}</a></li>
<li><a data-toggle="tab" href="#routing">{{ lang._('Routing Table') }}</a></li>
<li><a data-toggle="tab" href="#database">{{ lang._('Database') }}</a></li>
<!--<li><a data-toggle="tab" href="#neighbor">{{ lang._('Neighbor') }}</a></li>-->
<li><a data-toggle="tab" href="#interface">{{ lang._('Interface') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="overview" class="tab-pane fade in active">
</div>
<div id="routing" class="tab-pane fade in">
</div>
<div id="database" class="tab-pane fade in">
</div>
<div id="neighbor" class="tab-pane fade in">
</div>
<div id="interface" class="tab-pane fade in">
</div>
</div>

View file

@ -0,0 +1,59 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
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.
#}
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_general_settings'])}}
<hr />
<div class="col-md-12">
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
</div>
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_general_settings':"/api/quagga/general/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/general/set", formid='frm_general_settings',callback_ok=function(){
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
});
</script>

View file

@ -0,0 +1 @@
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}

View file

@ -0,0 +1,23 @@
<div class="content-box">
<table id="logtable" class="table table-condensed table-hover table-striped" style="table-layout: initial;">
<thead>
<tr>
<th data-column-id="date" data-sortable="false" data-type="string">{{ lang._('Date') }}</th>
<th data-column-id="time" data-sortable="false" data-type="string">{{ lang._('Time') }}</th>
<th data-column-id="service" data-sortable="false" data-type="string">{{ lang._('Service') }}</th>
<th data-column-id="message" data-sortable="false" data-type="string">{{ lang._('Message') }}</th>
</tr>
</thead>
</table>
</div>
<script>
$("#logtable").bootgrid({
ajax: true,
navigation: 0,
url: "/api/quagga/diagnostics/log",
ajaxSettings: { "method": "GET", cache: true },
responseHandler: function(resp) { return {"rows": resp}; },
sortable: false
});
</script>

View file

@ -0,0 +1,187 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
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.
#}
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#networks">{{ lang._('Networks') }}</a></li>
<li><a data-toggle="tab" href="#interfaces">{{ lang._('Interfaces') }}</a></li>
<li><a data-toggle="tab" href="#prefixlists">{{ lang._('Prefix Lists') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':generalForm,'id':'frm_ospf_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
</div>
</div>
<!-- Tab: Networks -->
<div id="networks" class="tab-pane fade in">
<table id="grid-networks" class="table table-responsive" data-editDialog="DialogEditNetwork">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="ipaddr" data-type="string" data-visible="true">{{ lang._('Network Address') }}</th>
<th data-column-id="netmask" data-type="string" data-visible="true">{{ lang._('Mask') }}</th>
<th data-column-id="area" data-type="string" data-visible="true">{{ lang._('Area') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
<!-- Tab: Interfaces -->
<div id="interfaces" class="tab-pane fade in">
<table id="grid-interfaces" class="table table-responsive" data-editDialog="DialogEditInterface">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="interfacename" data-type="string" data-visible="true">{{ lang._('Interface Name') }}</th>
<th data-column-id="networktype" data-type="string" data-visible="true">{{ lang._('Network Type') }}</th>
<th data-column-id="authtype" data-type="string" data-visible="true">{{ lang._('Authentication Type') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
<div id="prefixlists" class="tab-pane fade in">
<table id="grid-prefixlists" class="table table-responsive" data-editDialog="DialogEditPrefixLists">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle" data-sortable="false">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string" data-visible="true" data-sortable="true">{{ lang._('Name') }}</th>
<th data-column-id="seqnumber" data-type="string" data-visible="true" data-sortable="true">{{ lang._('Secquence Number') }}</th>
<th data-column-id="action" data-type="string" data-visible="true" data-sortable="false">{{ lang._('Action') }}</th>
<th data-column-id="network" data-type="string" data-visible="true" data-sortable="false">{{ lang._('Network') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_ospf_settings':"/api/quagga/ospfsettings/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/ospfsettings/set",formid='frm_ospf_settings',callback_ok=function(){
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
$("#grid-networks").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchNetwork',
'get':'/api/quagga/ospfsettings/getNetwork/',
'set':'/api/quagga/ospfsettings/setNetwork/',
'add':'/api/quagga/ospfsettings/addNetwork/',
'del':'/api/quagga/ospfsettings/delNetwork/',
'toggle':'/api/quagga/ospfsettings/toggleNetwork/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-interfaces").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchInterface',
'get':'/api/quagga/ospfsettings/getInterface/',
'set':'/api/quagga/ospfsettings/setInterface/',
'add':'/api/quagga/ospfsettings/addInterface/',
'del':'/api/quagga/ospfsettings/delInterface/',
'toggle':'/api/quagga/ospfsettings/toggleInterface/',
'options':{selection:false, multiSelect:false}
}
);
$("#grid-prefixlists").UIBootgrid(
{ 'search':'/api/quagga/ospfsettings/searchPrefixlist',
'get':'/api/quagga/ospfsettings/getPrefixlist/',
'set':'/api/quagga/ospfsettings/setPrefixlist/',
'add':'/api/quagga/ospfsettings/addPrefixlist/',
'del':'/api/quagga/ospfsettings/delPrefixlist/',
'toggle':'/api/quagga/ospfsettings/togglePrefixlist/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditNetwork,'id':'DialogEditNetwork','label':lang._('Edit Network')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditInterface,'id':'DialogEditInterface','label':lang._('Edit Interface')])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditPrefixLists,'id':'DialogEditPrefixLists','label':lang._('Edit Prefix Lists')])}}

View file

@ -0,0 +1,113 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
This file is Copyright © 2017 by Michael Muenz
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.
#}
<!-- Navigation bar -->
<ul class="nav nav-tabs" data-tabs="tabs" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General') }}</a></li>
<li><a data-toggle="tab" href="#interfaces">{{ lang._('Interfaces') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':ospf6Form,'id':'frm_ospf6_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
</div>
</div>
<!-- Tab: Interfaces -->
<div id="interfaces" class="tab-pane fade in">
<table id="grid-interfaces" class="table table-responsive" data-editDialog="DialogEditInterface">
<thead>
<tr>
<th data-column-id="enabled" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="interfacename" data-type="string" data-visible="true">{{ lang._('Interface Name') }}</th>
<th data-column-id="area" data-type="string" data-visible="true">{{ lang._('Area') }}</th>
<th data-column-id="networktype" data-type="string" data-visible="true">{{ lang._('Network Type') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-formatter="commands" data-sortable="false">{{ lang._('Commands') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td colspan="5"></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<!-- <button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button> -->
</td>
</tr>
</tfoot>
</table>
</div>
</div>
<script type="text/javascript">
$( document ).ready(function() {
var data_get_map = {'frm_ospf6_settings':"/api/quagga/ospf6settings/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/ospf6settings/set",formid='frm_ospf6_settings',callback_ok=function(){
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
$("#grid-interfaces").UIBootgrid(
{ 'search':'/api/quagga/ospf6settings/searchInterface',
'get':'/api/quagga/ospf6settings/getInterface/',
'set':'/api/quagga/ospf6settings/setInterface/',
'add':'/api/quagga/ospf6settings/addInterface/',
'del':'/api/quagga/ospf6settings/delInterface/',
'toggle':'/api/quagga/ospf6settings/toggleInterface/',
'options':{selection:false, multiSelect:false}
}
);
});
</script>
{{ partial("layout_partials/base_dialog",['fields':formDialogEditInterface,'id':'DialogEditInterface','label':lang._('Edit Interface')])}}

View file

@ -0,0 +1,62 @@
{#
OPNsense® is Copyright © 2014 2017 by Deciso B.V.
This file is Copyright © 2017 by Fabian Franz
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.
#}
<div class="content-box" style="padding-bottom: 1.5em;">
{{ partial("layout_partials/base_form",['fields':ripForm,'id':'frm_rip_settings'])}}
<div class="col-md-12">
<hr />
<button class="btn btn-primary" id="saveAct" type="button"><b>{{ lang._('Save') }}</b></button>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
var data_get_map = {'frm_rip_settings':"/api/quagga/rip/get"};
mapDataToFormUI(data_get_map).done(function(data){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
});
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
// link save button to API set action
$("#saveAct").click(function(){
saveFormToEndpoint(url="/api/quagga/rip/set",formid='frm_rip_settings',callback_ok=function(){
ajaxCall(url="/api/quagga/service/reconfigure", sendData={}, callback=function(data,status) {
ajaxCall(url="/api/quagga/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
});
</script>

View file

@ -0,0 +1,20 @@
#!/bin/sh
case "$1" in
bgp)
vtysh -d bgpd -c "show ip bgp"
;;
summary)
vtysh -d bgpd -c "show ip bgp summary"
;;
neighbor)
vtysh -d bgpd -c "show ip bgp neighbors $2"
;;
neighbor-adv)
vtysh -d bgpd -c "show ip bgp neighbors $2 advertised-routes"
;;
*)
echo "Usage: $0 bgp|summary|neighbor <ip>|neighbor-adv <ip>"
exit 1
esac
exit 0

View file

@ -0,0 +1,757 @@
#!/usr/local/bin/ruby
=begin
Copyright 2017 Fabian Franz
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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
=end
require 'json'
require 'shellwords'
require 'pp'
$QUAGGA_DEBUG = false
class VTYSH
def initialize(path = '/usr/local/bin/vtysh')
@path = path
end
def execute(param)
o = `#{@path} -c #{param.shellescape}`
raise "error" if o.length <= 2
raise "command error - command: #{param}" if o.include? "% Unknown command"
o
end
#def execute(param)
# fn = param.sub("show","sh").gsub(" ","_")
# File.read(fn)
#end
end
class QuaggaTableReader
attr_accessor :headers
def initialize(headers = [])
@headers = headers
end
def read_headline(line, start_without_header = false, start_without_header_name = 'status')
# get begin of header (number of the first char of the string)
header = line
header_offset = {}
header_offset[0] = start_without_header_name if start_without_header
@headers.map do |x|
header_offset[header.index(x)] = x.strip
end
# make ranges: this will make a range of the first char of the sting until
# the the char befor the next heading begins
ranges = []
0.upto (header_offset.keys.length - 2) do |i|
ranges << ((header_offset.keys[i])...(header_offset.keys[i + 1]))
end
# the last one has no next heading - this will go to the end of the line
ranges.push ((header_offset.keys.last)..-1) # path
@header_offset = header_offset
@ranges = ranges
nil
end
def read_entry(line, expand_fields = {})
raise "heading missing" unless @ranges
tmp = {}
return tmp unless line&.strip.length > 2
@ranges.each do |r|
# the string starts here
b = r.begin
# get the heading starting where the string starts
n = @header_offset[b]
# get the data or return an empty string
tmp[n] = line[r]&.strip || ""
end
# replace characters by the meaning
expand_fields.keys.each do |key|
tmp[key] = tmp[key].split("").map {|x| {dn: expand_fields[key][x], abb: x} } if tmp[key]
end
tmp
end
end
class General
def initialize(vtysh)
@vtysh = vtysh
end
def routes(ipv6 = false)
lines = @vtysh.execute("show ip#{ipv6 ? 'v6' : ''} route").lines
# headers
meanings = {}
while (line = lines.shift.strip) != ''
line = line.gsub('Codes: ','')
line.split(",").each do |meaning|
short, long = meaning.strip.split(" - ")
meanings[short] = long
end
end
# you don't have to understand this regex ;)
entry_regex = /(\S+?)\s+?(\S+?)(?: \[(\d+)\/(\d+)\])? (?:via (\S+?)|is ([^,]+?)), ([^,\n]+)(?:, (\S+))?/
entries = []
while (line = lines.shift&.strip)
if line.length > 10
code, network, ad, metric, via, direct, interface, time = line.scan(entry_regex).first
code = code.split('').map {|c| {short: c, long: meanings[c]}}
entries << {code: code, network: (network || direct), ad: ad, via: via, metric: metric, interface: interface, time: time }
end
end
entries
end
def routes6
routes(true)
end
def log
File.read('/var/log/frr.log').lines.select {|l| l.strip.length > 10}.map do |line|
date, time, service, message = line.split(' ', 4)
date = date.split('/').reverse.join(".") # format dd.mm.yyyy
service = service.split(':').first if service
{date: date, time:time, service: service, message: message }
end
end
end
class OSPF
def initialize(vtysh)
@vtysh = vtysh
end
def neighbors
qta = QuaggaTableReader.new(["Neighbor ID", "Pri", "State", "Dead Time", "Address", "Interface", "RXmtL", "RqstL", "DBsmL"])
lines = @vtysh.execute("show ip ospf neighbor").lines
lines.shift # empty line
data = []
qta.read_headline(lines.shift)
while (line = lines.shift) && (line.length > 2)
data << qta.read_entry(line)
end
data
end
def interface
lines = @vtysh.execute("show ip ospf interface").lines
interfaces = {}
current_if = ''
while line = lines.shift
next if line.strip.length <= 1
if line[0] != ' ' # we are in a heading
current_if = line.split(" ").first
interfaces[current_if] = {}
current_if = interfaces[current_if]
current_if[:enabled] = true
lines.shift
else
line.strip!
case line
when 'OSPF not enabled on this interface'
current_if[:enabled] = false
when /Internet Address ([^,]+?), Broadcast ([^,]+?), Area (.*)/
current_if[:address] = $1
current_if[:broadcast] = $2
current_if[:area] = $3
when /MTU mismatch detection:(.*)/
current_if[:mtu_mismatch_detection] = ($1 == 'enabled')
when /Router ID ([^,]+?), Network Type ([^,]+?), Cost: (\d+)/
current_if[:router_id] = $1
current_if[:network_type] = $2
current_if[:cost] = $3.to_i
when /Transmit Delay is (\d+) sec, State ([^,]+?), Priority (\d+)/
current_if[:transmit_delay] = $1.to_i
current_if[:state] = $2
current_if[:priority] = $3.to_i
when "No designated router on this network"
current_if[:designated_router] = nil
when /Designated Router \(ID\) ([^,]+?), Interface Address (.*)/
current_if[:designated_router] = $1
current_if[:designated_router_interface_address] = $2
when "No backup designated router on this network"
current_if[:backup_designated_router] = nil
when /Timer intervals configured, Hello (\d+)s, Dead (\d+)s, Wait (\d+)s, Retransmit (\d+)/
current_if[:intervals] = {hello: $1.to_i, dead: $2.to_i, wait: $3.to_i, retransmit: $4.to_i}
when /Multicast group memberships: (.*)/
current_if[:multicast_group_memberships] = $1.split(" ")
when /Hello due in ([\d\.]+|inactive)s?/
current_if[:hello_due_in] = $1 == 'inactive' ? $1 : $1.to_f
when /Neighbor Count is (\d+), Adjacent neighbor count is (\d+)/
current_if[:neighbor_count] = $1.to_i
current_if[:adjacent_neighbor_count] = $2.to_i
else
# make sure there is an array to write in
current_if[:unparsed] ||= []
current_if[:unparsed] << line
puts line if $QUAGGA_DEBUG
end
end
end
interfaces
end
def database
lines = @vtysh.execute("show ip ospf database").lines
db = {}
heading = ''
router = ''
router_link_states_area = ''
mode = :none
qta = nil
while line = lines.shift
next if line == ''
if line[0] == ' ' # heading
heading = line.strip
case heading
when /OSPF Router with ID \(([\.\d]+)\)/
router = $1
db[router] ||= {}
mode = :router
when /Router Link States \(Area ([\.\d]+)\)/
router_link_states_area = $1
db[router]['router_link_state_area'] ||= {}
db[router]['router_link_state_area'][$1] ||= []
mode = :router_link_state
qta = nil
when /Net Link States \(Area ([\.\d]+)\)/
net_link_states_area = $1
db[router]['net_link_state_area'] ||= {}
db[router]['net_link_state_area'][$1] ||= []
mode = :net_link_state
qta = nil
when 'AS External Link States'
mode = :states
db[router]['external_states'] ||= []
qta = nil
else
puts "unknown heading" if $QUAGGA_DEBUG
end
else
if qta == nil
case mode
when :router_link_state
qta = QuaggaTableReader.new(["Link ID", "ADV Router", "Age", "Seq#", "CkSum", "Link count"])
when :net_link_state
qta = QuaggaTableReader.new(["Link ID", "ADV Router", "Age", "Seq#", "CkSum"])
when :states
qta = QuaggaTableReader.new(["Link ID", "ADV Router", "Age", "Seq#", "CkSum", "Route\n"])
else
next
end
headline = lines.shift
qta.read_headline(headline,true)
else
entry = qta.read_entry(line)
case mode
when :router_link_state
db[router]['router_link_state_area'][router_link_states_area] << entry
when :net_link_state
db[router]['net_link_state_area'][net_link_states_area] << entry
when :states
db[router]['external_states'] << entry
end
end
end
# table
end
db
end
def route
lines = @vtysh.execute("show ip ospf route").lines
heading = ''
route = {}
last_line = []
while line = lines.shift
if line[0] == "=" #heading
heading = line.scan(/=* ([^=]*) =*/).first.first
route[heading] = []
else # data
case line.strip
when /N\s+([\d\.\/]+)\s+\[(\d+)\]\s+area:\s(.*)/
last_line = {network: $1, cost: $2.to_i, area: $3, type: 'N'}
route[heading] << last_line
when /N (E(?:\d+) (?:\S+))\s+\[([\d\/]+)\] tag: (\d+)/
last_line = {network: $1, cost: $2, tag: $3.to_i, type: 'N'}
route[heading] << last_line
when /(?:(directly attached) to|via ([^,]+),) (.*)/
last_line[:via] = $1 || $2
last_line[:via_interface] = $3
when /R\s+(\S+)\s+\[(\d+)\] area: ([^,]+)(, ASBR)/
last_line = {ip: $1, cost: $2.to_i, area: $3, asbr: (", ASBR" == $4), type: 'R'}
route[heading] << last_line
else
puts line if $QUAGGA_DEBUG
end
end
end
route
end
def overview
lines = @vtysh.execute("show ip ospf").lines
overview = {rfc2328_conform: false, asbr: false}
while line = lines.shift&.strip
case line
when /OSPF Routing Process, Router ID: ([\d\.]+)/
overview[:router_id] = $1
when "This implementation conforms to RFC2328"
overview[:rfc2328_conform] = true
when /OpaqueCapability flag is (\S+)/
overview[:opaque_capability] = ($1 == 'enabled')
when /Initial SPF scheduling delay (\d+) millisec\(s\)/
overview[:initial_spf_scheduling_delay] = $1.to_i
when /(Min|Max)imum hold time between consecutive SPFs (\d+) millisec\(s\)/
overview[:hold_time] ||= {}
overview[:hold_time][$1.downcase] = $2.to_i
when "This router is an ASBR (injecting external routing information)"
overview[:asbr] = true
when /Number of external LSA (\d+). Checksum Sum ([x\d]+)/
overview[:external_lsa] = {count: $1.to_i, checksum: $2}
when /Number of opaque AS LSA (\d+). Checksum Sum ([x\d]+)/
overview[:opaque_as_lsa] = {count: $1.to_i, checksum: $2}
when /Refresh timer (\d+) secs/
overview[:refresh_timer] = $1.to_i
when /Number of areas attached to this router: (\d+)/
overview[:areas_attached_count] = $1.to_i
when /Hold time multiplier is currently (\d+)/
overview[:current_hold_time_multipier] = $1.to_i
when /RFC1583Compatibility flag is (\S+)/
overview[:rfc1583_compatibility] = ($1 == 'enabled')
when /SPF timer is (.*)/
overview[:spf_timer] = $1
when ""
break
else
puts line if $QUAGGA_DEBUG
end
end
# general overview has ended - now the area overviews come
overview[:areas] = {}
current_area = {}
while line = lines.shift&.strip
case line
when /Area ID: (.*)/
current_area = {}
overview[:areas][$1] = current_area
when /Number of interfaces in this area: Total: (\d+), Active: (\d+)/
current_area[:interfaces] = {total: $1.to_i,active: $2.to_i}
when /Number of (router|network|summary) LSA (\d+). Checksum Sum ([\da-fx]+)/
current_area[:lsa] ||= {}
current_area[:lsa][$1] = {count: $2.to_i, checksum: $3}
when /Number of LSA (\d+)/
current_area[:lsa] ||= {}
current_area[:lsa][:count] = $1.to_i
when /Number of (opaque (?:area|link)|NSSA|ASBR summary) LSA (\d+). Checksum Sum ([\da-fx]+)/
current_area[:lsa] ||= {}
current_area[:lsa][$1] = {count: $2.to_i, checksum: $3}
when /Number of fully adjacent neighbors in this area: (\d+)/
current_area[:fully_adjacent_neighbor_count] = $1.to_i
when /SPF algorithm executed (\d) times/
current_area[:spf_exec_count] = $1.to_i
when "Area has no authentication"
current_area[:auth] = "none"
else
puts line if $QUAGGA_DEBUG
end
end
overview
end
end
class BGP
def initialize(sh)
@vtysh = sh
end
def overview
output = @vtysh.execute('show ip bgp')
return {} if output.include? "No BGP process is configured"
return {} unless output.include? 'version' # we get an empty output if quagga is not running
output = output.split("\n")
bgp = {}
x,y = output.shift.scan(/.*?version is (\d+).*?ID is ([0-9\.]+).*/).first
bgp['table_version'] = x
bgp['local_router_id'] = y
# find out, what the status abbreviations mean
status_codes = {}
line = output.shift
line.split(":").last.strip.split(",").each do |x|
k,v = x.strip.split(" ")
status_codes[k] = v
end
while line.end_with? ","
line = output.shift
line.strip.split(",").each do |x|
k,v = x.strip.split(" ")
status_codes[k] = v
end
end
# same like before but for the origin codes
origin_codes = {}
output.shift.split(":").last.strip.split(",").each do |x|
k,v = x.strip.split(" - ")
origin_codes[k] = v
end
# drop empty line
output.shift
# read entries
bgp['output'] = []
qta = QuaggaTableReader.new(["Network", "Next Hop", "Metric", "LocPrf", "Weight", "Path"])
qta.read_headline(output.shift,true)
while line = output.shift&.strip
break if line == ''
data = qta.read_entry(line)
data['status'] = data['status'].split("").map {|x| {dn: status_codes[x], abb: x} }
data['Path'] = data['Path'].split("").map {|x| {dn: origin_codes[x], abb: x} }
bgp['output'] << data
end
bgp
end
end
class OSPFv3
def initialize(sh)
@vtysh = sh
end
def overview
lines = @vtysh.execute("show ipv6 ospf6").lines
overview = {}
while line = lines.shift&.strip
case line
when /OSPFv3 Routing Process \((\d+)\) with Router-ID ([\d\.]+)/
overview[:router_id] = $2
overview[:routing_process] = $1.to_i
when /Initial SPF scheduling delay (\d+) millisec\(s\)/
overview[:initial_spf_scheduling_delay] = $1.to_i
# this line contains a typo in the output - I made it to work with and without
# this typo
when /(Min|Max)imum hold time between consecutive SPFs (\d+) milli?second\(s\)/
overview[:hold_time] ||= {}
overview[:hold_time][$1.downcase] = $2.to_i
when "This router is an ASBR (injecting external routing information)"
overview[:asbr] = true
when /SPF timer is (.*)/
overview[:spf_timer] = $1
when /Running (.*)/
overview[:running_time] = $1
when /Number of AS scoped LSAs is (\d+)/
overview[:number_as_scoped] = $1.to_i
when /Hold time multiplier is currently (\d+)/
overview[:current_hold_time_multipier] = $1.to_i
when /Number of areas in this router is (\d+)/
overview[:number_of_areas] = $1.to_i
when ""
break
else
# debug
puts line if $QUAGGA_DEBUG
end
end
# general overview has ended - now the area overviews come
overview[:areas] = {}
current_area = {}
while line = lines.shift&.strip
case line
when /^Area ([\d\.]*)/
current_area = {}
overview[:areas][$1] = current_area
when /Interface attached to this area: (.*)/
current_area[:interfaces] = $1.split(" ")
when /Number of Area scoped LSAs is (.*)/
current_area[:number_lsas] = $1.to_i
else
puts line if $QUAGGA_DEBUG
end
end
overview
end
def linkstate
lines = @vtysh.execute("show ipv6 ospf6 linkstate").lines
linkstate = {}
qta = nil
current_area = []
while line = lines.shift&.strip
case line
when /SPF Result in Area (.*)/
linkstate[$1] = current_area = []
qta = QuaggaTableReader.new(["Type","Router-ID", "Net-ID", "Rtr-Bits", "Options", "Cost"])
lines.shift
qta.read_headline(lines.shift)
else
if line.length > 10
current_area << qta.read_entry(line)
end
end
end
linkstate
end
def route
route = []
lines = @vtysh.execute("show ipv6 ospf6 route").lines
lines.each do |line|
f1, f2, network, gateway, interface, time = line.strip.split(/\s+/)
route << { f1: f1,
f2: f2,
network: network,
gateway: gateway,
interface: interface,
time: time }
end
route
end
def neighbors
qta = QuaggaTableReader.new(["Neighbor ID","Pri", "DeadTime", "State/IfState", "Duration I/F[State]"])
neighbor = []
nb = @vtysh.execute("show ipv6 ospf6 neighbor").lines
qta.read_headline(nb.shift.strip)
while line = nb.shift&.strip
puts line
if line.length > 10
tmp = qta.read_entry(line)
tmp['Pri'] = tmp['Pri'].to_i
neighbor << tmp
end
end
neighbor
end
def database
lines = @vtysh.execute("show ipv6 ospf6 database").lines
database = {}
mode = :none
area = ''
qta = :none
while line = lines.shift&.strip
case line
when /Area Scoped Link State Database \(Area (.*)\)/
mode = :scoped_link_db
database[:scoped_link_db] ||= {}
database[:scoped_link_db][$1] = area = []
qta = database_qta(lines)
when /I\/F Scoped Link State Database \(I\/F (\S+) in Area (.*)\)/
mode = :if_scoped_link_state
database[:if_scoped_link_state] ||= {}
database[:if_scoped_link_state][$1] ||= {}
area = database[:if_scoped_link_state][$1][$2] ||= []
qta= database_qta(lines)
when "AS Scoped Link State Database"
mode = :as_scoped
area = database[:as_scoped] ||= []
qta=database_qta(lines)
# note: i have no data for this but i think it looks like the others
else
if line.length > 10
area << qta.read_entry(line)
end
end
end
database
end
def interface
lines = @vtysh.execute("show ipv6 ospf6 interface").lines
int = {}
current_if = {}
while line = lines.shift
if line.length > 5
case line.strip
when /(\S+) is (down|up), type ([A-Z]+)/
current_if = int[$1] = {up: ($2 == "up" ? true : false),
type: $3,
enabled: true}
when /Interface ID: (\d+)/
current_if[:id] = $1.to_i
when /OSPF not enabled on this interface/
current_if[:enabled] = false
when /Instance ID (\d+), Interface MTU (\d+) \(autodetect: (\d+)\)/
current_if[:instance_id] = $1.to_i
current_if[:interface_mtu] = $2.to_i
current_if[:interface_mtu_autodetect] = $3.to_i
when "Internet Address:"
# ignore
when /(inet |inet6): (\S+)/
current_if[:IPv6] ||= []
current_if[:IPv4] ||= []
family = $1 == 'inet6' ? :IPv6 : :IPv4
address = $2
current_if[family] << address
when /MTU mismatch detection: (en|dis)abled/
current_if[:mtu_mismatch_detection] = $1 == 'en'
when /DR: (\S+) BDR: (\S+)/
current_if[:designated_router] = $1
current_if[:backup_designated_router] = $2
when /State (\S+), Transmit Delay (\d+) sec, Priority (\d+)/
current_if[:state] = $1
current_if[:transmit_delay] = $2.to_i
current_if[:priority] = $3.to_i
when /Number of I\/F scoped LSAs is (\d+)/
current_if[:number_if_scoped_lsas] = $1.to_i
when /(\d+) Pending LSAs for (\S+) in Time ([\d:]+)(?: (.*))/
current_if[:pending_lsas] ||= {}
current_if[:pending_lsas][$2] = {time: $3,
count: $1,
flags: $4}
when "Timer intervals configured:"
# ignore
when /Hello (\d+), Dead (\d+), Retransmit (\d+)/
current_if[:timers] = {hello: $1.to_i,
dead: $2.to_i,
retransmit: $3.to_i }
when /Area ID (\S+), Cost (\d+)/
current_if[:area_cost] ||= []
current_if[:area_cost] << {area: $1, cost: $2.to_i }
else
puts line if $QUAGGA_DEBUG
end
end
end
int
end
private
def database_qta(lines)
# DON'T REMOVE THE SPACES!!!
# For some reasons the fields are right aligned with the fields which makes it hard
# to parse. I don't know a better way to get the correct offset except automatically.
# (Detection of semantic of the fields)
qta = QuaggaTableReader.new(["Type", "LSId", "AdvRouter", " Age", " SeqNum"," Payload"])
lines.shift
qta.read_headline(lines.shift)
qta
end
end
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: #{__FILE__} -s section [section specific params]"
#### OSPFv2
opts.on("-d", "--ospf-database", "Prints the OSPF Database") do |od|
options[:ospf_database] = od
end
opts.on("-r", "--ospf-route", 'print OSPF routing table') do |od|
options[:ospf_route] = od
end
opts.on("-i", "--ospf-interface", 'print OSPF interface information') do |od|
options[:ospf_interface] = od
end
opts.on("-n", "--ospf-neighbor", 'Print OSPF neighbors') do |od|
options[:ospf_neighbors] = od
end
opts.on("-o", "--ospf-overview", "Print OSPF summary") do |od|
options[:ospf_overview] = od
end
#### OSPFv3
opts.on("-D", "--ospfv3-database", "Prints the OSPFv3 Database") do |od|
options[:ospfv3_database] = od
end
opts.on("-t", "--ospfv3-route", 'print OSPFv3 routing table') do |od|
options[:ospfv3_route] = od
end
opts.on("-I", "--ospfv3-interface", 'print OSPFv3 interface information') do |od|
options[:ospfv3_interface] = od
end
opts.on("-N", "--ospfv3-neighbor", 'Print OSPFv3 neighbors') do |od|
options[:ospfv3_neighbors] = od
end
opts.on("-O", "--ospfv3-overview", "Print OSPFv3 summary") do |od|
options[:ospfv3_overview] = od
end
#### general things about routing
opts.on("-R", "--general-routes", "Print Routing Table (IPv4)") do |od|
options[:general_routes] = od
end
opts.on("-6", "--general-routes6", "Print Routing Table (IPv6)") do |od|
options[:general_routes6] = od
end
opts.on("-l", "--general-log", "Print Logs") do |od|
options[:general_log] = od
end
### BGP
opts.on("-B", "--bgp-overview", "Print an overview of BGP") do |od|
options[:bgp_overview] = od
end
### program opts
opts.on("-H", "--human-readable", "Print the output human readable (not json)") do |od|
options[:human_readable] = od
end
opts.on("-X", "--debug", "Prints debug output") do |od|
$QUAGGA_DEBUG = true
end
opts.on("-h", "--help", "Prints this help") do
puts opts
exit
end
end.parse!
# use the lib
sh = VTYSH.new
ospf = OSPF.new sh
ospfv3 = OSPFv3.new sh
bgp = BGP.new sh
general = General.new sh
result = {}
options.keys.each do |k|
# if it is true
if options[k]
begin
if k.to_s.include? 'ospf_'
cmd = k.to_s.split('_').last
result[k] = ospf.send(cmd)
elsif k.to_s.include? 'ospfv3'
cmd = k.to_s.split('_').last
result[k] = ospfv3.send(cmd)
elsif k.to_s.include? 'general'
cmd = k.to_s.split('_').last
result[k] = general.send(cmd)
elsif k.to_s.include? 'bgp'
cmd = k.to_s.split('_').last
result[k] = bgp.send(cmd)
end
rescue # do nothing on an error
result[k] = "error"
puts $! if $QUAGGA_DEBUG
end
end
end
# ospf.database, general.routes, ospf.interface, ospf.neighbors, ospf.route, ospf.overview
if options[:human_readable]
pp result
else
print result.to_json
end

View file

@ -0,0 +1,20 @@
#!/bin/sh
user=frr
group=frr
mkdir -p /var/run/frr
chown $user:$group /var/run/frr
chmod 750 /var/run/frr
mkdir -p /usr/local/etc/frr
chown $user:$group /usr/local/etc/frr
chmod 750 /usr/local/etc/frr
# ensure that frr can read the configuration files
chown -R $user:$group /usr/local/etc/frr
chown -R $user:$group /var/run/frr
# logfile (if used)
touch /var/log/frr.log
chown $user:$group /var/log/frr.log

View file

@ -0,0 +1,125 @@
[start]
command:/usr/local/opnsense/scripts/quagga/setup.sh;/usr/local/etc/rc.d/frr start
parameters:
type:script
message:starting quagga
[stop]
command:/usr/local/etc/rc.d/frr stop; exit 0
parameters:
type:script
message:stopping quagga
[restart]
command:/usr/local/opnsense/scripts/quagga/setup.sh;/usr/local/etc/rc.d/frr restart
parameters:
type:script
message:restarting quagga
[reconfigure]
command:/usr/local/opnsense/scripts/quagga/setup.sh;/usr/local/etc/rc.d/frr reload
parameters:
type:script
message:reconfigure quagga
[status]
command:/usr/local/etc/rc.d/frr status;exit 0
parameters:
type:script_output
message:request quagga
[diag-bgp]
command:/usr/local/opnsense/scripts/quagga/diag-bgp.sh
parameters:%s
type:script_output
message:bgp diagnostics
[diag-bgp2]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --bgp-overview
parameters:
type:script_output
message:bgp diagnostics
[ospf-database]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospf-database
parameters:
type:script_output
message: Shows the OSPF database
[ospf-route]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospf-route
parameters:
type:script_output
message: print OSPF routing table
[ospf-interface]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospf-interface
parameters:
type:script_output
message: print OSPF interface information
[ospf-neighbor]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospf-neighbor
parameters:
type:script_output
message: Print OSPF neighbors
[ospf-overview]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospf-overview
parameters:
type:script_output
message: Print OSPF summary
[ospfv3-database]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-database
parameters:
type:script_output
message: Shows the OSPF database
[ospfv3-route]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-route
parameters:
type:script_output
message: print OSPF routing table
[ospfv3-interface]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-interface
parameters:
type:script_output
message: print OSPF interface information
[ospfv3-neighbor]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-neighbor
parameters:
type:script_output
message: Print OSPF neighbors
[ospfv3-overview]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --ospfv3-overview
parameters:
type:script_output
message: Print OSPF summary
[general-routes]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --general-routes
parameters:
type:script_output
message: Print IPv4 Routing Table
[general-routes6]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --general-routes6
parameters:
type:script_output
message: Print IPv6 Routing Table
[general-log]
command:/usr/local/opnsense/scripts/quagga/quagga.rb --general-log
parameters:
type:script_output
message: Show Quagga logs
[general-runningconfig]
command:/usr/local/bin/vtysh -c "show run"
parameters:
type:script_output
message: Show running configuration

View file

@ -0,0 +1,6 @@
bgpd.conf:/usr/local/etc/frr/bgpd.conf
ospfd.conf:/usr/local/etc/frr/ospfd.conf
ospf6d.conf:/usr/local/etc/frr/ospf6d.conf
ripd.conf:/usr/local/etc/frr/ripd.conf
frr:/etc/rc.conf.d/frr
zebra.conf:/usr/local/etc/frr/zebra.conf

View file

@ -0,0 +1,118 @@
{% if helpers.exists('OPNsense.quagga.bgp.enabled') and OPNsense.quagga.bgp.enabled == '1' %}
{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
!
! Zebra configuration saved from vty
! 2017/03/03 20:21:04
!
{% if helpers.exists('OPNsense.quagga.general') %}
{% if helpers.exists('OPNsense.quagga.general.enablelogfile') and OPNsense.quagga.general.enablelogfile == '1' %}
log file /var/log/frr.log {{ OPNsense.quagga.general.logfilelevel }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.general.enablesyslog') and OPNsense.quagga.general.enablesyslog == '1' %}
log syslog {{ OPNsense.quagga.general.sysloglevel }}
{% endif %}
{% endif %}
!
!
!
{% if helpers.exists('OPNsense.quagga.bgp.asnumber') and OPNsense.quagga.bgp.asnumber != '' %}
router bgp {{ OPNsense.quagga.bgp.asnumber }}
{% if helpers.exists('OPNsense.quagga.bgp.networks') %}
{% for network in OPNsense.quagga.bgp.networks.split(',') %}
network {{ network }}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.quagga.bgp.redistribute') and OPNsense.quagga.bgp.redistribute != '' %}
{% for bgp_redistribute in OPNsense.quagga.bgp.redistribute.split(',') %}
redistribute {{ bgp_redistribute }}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.quagga.bgp.neighbors.neighbor') %}
{% for neighbor in helpers.toList('OPNsense.quagga.bgp.neighbors.neighbor') %}
{% if neighbor.enabled == '1' %}
neighbor {{ neighbor.address }} remote-as {{ neighbor.remoteas }}
{% if 'updatesource' in neighbor and neighbor.updatesource != '' %}
neighbor {{ neighbor.address }} update-source {{ physical_interface(neighbor.updatesource) }}
{% endif %}
{% if 'nexthopself' in neighbor and neighbor.nexthopself == '1' %}
neighbor {{ neighbor.address }} next-hop-self
{% endif %}
{% if 'defaultoriginate' in neighbor and neighbor.defaultoriginate == '1' %}
neighbor {{ neighbor.address }} default-originate
{% endif %}
{% if neighbor.linkedPrefixlistIn|default("") != "" %}
{% for prefixlist in neighbor.linkedPrefixlistIn.split(",") %}
{% set prefixlist2_data = helpers.getUUID(prefixlist) %}
{% if prefixlist2_data != {} and prefixlist2_data.enabled == '1' %}
neighbor {{ neighbor.address }} prefix-list {{ prefixlist2_data.name }} in
{% endif %}
{% endfor %}
{% endif %}
{% if neighbor.linkedPrefixlistOut|default("") != "" %}
{% for prefixlist in neighbor.linkedPrefixlistOut.split(",") %}
{% set prefixlist_data = helpers.getUUID(prefixlist) %}
{% if prefixlist_data != {} and prefixlist_data.enabled == '1' %}
neighbor {{ neighbor.address }} prefix-list {{ prefixlist_data.name }} out
{% endif %}
{% endfor %}
{% endif %}
{% if neighbor.linkedRoutemapIn|default("") != "" %}
{% for aspath in neighbor.linkedRoutemapIn.split(",") %}
{% set routemap2_data = helpers.getUUID(aspath) %}
{% if routemap2_data != {} and routemap2_data.enabled == '1' %}
neighbor {{ neighbor.address }} route-map {{ routemap2_data.name }} in
{% endif %}
{% endfor %}
{% endif %}
{% if neighbor.linkedRoutemapOut|default("") != "" %}
{% for aspath in neighbor.linkedRoutemapOut.split(",") %}
{% set routemap_data = helpers.getUUID(aspath) %}
{% if routemap_data != {} and routemap_data.enabled == '1' %}
neighbor {{ neighbor.address }} route-map {{ routemap_data.name }} out
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
!
{% if helpers.exists('OPNsense.quagga.bgp.prefixlists.prefixlist') %}
{% for prefixlist in helpers.sortDictList(OPNsense.quagga.bgp.prefixlists.prefixlist, 'name', 'seqnumber' ) %}
{% if prefixlist.enabled == '1' %}
ip prefix-list {{ prefixlist.name }} seq {{ prefixlist.seqnumber }} {{ prefixlist.action }} {{ prefixlist.network }}
{% endif %}
{% endfor %}
{% endif %}
!
{% if helpers.exists('OPNsense.quagga.bgp.aspaths.aspath') %}
{% for aspath in helpers.sortDictList(OPNsense.quagga.bgp.aspaths.aspath, 'number' ) %}
{% if aspath.enabled == '1' %}
ip as-path access-list {{ aspath.number }} {{ aspath.action }} {{ aspath.as }}
{% endif %}
{% endfor %}
{% endif %}
!
{% if helpers.exists('OPNsense.quagga.bgp.routemaps.routemap') %}
{% for routemap in helpers.sortDictList(OPNsense.quagga.bgp.routemaps.routemap, 'name', 'id' ) %}
{% if routemap.enabled == '1' %}
route-map {{ routemap.name }} {{ routemap.action }} {{ routemap.id }}
{% if routemap.match|default("") != "" %}
{% for aspath in routemap.match.split(",") %}
{% set aspath_data = helpers.getUUID(aspath) %}
{% if 'match' in routemap and routemap.match != '' %}
match as-path {{ aspath_data.number }}
{% endif %}
{% endfor %}
{% endif %}
{% if routemap.set != '' %}
set {{ routemap.set }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
!
{% endif %}
!
line vty
!
{% endif %}

View file

@ -0,0 +1,18 @@
defaultrouter="NO"
frr_enable="{% if helpers.exists('OPNsense.quagga.general.enabled') and OPNsense.quagga.general.enabled == '1' %}YES{% else %}NO{% endif %}"
{% if helpers.exists('OPNsense.quagga.general.enabled') and OPNsense.quagga.general.enabled == '1' %}
frr_opnsense_bootup_run="/usr/local/opnsense/scripts/quagga/setup.sh"
{% endif %}
frr_daemons="zebra{%
if helpers.exists('OPNsense.quagga.ospf.enabled') and OPNsense.quagga.ospf.enabled == '1' %} ospfd{% endif %}{%
if helpers.exists('OPNsense.quagga.rip.enabled') and OPNsense.quagga.rip.enabled == '1' %} ripd{% endif %}{%
if helpers.exists('OPNsense.quagga.bgp.enabled') and OPNsense.quagga.bgp.enabled == '1' %} bgpd{% endif %}{%
if helpers.exists('OPNsense.quagga.ospf6.enabled') and OPNsense.quagga.ospf6.enabled == '1' %} ospf6d{% endif %}{%
if helpers.exists('OPNsense.quagga.ripng.enabled') and OPNsense.quagga.ripng.enabled == '1' %} ripngd{% endif %}{%
if helpers.exists('OPNsense.quagga.isis.enabled') and OPNsense.quagga.isis.enabled == '1' %} isisd{% endif %}"
#frr_flags="...."
#frr_extralibs_path="... ..."
#router_enable="NO"
watchfrr_enable="YES"

View file

@ -0,0 +1,53 @@
{% macro cline(directive, modelname) -%}{% if modelname %}
ipv6 ospf6 {{ directive }} {{ modelname }}
{% endif %}{%- endmacro %}
{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
{% if helpers.exists('OPNsense.quagga.ospf6.enabled') and OPNsense.quagga.ospf6.enabled == '1' %}
!
! Zebra configuration saved from vty
! 2017/03/03 20:21:04
!
{% if helpers.exists('OPNsense.quagga.general') %}
{% if helpers.exists('OPNsense.quagga.general.enablelogfile') and OPNsense.quagga.general.enablelogfile == '1' %}
log file /var/log/frr.log {{ OPNsense.quagga.general.logfilelevel }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.general.enablesyslog') and OPNsense.quagga.general.enablesyslog == '1' %}
log syslog {{ OPNsense.quagga.general.sysloglevel }}
{% endif %}
{% endif %}
!
!
!
{% if helpers.exists('OPNsense.quagga.ospf6.interfaces.interface') %}
{% for interface in helpers.toList('OPNsense.quagga.ospf6.interfaces.interface') %}
{% if interface.enabled == '1' %}
interface {{ physical_interface(interface.interfacename) }}
{{ cline("cost",interface.cost)
}}{{ cline("dead-interval",interface.deadinterval)
}}{{ cline("hello-interval",interface.hellointerval)
}}{{ cline("priority",interface.priority)
}}{{ cline("retransmit-interval",interface.retransmitinterval)
}}!
{% endif %}
{% endfor %}
{% endif %}
!
router ospf6
{% if helpers.exists('OPNsense.quagga.ospf6.redistribute') and OPNsense.quagga.ospf6.redistribute != '' %}
{% for line in OPNsense.quagga.ospf6.redistribute.split(',') %}
redistribute {{ line }}
{% endfor %}{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf6.interfaces.interface') %}
{% for interface in helpers.toList('OPNsense.quagga.ospf6.interfaces.interface') %}
{% if interface.enabled == '1' %}
interface {{ physical_interface(interface.interfacename) }} area {{ interface.area }}
{% endif %}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf6.routerid') and OPNsense.quagga.ospf6.routerid != '' %}
router-id {{ OPNsense.quagga.ospf6.routerid }}
{% endif %}
!
line vty
!
{% endif %}

View file

@ -0,0 +1,89 @@
{% macro cline(directive, modelname) -%}{% if modelname %}
ip ospf {{ directive }} {{ modelname }}
{% endif %}{%- endmacro %}
{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
{% if helpers.exists('OPNsense.quagga.ospf.enabled') and OPNsense.quagga.ospf.enabled == '1' %}
!
! Zebra configuration saved from vty
! 2017/03/03 20:21:04
!
{% if helpers.exists('OPNsense.quagga.general') %}
{% if helpers.exists('OPNsense.quagga.general.enablelogfile') and OPNsense.quagga.general.enablelogfile == '1' %}
log file /var/log/frr.log {{ OPNsense.quagga.general.logfilelevel }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.general.enablesyslog') and OPNsense.quagga.general.enablesyslog == '1' %}
log syslog {{ OPNsense.quagga.general.sysloglevel }}
{% endif %}
{% endif %}
!
!
!
{% if helpers.exists('OPNsense.quagga.ospf.interfaces.interface') %}
{% for interface in helpers.toList('OPNsense.quagga.ospf.interfaces.interface') %}
{% if interface.enabled == '1' %}
interface {{ physical_interface(interface.interfacename) }}
{{ cline("authentication",interface.authtype)
}}{% if interface.authtype and interface.authtype == 'message-digest'
%}{{ cline("message-digest-key 1 md5",interface.authkey)
}}{% endif
%}{{ cline("cost",interface.cost)
}}{{ cline("dead-interval",interface.deadinterval)
}}{{ cline("hello-interval",interface.hellointerval)
}}{{ cline("priority",interface.priority)
}}{{ cline("retransmit-interval",interface.retransmitinterval)
}}!
{% endif %}
{% endfor %}
{% endif %}
!
router ospf
{% if helpers.exists('OPNsense.quagga.ospf.routerid') and OPNsense.quagga.ospf.routerid != '' %}
ospf router-id {{ OPNsense.quagga.ospf.routerid }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf.redistribute') and OPNsense.quagga.ospf.redistribute != '' %}
{% for line in OPNsense.quagga.ospf.redistribute.split(',') %}
redistribute {{ line }}
{% endfor %}{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf.passiveinterfaces') and OPNsense.quagga.ospf.passiveinterfaces != '' %}
{% for line in OPNsense.quagga.ospf.passiveinterfaces.split(',') %}
passive-interface {{ physical_interface(line) }}
{% endfor %}{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf.networks.network') %}
{% for network in helpers.toList('OPNsense.quagga.ospf.networks.network') %}
{% if network.enabled == '1' %}
network {{ network.ipaddr }}/{{ network.netmask }} area {{ network.area }}
{% endif %}
{% if network.linkedPrefixlistIn|default("") != "" %}
{% for prefixlist in network.linkedPrefixlistIn.split(",") %}
{% set prefixlist2_data = helpers.getUUID(prefixlist) %}
{% if prefixlist2_data != {} and prefixlist2_data.enabled == '1' %}
area {{ network.area }} filter-list prefix {{ prefixlist2_data.name }} in
{% endif %}
{% endfor %}
{% endif %}
{% if network.linkedPrefixlistOut|default("") != "" %}
{% for prefixlist in network.linkedPrefixlistOut.split(",") %}
{% set prefixlist_data = helpers.getUUID(prefixlist) %}
{% if prefixlist_data != {} and prefixlist_data.enabled == '1' %}
area {{ network.area }} filter-list prefix {{ prefixlist_data.name }} out
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.quagga.ospf.originate') and OPNsense.quagga.ospf.originate == '1' %}
default-information originate{% if helpers.exists('OPNsense.quagga.ospf.originatealways') and OPNsense.quagga.ospf.originatealways == '1' %} always {% endif %}
{% endif %}
!
{% if helpers.exists('OPNsense.quagga.ospf.prefixlists.prefixlist') %}
{% for prefixlist in helpers.sortDictList(OPNsense.quagga.ospf.prefixlists.prefixlist, 'name', 'seqnumber' ) %}
{% if prefixlist.enabled == '1' %}
ip prefix-list {{ prefixlist.name }} seq {{ prefixlist.seqnumber }} {{ prefixlist.action }} {{ prefixlist.network }}
{% endif %}
{% endfor %}
{% endif %}
!
line vty
!
{% endif %}

View file

@ -0,0 +1,34 @@
{% if helpers.exists('OPNsense.quagga.rip.enabled') and OPNsense.quagga.rip.enabled == '1' %}
{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
!
! Zebra configuration saved from vty
! 2017/03/26 22:40:16
!
{% if helpers.exists('OPNsense.quagga.general') %}
{% if helpers.exists('OPNsense.quagga.general.enablelogfile') and OPNsense.quagga.general.enablelogfile == '1' %}
log file /var/log/frr.log {{ OPNsense.quagga.general.logfilelevel }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.general.enablesyslog') and OPNsense.quagga.general.enablesyslog == '1' %}
log syslog {{ OPNsense.quagga.general.sysloglevel }}
{% endif %}
{% endif %}
!
router rip
version {{ OPNsense.quagga.rip.version }}
{% if helpers.exists('OPNsense.quagga.rip.redistribute') and OPNsense.quagga.rip.redistribute != '' %}
{% for line in OPNsense.quagga.rip.redistribute.split(',') %}
redistribute {{ line }}
{% endfor %}{% endif %}
{% if helpers.exists('OPNsense.quagga.rip.networks') %}
{% for network in OPNsense.quagga.rip.networks.split(',') %}
network {{ network }}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.quagga.rip.passiveinterfaces') and OPNsense.quagga.rip.passiveinterfaces != '' %}
{% for line in OPNsense.quagga.rip.passiveinterfaces.split(',') %}
passive-interface {{ physical_interface(line) }}
{% endfor %}{% endif %}
!
line vty
!
{% endif %}

View file

@ -0,0 +1,22 @@
{% if helpers.exists('OPNsense.quagga.general') %}
!
! Zebra configuration saved from vty
! 2017/03/03 20:21:04
!
{% if helpers.exists('OPNsense.quagga.general.enablelogfile') and OPNsense.quagga.general.enablelogfile == '1' %}
log file /var/log/frr.log {{ OPNsense.quagga.general.logfilelevel }}
{% endif %}
{% if helpers.exists('OPNsense.quagga.general.enablesyslog') and OPNsense.quagga.general.enablesyslog == '1' %}
log syslog {{ OPNsense.quagga.general.sysloglevel }}
{% endif %}
!
!
!
!
ip forwarding
ipv6 forwarding
!
!
line vty
!
{% endif %}

File diff suppressed because it is too large Load diff