From 05c9506b963d8f7e0d6104e1320df01ce00fa89a Mon Sep 17 00:00:00 2001 From: Viktor G Date: Wed, 19 Feb 2020 00:52:23 +0300 Subject: [PATCH] Quagga OSPF cost-shifting as a CARP failover. Issue #8181 (cherry picked from commit 1ef0edeae6f950d3541167b1609000df4a25e0c0) --- net/pfSense-pkg-Quagga_OSPF/Makefile | 2 +- .../files/usr/local/bin/quaggactl | 22 +++ .../files/usr/local/pkg/quagga_ospfd.inc | 153 +++++++++++++++--- .../files/usr/local/pkg/quagga_ospfd.xml | 52 +++++- .../files/usr/local/www/status_ospfd.php | 3 + 5 files changed, 209 insertions(+), 23 deletions(-) diff --git a/net/pfSense-pkg-Quagga_OSPF/Makefile b/net/pfSense-pkg-Quagga_OSPF/Makefile index caabe7228ac2..002dd400ddaa 100644 --- a/net/pfSense-pkg-Quagga_OSPF/Makefile +++ b/net/pfSense-pkg-Quagga_OSPF/Makefile @@ -2,7 +2,7 @@ PORTNAME= pfSense-pkg-Quagga_OSPF PORTVERSION= 0.6.21 -PORTREVISION= 4 +PORTREVISION= 5 CATEGORIES= net MASTER_SITES= # empty DISTFILES= # empty diff --git a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/bin/quaggactl b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/bin/quaggactl index 28f8265d7e92..bac65dfa1a63 100644 --- a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/bin/quaggactl +++ b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/bin/quaggactl @@ -53,6 +53,9 @@ zebra) bgpr*) daemon_command ${ZEBRA_PORT} ${ZEBRA_PASSWORD} "show ip route bgp" ;; + run*) + daemon_command ${ZEBRA_PORT} ${ZEBRA_PASSWORD} "enable\nshow running-config " + ;; esac ;; ospf*) if [ "`pgrep ospfd`" = "" ]; then @@ -87,6 +90,22 @@ ospf*) rou*) daemon_command ${OSPF_PORT} ${OSPF_PASSWORD} "show ip ospf route" ;; + run*) + daemon_command ${OSPF_PORT} ${OSPF_PASSWORD} "enable\nshow running-config" + ;; + cos*) + if [ -z "$3" ] || [ -z "$4" ]; then + echo "interface or cost not properly specified." + exit 1 + fi + case $4 in + 0) + daemon_command ${OSPF_PORT} ${OSPF_PASSWORD} "enable\nconfig terminal\ninterface $3\nno ip ospf cost\nend" + ;; + *) + daemon_command ${OSPF_PORT} ${OSPF_PASSWORD} "enable\nconfig terminal\ninterface $3\nip ospf cost $4\nend" + ;; + esac ;; esac ;; bgp6*) if [ "`pgrep bgpd`" = "" ]; then @@ -115,5 +134,8 @@ bgp*) shift; shift; daemon_command ${BGP_PORT} ${BGP_PASSWORD} "show ip bgp summary $*" ;; + run*) + daemon_command ${BGP_PORT} ${BGP_PASSWORD} "enable\nshow running-config" + ;; esac ;; esac diff --git a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.inc b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.inc index b4b71fcb433a..4717e5180f3e 100644 --- a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.inc +++ b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.inc @@ -77,7 +77,7 @@ function quagga_ospfd_install_conf() { // generate ospfd.conf based on the assistant if (is_array($config['installedpackages']['quaggaospfd']['config'])) { $ospfd_conf = &$config['installedpackages']['quaggaospfd']['config'][0]; - } elseif (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd']) || + } elseif (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd']) || isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospf6d']) || isset($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd'])) { log_error("Quagga: No assistant generated config for OSPF, but found raw config for one or more daemon"); @@ -293,8 +293,7 @@ function quagga_ospfd_install_conf() { && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd'])) { // if there is a raw config specified in the config.xml use that instead of the assisted config $bgpdconffile = str_replace("\r","",base64_decode($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd'])); - } - else { + } else { $bgpdconffile = "# This file was created by the pfSense package manager. Do not edit!\n\n"; if ($ospfd_conf['password']) { $bgpdconffile .= "password {$ospfd_conf['password']}\n"; @@ -323,28 +322,42 @@ function quagga_ospfd_install_conf() { fwrite($fd, $bgpdaddmd5file); fclose($fd); } - if ($bgpddelmd5file != "") { $fd = fopen("{$quagga_config_base}/bgpddelmd5pw.conf", "w"); fwrite($fd, $bgpddelmd5file); fclose($fd); } } - /* Make ospf6 config */ + /* Make ospf6 config */ if (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospf6d']) && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['ospf6d'])) { // if there is a raw config specified in the config.xml use that instead of the assisted config $ospf6dconffile = str_replace("\r","",base64_decode($config['installedpackages']['quaggaospfdraw']['config'][0]['ospf6d'])); } else { - $ospf6dconffile = ""; + $ospf6dconffile = ""; } $fd = fopen("{$quagga_config_base}/ospf6d.conf", "w"); fwrite($fd, $ospf6dconffile); fclose($fd); + //UPGRADE PATH - Checks if legacy "CARP Disable" mode was previously in use proior to 0.6.20; if previously in use, sets "carpmode" to "quaggadisable". If not in use, sets "carpmode" to "none". + if (!isset($ospfd_conf['carpmode'])) { + syslog(LOG_NOTICE, "Quagga: CARP failover mode upgrade initializing"); + if (strpos($ospfd_conf['carpstatusvid'], '_vip') !== false) { + $ospfd_conf['carpmode'] = "quaggadisable"; + syslog(LOG_NOTICE, "Quagga: CARP failover mode established as 'quaggadisable'"); + } else { + $ospfd_conf['carpmode'] = "none"; + syslog(LOG_NOTICE, "Quagga: CARP failover mode established as 'none'"); + } + write_config( $desc = gettext("Quagga_OSPFd: Upgraded failover method for legacy configurations of Quagga_OSPFD") ); + syslog(LOG_NOTICE, "Quagga: CARP failover upgrade complete"); + } + $carp_ip_status_check = ""; - if (isset($ospfd_conf['carpstatusvid']) && $ospfd_conf['carpstatusvid'] != "none") { + if ((isset($ospfd_conf['carpmode']) && ($ospfd_conf['carpmode'] == "quaggadisable")) + && (isset($ospfd_conf['carpstatusvid']) && ($ospfd_conf['carpstatusvid'] != "none"))) { $vip = get_configured_vip($ospfd_conf['carpstatusvid']); $carpcheckinterface = escapeshellarg(get_real_interface($vip['interface'])); $vhid = escapeshellarg("vhid {$vip['vhid']}"); @@ -352,10 +365,39 @@ function quagga_ospfd_install_conf() { CARP_STATUS=`/sbin/ifconfig {$carpcheckinterface} | /usr/bin/grep 'carp:' | /usr/bin/grep {$vhid} | /usr/bin/awk '{print \$2;}'` if [ \${CARP_STATUS} != "MASTER" ]; then + logger "Quagga: CARP \"Quagga Disable\" Mode - Interface {$carpcheckinterface} is NOT in MASTER state, exiting"; exit; fi EOF; } + + $carp_ospfcost_status_check = ""; + if ((isset($ospfd_conf['carpmode']) && ($ospfd_conf['carpmode'] == "ospfcost")) + && (isset($ospfd_conf['carpcostvid']) && (substr($ospfd_conf['carpcostvid'], 0, 4) != "none")) + && (isset($ospfd_conf['carpactivecost']) && isset($ospfd_conf['carpbackupcost'])) + && ($ospfd_conf['carpactivecost'] >= 0 && ($ospfd_conf['carpactivecost'] <= 65535)) + && ($ospfd_conf['carpbackupcost'] >= 0 && ($ospfd_conf['carpbackupcost'] <= 65535))) { + $control_script = "/usr/local/bin/quaggactl"; + $carpvips = explode(",", $ospfd_conf['carpcostvid']); + foreach ($carpvips as $vips) { + $vip = get_configured_vip($vips); + $phyint = get_real_interface($vip['interface']); + $carpcheckinterface = escapeshellarg(get_real_interface($vip['interface'])); + $vhid = escapeshellarg("vhid {$vip['vhid']}"); + $carp_ospfcost_status_check .= << 65535)) || + (($ospfd_conf['carpbackupcost'] < 0) || ($ospfd_conf['carpbackupcost'] > 65535))) { + syslog(LOG_ALERT, "Quagga: Failed checking CARP mode parameters: {$ospfd_conf['carpmode']}"); + return null; + } + + list($vhid, $iface) = explode("@", trim($pluginparams['interface'])); + $friendly = convert_real_interface_to_friendly_interface_name($iface); - /* Start or stop the service as needed based on the CARP transition. */ - if ($pluginparams['event'] == "rc.carpmaster") { - start_service("Quagga OSPFd"); - } elseif ($pluginparams['event'] == "rc.carpbackup") { - stop_service("Quagga OSPFd"); + switch ($ospfd_conf['carpmode']) { + case "quaggadisable": + syslog(LOG_INFO, "Quagga: CARP mode {$ospfd_conf['carpmode']}"); + $vip = get_configured_vip($ospfd_conf['carpstatusvid']); + syslog(LOG_INFO, "Quagga: CARP VHID and Interface {$vip['vhid']},{$vip['interface']}"); + if (($vip['vhid'] != $vhid) || ($vip['interface'] != $friendly)) { + return null; + } + + /* Start or stop the service as needed based on the CARP transition. */ + if ((isset($ospfd_conf['carpmode']) && ($ospfd_conf['carpmode'] == "quaggadisable")) && + (isset($ospfd_conf['carpstatusvid']) && ($ospfd_conf['carpstatusvid'] != "none"))) { + if ($pluginparams['event'] == "rc.carpmaster") { + start_service("Quagga OSPFd"); + } elseif ($pluginparams['event'] == "rc.carpbackup") { + stop_service("Quagga OSPFd"); + } + } + break; + case "ospfcost": + syslog(LOG_INFO, "Quagga: CARP mode {$ospfd_conf['carpmode']}"); + $carpvips = explode(",", $ospfd_conf['carpcostvid']); + $match = FALSE; + $i = 0; + foreach ($carpvips as $vip) { + $vips[$i] = get_configured_vip($vip); + if (($vips[$i]['vhid'] == $vhid) && ($vips[$i]['interface'] == $friendly)) { + $match = TRUE; + syslog(LOG_INFO, "Quagga: CARP VHID and Interface {$vips[$i]['vhid']} {$vips[$i]['interface']}"); + $phyint = get_real_interface($vips[$i]['interface']); + syslog(LOG_INFO, "Quagga: CARP Interface identified {$phyint}"); + } + $i++; + } + unset($vip); + + if ($match != TRUE){ + syslog(LOG_NOTICE, "Quagga: Couldn't find an Interface or VHID match!"); + return null; + } + + /* Shift OSPF cost up or downas needed based on the CARP transition. */ + $control_script = "/usr/local/bin/quaggactl"; + if ((isset($ospfd_conf['carpmode']) && ($ospfd_conf['carpmode'] == "ospfcost")) && + (isset($ospfd_conf['carpcostvid']) && (substr($ospfd_conf['carpcostvid'], 0, 4) != "none"))) { + if ($pluginparams['event'] == "rc.carpmaster") { + syslog(LOG_INFO, "Quagga: Shifted OSPF Master cost on {$phyint} to {$ospfd_conf['carpactivecost']}"); + mwexec("{$control_script} ospf cost {$phyint} {$ospfd_conf['carpactivecost']}"); + return null; + } elseif ($pluginparams['event'] == "rc.carpbackup") { + syslog(LOG_INFO, "Quagga: Shifted OSPF Backup cost on {$phyint} to {$ospfd_conf['carpbackupcost']}"); + mwexec("{$control_script} ospf cost {$phyint} {$ospfd_conf['carpbackupcost']}"); + return null; + } + } + break; + default: + break; } } @@ -544,11 +656,10 @@ function write_quagga_running_config($module) { if ( file_exists( $moduleRunningFile ) && ( filesize( $moduleRunningFile ) > 0 ) ) { $moduleRunning = fopen( "$moduleRunningFile", "r" ); $config['installedpackages']['quaggaospfdraw']['config'][0][$module . "running"] = base64_encode( fread( $moduleRunning, filesize($moduleRunningFile) )); - } - else { + } else { $config['installedpackages']['quaggaospfdraw']['config'][0][$module . "running"] = base64_encode("!!!!! {$module}.conf does not exist or is empty."); } - write_config( $write_config_only = true ); + write_config( $desc = gettext("Quagga_OSPFd: Wrote {$module}.conf startup-config to pfSense config file."), $backup = false, $write_config_only = true ); } write_quagga_running_config('bgpd'); diff --git a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.xml b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.xml index bc32a8327435..cebc268697bf 100644 --- a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.xml +++ b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/pkg/quagga_ospfd.xml @@ -225,18 +225,68 @@ + + CARP Mode + carpmode + + "Quagga Disable" mode keeps Quagga disabled on backup unit until it is active.
"OSPF Cost" mode dynamically changes OSPF cost allowing both firwalls to have an active routing table.
+ ]]> +
+ select + none + + + + + +
CARP Status IP carpstatusvid + For "Quagga Disable" mode. Used to determine the CARP status. When the CARP vhid is in BACKUP status, quagga will not be started.
+ ]]> +
+ select_source + + name + value +
+ + OSPF Cost Interfaces + carpcostvid + + For "OSPF Cost" mode. Select interfaces for dynamic OSPF cost changes based on CARP Master/Backup status.
]]>
select_source name value + +
+ + CARP OSPF Active Cost + carpactivecost + + For "OSPF Cost" mode. OSPF cost on selected interfaces when CARP Master. (Range 1-65535 or 0 for default/auto cost)
+ ]]> +
+ input +
+ + CARP OSPF Backup Cost + carpbackupcost + + For "OSPF Cost" mode. OSPF cost on selected interfaces when CARP Backup. (Range 1-65535 or 0 for default/auto cost)
+ ]]> +
+ input
diff --git a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/www/status_ospfd.php b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/www/status_ospfd.php index baa74284c8b9..ec11f7136113 100644 --- a/net/pfSense-pkg-Quagga_OSPF/files/usr/local/www/status_ospfd.php +++ b/net/pfSense-pkg-Quagga_OSPF/files/usr/local/www/status_ospfd.php @@ -78,8 +78,11 @@ function doCmdT($title, $command) { defCmdT("Quagga BGP IPv6 Routes", "{$control_script} bgp6 route"); defCmdT("Quagga BGP Neighbors", "{$control_script} bgp neighbor"); defCmdT("Quagga BGP Summary", "{$control_script} bgp sum"); +defCmdT("Quagga ospfd running-config", "{$control_script} ospf run"); defCmdT("Quagga ospfd.conf", "/bin/cat {$pkg_homedir}/ospfd.conf"); +defCmdT("Quagga bgpd running-config", "{$control_script} bgp run"); defCmdT("Quagga bgpd.conf", "/bin/cat {$pkg_homedir}/bgpd.conf"); +defCmdT("Quagga zebra running-config", "{$control_script} zebra run"); defCmdT("Quagga zebra.conf", "/bin/cat {$pkg_homedir}/zebra.conf"); $tab_array = array();