diff --git a/net/pfSense-pkg-Quagga_OSPF/Makefile b/net/pfSense-pkg-Quagga_OSPF/Makefile index 2bed38949e2a..12aacc61289e 100644 --- a/net/pfSense-pkg-Quagga_OSPF/Makefile +++ b/net/pfSense-pkg-Quagga_OSPF/Makefile @@ -1,7 +1,7 @@ # $FreeBSD$ PORTNAME= pfSense-pkg-Quagga_OSPF -PORTVERSION= 0.6.21 +PORTVERSION= 0.6.22 PORTREVISION= 3 CATEGORIES= net MASTER_SITES= # 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 894f4e01b7b3..e0a790038d8d 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 @@ -78,9 +78,9 @@ 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']) || - isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospf6d']) || - isset($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd'])) { + } 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"); } else { log_error("Quagga OSPFd: No config data found."); @@ -88,7 +88,7 @@ function quagga_ospfd_install_conf() { } if (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd']) - && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd'])) { + && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd'])) { // if there is a raw config specifyed in tthe config.xml use that instead of the assisted config $conffile = str_replace("\r","",base64_decode($config['installedpackages']['quaggaospfdraw']['config'][0]['ospfd'])); } else { @@ -266,7 +266,7 @@ function quagga_ospfd_install_conf() { /* Make zebra config */ if (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['zebra']) - && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['zebra'])) { + && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['zebra'])) { // if there is a raw config specifyed in tthe config.xml use that instead of the assisted config $zebraconffile = str_replace("\r", "", base64_decode($config['installedpackages']['quaggaospfdraw']['config'][0]['zebra'])); } else { @@ -291,11 +291,10 @@ function quagga_ospfd_install_conf() { /* Make bgpd config, add password and logging */ if (isset($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd']) - && !empty($config['installedpackages']['quaggaospfdraw']['config'][0]['bgpd'])) { + && !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"; @@ -324,39 +323,81 @@ 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") { - $vip = get_configured_vip($ospfd_conf['carpstatusvid']); - $carpcheckinterface = escapeshellarg(get_real_interface($vip['interface'])); - $vhid = escapeshellarg("vhid {$vip['vhid']}"); - $carp_ip_status_check = <<<EOF + 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']}"); + $carp_ip_status_check = <<<EOF 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 .= <<<EOF + +CARP_STATUS=`/sbin/ifconfig {$carpcheckinterface} | /usr/bin/grep 'carp:' | /usr/bin/grep {$vhid} | /usr/bin/awk '{print \$2;}'` +if [ \${CARP_STATUS} == "MASTER" ]; then + {$control_script} ospf cost {$phyint} {$ospfd_conf['carpactivecost']}; + logger "Quagga: CARP \"OSPF Cost\" Mode - Interface {$carpcheckinterface} is in MASTER state, OSPF cost set to {$ospfd_conf['carpactivecost']}"; +else + {$control_script} ospf cost {$phyint} {$ospfd_conf['carpbackupcost']}; + logger "Quagga: CARP \"OSPF Cost\" Mode - Interface {$carpcheckinterface} is NOT in MASTER state, OSPF cost set to {$ospfd_conf['carpbackupcost']}"; +fi +EOF; + + } + } // Create rc.d file @@ -422,6 +463,7 @@ fi [ -s {$quagga_config_base}/ospf6d.conf ] && /usr/local/sbin/ospf6d -d -f {$quagga_config_base}/ospf6d.conf [ -s {$quagga_config_base}/bgpdaddmd5pw.conf ] && /sbin/setkey -f {$quagga_config_base}/bgpdaddmd5pw.conf [ -s {$quagga_config_base}/bgpd.conf ] && /usr/local/sbin/bgpd -d -f {$quagga_config_base}/bgpd.conf +{$carp_ospfcost_status_check} EOF; write_rcfile(array( @@ -439,18 +481,20 @@ EOF; mwexec("/bin/chmod u+rw,go-rw {$quagga_config_base}/bgpd.conf"); // Kick off newly created rc.d script - 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")) { $status = get_carp_interface_status($ospfd_conf['carpstatusvid']); switch (strtoupper($status)) { // Stop the service if the VIP is in BACKUP or INIT state. case "BACKUP": case "INIT": mwexec_bg("/usr/local/etc/rc.d/quagga.sh stop"); + syslog(LOG_NOTICE, "Quagga: CARP \"Quagga Disable\" Mode - Interface {$carpcheckinterface} is NOT in MASTER state, exiting"); break; // Start the service if the VIP is MASTER state. case "MASTER": // Assume it's up if the status can't be determined. default: + syslog(LOG_NOTICE, "Quagga: CARP \"Quagga Disable\" Mode - Interface {$carpcheckinterface} is in MASTER state, starting"); mwexec_bg("/usr/local/etc/rc.d/quagga.sh restart"); break; } @@ -517,22 +561,83 @@ function quagga_ospfd_plugin_carp($pluginparams) { return null; } /* If there is no properly configured CARP status check IP, then stop */ - if (!isset($ospfd_conf['carpstatusvid']) || $ospfd_conf['carpstatusvid'] == "none") { - return null; - } - list($vhid, $iface) = explode("@", trim($pluginparams['interface'])); - $friendly = convert_real_interface_to_friendly_interface_name($iface); - $vip = get_configured_vip($ospfd_conf['carpstatusvid']); - if ($vip['vhid'] != $vhid || $vip['interface'] != $friendly) { - return null; - } - - /* 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"); - } + if (!isset($ospfd_conf['carpmode']) || $ospfd_conf['carpmode'] == "none") { + syslog(LOG_ALERT, "Quagga: CARP failover mode not set."); + return null; + } + /* Verify "quaggadisable" parameters are properly set.*/ + if ( $ospfd_conf['carpmode'] == "quaggadisable" && (!isset($ospfd_conf['carpstatusvid']) || $ospfd_conf['carpstatusvid'] == "none")) { + syslog(LOG_ALERT, "Quagga: Failed checking CARP mode parameters: {$ospfd_conf['carpmode']}"); + return null; + } + /* Verify "carpmode" parameters are properly set.*/ + if ( $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)) { + 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); + + 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; + } } /* The following function checks for the presence of and writes the contents of "/var/etc/quagga/$module.conf" into the $module . "running" field within the config.xml file */ @@ -547,11 +652,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 ); conf_mount_ro(); } 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 0c103aa7ebd1..5ccb6d967d99 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 @@ </rowhelperfield> </rowhelper> </field> + <field> + <fielddescr>CARP Mode</fielddescr> + <fieldname>carpmode</fieldname> + <description> + <![CDATA[ + Determines OSPF behavior when used in conjunction with CARP.<br /><b>"Quagga Disable"</b> mode keeps Quagga disabled on backup unit until it is active.<br /><b>"OSPF Cost"</b> mode dynamically changes OSPF cost allowing both firwalls to have an active routing table.<br /> + ]]> + </description> + <type>select</type> + <default_value>none</default_value> + <options> + <option><name>None (Do not track CARP status) (default)</name><value>none</value></option> + <option><name>Quagga Disable (Disable Quagga if backup)</name><value>quaggadisable</value></option> + <option><name>OSPF Cost (Dynamically change OSPF cost)</name><value>ospfcost</value></option> + </options> + </field> <field> <fielddescr>CARP Status IP</fielddescr> <fieldname>carpstatusvid</fieldname> <description> <![CDATA[ - Used to determine the CARP status. When the CARP vhid is in BACKUP status, quagga will not be started.<br /> + <b>For "Quagga Disable" mode.</b> Used to determine the CARP status. When the CARP vhid is in BACKUP status, quagga will not be started.<br /> + ]]> + </description> + <type>select_source</type> + <source><![CDATA[quagga_ospfd_get_carp_list()]]></source> + <source_name>name</source_name> + <source_value>value</source_value> + </field> + <field> + <fielddescr>OSPF Cost Interfaces</fielddescr> + <fieldname>carpcostvid</fieldname> + <description> + <![CDATA[ + <b>For "OSPF Cost" mode.</b> Select interfaces for dynamic OSPF cost changes based on CARP Master/Backup status.<br /> ]]> </description> <type>select_source</type> <source><![CDATA[quagga_ospfd_get_carp_list()]]></source> <source_name>name</source_name> <source_value>value</source_value> + <multiple></multiple> + </field> + <field> + <fielddescr>CARP OSPF Active Cost</fielddescr> + <fieldname>carpactivecost</fieldname> + <description> + <![CDATA[ + <b>For "OSPF Cost" mode.</b> OSPF cost on selected interfaces when CARP Master. (Range 1-65535 or 0 for default/auto cost)<br /> + ]]> + </description> + <type>input</type> + </field> + <field> + <fielddescr>CARP OSPF Backup Cost</fielddescr> + <fieldname>carpbackupcost</fieldname> + <description> + <![CDATA[ + <b>For "OSPF Cost" mode.</b> OSPF cost on selected interfaces when CARP Backup. (Range 1-65535 or 0 for default/auto cost)<br /> + ]]> + </description> + <type>input</type> </field> </fields> <custom_php_resync_config_command> 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 57c2f4d044c2..cbb7eaa45273 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();