diff --git a/net/frr/pkg-descr b/net/frr/pkg-descr
index be8a21162..ff023d830 100644
--- a/net/frr/pkg-descr
+++ b/net/frr/pkg-descr
@@ -11,6 +11,13 @@ switching and routing, Internet access routers, and Internet peering.
Plugin Changelog
================
+1.28
+
+* OSPF6 Interface change networktype and interfacename to dropdown in stead of multi select
+* Diagnostics / BGP - fix search in grid, should only use a formatter for presentation purposes.
+* Add ospf6 carp demotion event handler
+
+
1.27
* Add BGP password authentication
diff --git a/net/frr/src/etc/rc.carp_service_status.d/carp_frr_ospf6 b/net/frr/src/etc/rc.carp_service_status.d/carp_frr_ospf6
new file mode 100755
index 000000000..218699f55
--- /dev/null
+++ b/net/frr/src/etc/rc.carp_service_status.d/carp_frr_ospf6
@@ -0,0 +1,25 @@
+#!/bin/sh
+if [ -f /etc/rc.conf.d/frr ]; then
+ . /etc/rc.conf.d/frr
+fi
+
+if [ "$frr_enable" == "YES" ] && (`echo "$frr_daemons" | /usr/bin/grep -F -q -w "ospf6d"`) &&
+ (`echo "$frr_carp_demote" | /usr/bin/grep -F -q -w "ospf6d"`) ; then
+ # OSPF enabled
+ OSPF_NEIGHBOR=`echo "show ipv6 ospf6 neighbor" | /usr/local/bin/vtysh 2>&1` IFS=
+ if [ "$?" -eq 0 ]; then
+ # running, check if we can find any neighbors
+ IFS=
+ neighbors_count=`echo $OSPF_NEIGHBOR | grep "Full/" | wc -l`
+ unset IFS
+ if [ "$neighbors_count" -eq 0 ]; then
+ # no neighbors in state Full/* found
+ exit 2
+ else
+ exit 0
+ fi
+ else
+ # not running
+ exit 1
+ fi
+fi
diff --git a/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPF6Interface.xml b/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPF6Interface.xml
index 545575167..2ddc6d816 100644
--- a/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPF6Interface.xml
+++ b/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/dialogEditOSPF6Interface.xml
@@ -7,7 +7,7 @@
interface.interfacename
- select_multiple
+ dropdownSelect an interface where this settings apply to.
@@ -26,6 +26,18 @@
text
+
+ interface.cost_demoted
+
+ text
+
+
+ interface.carp_depend_on
+
+ dropdown
+ The carp VHID to depend on, when this virtual address is not in master state,
+ the interface cost will be set to the demoted cost (specified above).
+ interface.hellointerval
@@ -54,6 +66,6 @@
interface.networktype
- select_multiple
+ dropdown
diff --git a/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf6.xml b/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf6.xml
index 7f6139457..43bfb1b11 100644
--- a/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf6.xml
+++ b/net/frr/src/opnsense/mvc/app/controllers/OPNsense/Quagga/forms/ospf6.xml
@@ -5,6 +5,16 @@
checkboxThis will activate the OSPFv3 service if routing protocols are enabled in "General".
+
+ ospf6.carp_demote
+
+ checkbox
+
+ Register CARP status monitor, when no neighbors are found, consider this node less attractive.
+ This feature needs syslog enabled using "Debugging" logging to catch all relevant status events.
+ This option is not compatible with "Enable CARP Failover".
+
+ ospf6.redistribute
diff --git a/net/frr/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF6.xml b/net/frr/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF6.xml
index 46e433426..b6a9b1b65 100644
--- a/net/frr/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF6.xml
+++ b/net/frr/src/opnsense/mvc/app/models/OPNsense/Quagga/OSPF6.xml
@@ -7,6 +7,10 @@
0Y
+
+ 0
+ Y
+ NY
@@ -52,6 +56,17 @@
4294967295Cost must be between 0 and 4294967295.
+
+ 65535
+ 1
+ N
+ 65535
+ Cost must be between 1 and 65535.
+
+
+ carp
+ N
+ 0
diff --git a/net/frr/src/opnsense/mvc/app/views/OPNsense/Quagga/diagnosticsbgp.volt b/net/frr/src/opnsense/mvc/app/views/OPNsense/Quagga/diagnosticsbgp.volt
index 60c7d72f1..b0e196ce0 100644
--- a/net/frr/src/opnsense/mvc/app/views/OPNsense/Quagga/diagnosticsbgp.volt
+++ b/net/frr/src/opnsense/mvc/app/views/OPNsense/Quagga/diagnosticsbgp.volt
@@ -101,7 +101,6 @@ $(document).ready(function() {
content = _.template($('#routestpl').html())(data['response']);
$('#routing').html(content);
$('#routing table').bootgrid({
- converters: dataconverters,
formatters: dataformatters
});
});
@@ -110,7 +109,6 @@ $(document).ready(function() {
content = _.template($('#routestpl').html())(data['response']);
$('#routing6').html(content);
$('#routing6 table').bootgrid({
- converters: dataconverters,
formatters: dataformatters
});
});
diff --git a/net/frr/src/opnsense/scripts/frr/lib/events/ospf6d.py b/net/frr/src/opnsense/scripts/frr/lib/events/ospf6d.py
new file mode 100644
index 000000000..42d86c9d9
--- /dev/null
+++ b/net/frr/src/opnsense/scripts/frr/lib/events/ospf6d.py
@@ -0,0 +1,107 @@
+"""
+ Copyright (c) 2022 Ad Schellevis
+ 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.
+
+"""
+import os
+import syslog
+from configparser import ConfigParser
+from ..base import BaseEventHandler
+
+
+class Ospf6dEventHandler(BaseEventHandler):
+ _config = '/usr/local/etc/frr/ospf6d_carp.conf'
+
+ @property
+ def should_run(self):
+ return self.vtysh.is_running('ospf6d')
+
+ def _read_config(self):
+ result = dict()
+ if os.path.isfile(self._config):
+ cnf = ConfigParser()
+ cnf.read(self._config)
+ not_empty = lambda x, y: cnf.has_option(x, y) and cnf.get(x, y) != '' and cnf.get(x, y) != '0'
+ for section in cnf.sections():
+ if not_empty(section, 'interface') and not_empty(section, 'interface') \
+ and not_empty(section, 'demoted_cost') and not_empty(section, 'carp_depend_on'):
+ default_cost = cnf.getint(section, 'default_cost') if not_empty(section, 'default_cost') else None
+ result[cnf.get(section, 'interface')] = {
+ 'demoted_cost': cnf.getint(section, 'demoted_cost'),
+ 'carp_depend_on': cnf.get(section, 'carp_depend_on'),
+ 'default_cost': default_cost,
+ }
+
+ return result
+
+ def execute(self):
+ if os.path.isfile(self._config):
+ # parse ospf6 interface data, keep structure similar to what ospf offers when using json output
+ ospf_interfaces = {
+ 'interfaces': {}
+ }
+ this_interface = None
+ for line in self.vtysh.execute('show ipv6 ospf6 interface', translate=None).decode().split('\n'):
+ if len(line) > 0 and line[0] != ' ':
+ this_interface = line.split()[0]
+ ospf_interfaces['interfaces'][this_interface] = {}
+ elif this_interface is not None:
+ if line.find('Area ID') > 0 and line.split()[-1].isdigit():
+ # Area ID X.X.X.X, Cost XXXX
+ ospf_interfaces['interfaces'][this_interface]['cost'] = int(line.split()[-1])
+
+ config_interfaces = self._read_config()
+ for intf in config_interfaces:
+ if 'interfaces' in ospf_interfaces and intf in ospf_interfaces['interfaces']:
+ ospf_intf_cost = ospf_interfaces['interfaces'][intf]['cost']
+ is_intf_master = self.ifstatus.address_status(config_interfaces[intf]['carp_depend_on']) == 'master'
+ is_ospf_dem = ospf_intf_cost == config_interfaces[intf]['demoted_cost']
+ if is_intf_master and is_ospf_dem:
+ # promote ospf6 interface
+ conf_cost = config_interfaces[intf]['default_cost']
+ if conf_cost is None:
+ syslog.syslog(
+ syslog.LOG_NOTICE, 'ospf6d promote interface %s (no default cost configured).' % intf
+ )
+ self.vtysh.execute(
+ ['interface %s' % intf, 'no ipv6 ospf6 cost'], translate=None, configure=True
+ )
+ elif conf_cost != ospf_intf_cost:
+ syslog.syslog(
+ syslog.LOG_NOTICE, 'ospf6d promote interface %s (cost %d).' % (intf, conf_cost)
+ )
+ self.vtysh.execute(
+ ['interface %s' % intf, 'ipv6 ospf6 cost %d' % conf_cost],
+ translate=None, configure=True
+ )
+ elif not is_intf_master and not is_ospf_dem:
+ # demote ospf6 interface
+ conf_cost = config_interfaces[intf]['demoted_cost']
+ syslog.syslog(
+ syslog.LOG_NOTICE, 'ospf6d demote interface %s (cost %d).' % (intf, conf_cost)
+ )
+ self.vtysh.execute(
+ ['interface %s' % intf, 'ipv6 ospf6 cost %d' % conf_cost],
+ translate=None, configure=True
+ )
diff --git a/net/frr/src/opnsense/scripts/frr/lib/events/ospfd.py b/net/frr/src/opnsense/scripts/frr/lib/events/ospfd.py
index d69274708..7eabadb9b 100755
--- a/net/frr/src/opnsense/scripts/frr/lib/events/ospfd.py
+++ b/net/frr/src/opnsense/scripts/frr/lib/events/ospfd.py
@@ -59,8 +59,6 @@ class OspfdEventHandler(BaseEventHandler):
if os.path.isfile(self._config):
ospf_interfaces = self.vtysh.execute('show ip ospf interface json')
config_interfaces = self._read_config()
- cnf = ConfigParser()
- cnf.read(self._config)
for intf in config_interfaces:
if 'interfaces' in ospf_interfaces and intf in ospf_interfaces['interfaces']:
ospf_intf_cost = ospf_interfaces['interfaces'][intf]['cost']
diff --git a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS
index c2e0542d6..ea22bda2d 100644
--- a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS
+++ b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/+TARGETS
@@ -3,6 +3,7 @@ bgpd.conf:/usr/local/etc/frr/bgpd.conf
ospfd.conf:/usr/local/etc/frr/ospfd.conf
ospfd_carp.conf:/usr/local/etc/frr/ospfd_carp.conf
ospf6d.conf:/usr/local/etc/frr/ospf6d.conf
+ospf6d_carp.conf:/usr/local/etc/frr/ospf6d_carp.conf
ripd.conf:/usr/local/etc/frr/ripd.conf
sa_policies.conf:/usr/local/etc/frr/sa_policies.conf
frr:/etc/rc.conf.d/frr
diff --git a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/frr b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/frr
index 9c8ee8525..2b0b29166 100644
--- a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/frr
+++ b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/frr
@@ -12,7 +12,10 @@ if helpers.exists('OPNsense.quagga.bgp.enabled') and OPNsense.quagga.bgp.enabled
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_carp_demote="{% if not helpers.empty('OPNsense.quagga.ospf.carp_demote') %} ospfd{% endif %}"
+frr_carp_demote="{%
+ if not helpers.empty('OPNsense.quagga.ospf.carp_demote') %} ospfd{% endif %}{%
+ if not helpers.empty('OPNsense.quagga.ospf6.carp_demote') %} ospf6d{% endif
+%}"
start_postcmd="/usr/local/opnsense/scripts/frr/carp_event_handler"
{% else %}
frr_enable="NO"
diff --git a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/ospf6d_carp.conf b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/ospf6d_carp.conf
new file mode 100644
index 000000000..af3400036
--- /dev/null
+++ b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/ospf6d_carp.conf
@@ -0,0 +1,13 @@
+{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
+{% if helpers.exists('OPNsense.quagga.ospf6.interfaces.interface') %}
+{% for interface in helpers.toList('OPNsense.quagga.ospf6.interfaces.interface') %}
+{% if interface.enabled == '1' %}
+[{{ interface['@uuid'] }}]
+enabled={{interface.enabled|default('0')}}
+interface={{physical_interface(interface.interfacename)}}
+default_cost={{interface.cost|default('')}}
+demoted_cost={{interface.cost_demoted|default('')}}
+carp_depend_on={{interface.carp_depend_on|default('')}}
+{% endif %}
+{% endfor %}
+{% endif %}
diff --git a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/syslog-ng-frr-events.conf b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/syslog-ng-frr-events.conf
index 9644313b8..309d47627 100644
--- a/net/frr/src/opnsense/service/templates/OPNsense/Quagga/syslog-ng-frr-events.conf
+++ b/net/frr/src/opnsense/service/templates/OPNsense/Quagga/syslog-ng-frr-events.conf
@@ -6,7 +6,8 @@ destination d_frr_event {
};
filter f_frr_ospf {
- program("ospfd") and (
+ (program("ospfd") or program("ospf6d"))
+ and (
(
level("info") or level("notice")
) or (