diff options
author | jim-p <jimp@pfsense.org> | 2015-06-05 12:08:44 -0400 |
---|---|---|
committer | jim-p <jimp@pfsense.org> | 2015-06-05 12:08:44 -0400 |
commit | 5f8d92438c489cc9ea6d6685e7a541612b10098a (patch) | |
tree | 0f8184713f421bb5a4ffa3681551da95ec4ae7fe /config | |
parent | e2a343ed332f4220cc5a57536bab98cf86bf4daa (diff) | |
download | pfsense-packages-5f8d92438c489cc9ea6d6685e7a541612b10098a.tar.gz pfsense-packages-5f8d92438c489cc9ea6d6685e7a541612b10098a.tar.bz2 pfsense-packages-5f8d92438c489cc9ea6d6685e7a541612b10098a.zip |
Add CARP status support to OpenBGPD so it can be stopped on a secondary unit.
Diffstat (limited to 'config')
-rw-r--r-- | config/openbgpd/openbgpd.inc | 116 | ||||
-rw-r--r-- | config/openbgpd/openbgpd.xml | 14 |
2 files changed, 126 insertions, 4 deletions
diff --git a/config/openbgpd/openbgpd.inc b/config/openbgpd/openbgpd.inc index c625cff8..038ffa11 100644 --- a/config/openbgpd/openbgpd.inc +++ b/config/openbgpd/openbgpd.inc @@ -191,6 +191,46 @@ function openbgpd_install_conf() { @chmod("{$bgpd_config_base}/bgpd.conf", 0600); unset($conffile); + $carp_ip_status_check = ""; + if (is_ipaddr($openbgpd_conf['carpstatusip'])) { + + $pfs_version = substr(trim(file_get_contents("/etc/version")),0,3); + switch ($pfs_version) { + case "2.0": + case "2.1": + /* Check for 2.1 and before */ + $carpcheckinterface = trim(find_carp_interface($openbgpd_conf['carpstatusip'])); + $carp_ip_status_check = <<<EOF + +CARP_STATUS=`/sbin/ifconfig {$carpcheckinterface} | /usr/bin/grep carp: | /usr/bin/awk '{print \$2;}'` +if [ \${CARP_STATUS} != "MASTER" ]; then + exit; +fi + +EOF; + break; + case "2.2": + default: + /* Check for 2.2 and later */ + if (is_array($config['virtualip']['vip'])) { + foreach ($config['virtualip']['vip'] as $vip) { + if (($vip['mode'] == "carp") && ($vip['subnet'] == $openbgpd_conf['carpstatusip'])) { + $carpcheckinterface = escapeshellarg(get_real_interface($vip['interface'])); + $vhid = escapeshellarg($vip['vhid']); + $carp_ip_status_check = <<<EOF + +CARP_STATUS=`/sbin/ifconfig {$carpcheckinterface} | /usr/bin/grep 'carp:' | /usr/bin/grep 'vhid {$vhid}' | /usr/bin/awk '{print \$2;}'` +if [ \${CARP_STATUS} != "MASTER" ]; then + exit; +fi +EOF; + } + } + } + break; + } + } + // Create rc.d file $rc_file_stop = <<<EOF killall -TERM bgpd @@ -210,6 +250,7 @@ fi NUMBGPD=`ps auxw | grep -c '[b]gpd.*parent'` if [ \${NUMBGPD} -lt 1 ] ; then + {$carp_ip_status_check} {$pkg_bin}/bgpd -f {$bgpd_config_base}/bgpd.conf else {$pkg_bin}/bgpctl reload @@ -225,13 +266,36 @@ EOF; $_gb = exec("/sbin/sysctl net.inet.ip.ipsec_in_use=1"); // bgpd process running? if so reload, else start. + + // Kick off newly created rc.d script + if (is_ipaddr($openbgpd_conf['carpstatusip'])) { + $status = openbgpd_get_carp_status_by_ip($openbgpd_conf['carpstatusip']); + switch (strtoupper($status)) { + // Stop the service if the VIP is in BACKUP or INIT state. + case "BACKUP": + case "INIT": + exec("/usr/local/etc/rc.d/bgpd.sh stop"); + break; + // Start the service if the VIP is MASTER state. + case "MASTER": + // Assume it's up if the status can't be determined. + default: + openbgpd_restart(); + break; + } + } else { + openbgpd_restart(); + } + + conf_mount_ro(); +} + +function openbgpd_restart() { if(is_openbgpd_running() == true) { exec("{$pkg_bin}/bgpctl reload"); } else { exec("{$pkg_bin}/bgpd -f {$bgpd_config_base}/bgpd.conf"); } - - conf_mount_ro(); } // get the raw openbgpd confi file for manual inspection/editing @@ -362,4 +426,52 @@ function is_openbgpd_running() { return false; } +function openbgpd_get_carp_status_by_ip($ipaddr) { + $iface = trim(find_carp_interface($ipaddr)); + if ($iface) { + $status = get_carp_interface_status($iface); + // If there is no status for that interface, return null. + if (!$status) + $status = null; + } else { + // If there is no VIP by that IP, return null. + $status = null; + } + return $status; +} + +function openbgpd_plugin_carp($pluginparams) { + global $config; + require_once("service-utils.inc"); + // Called when a CARP interface changes state + // $pluginparams['event'] either 'rc.carpmaster' or 'rc.carpbackup' + // $pluginparams['interface'] contains the affected interface + + /* If there is no bgp config, then stop */ + if(is_array($config['installedpackages']['openbgpd']['config'])) { + $openbgpd_conf = &$config['installedpackages']['openbgpd']['config'][0]; + } else { + return null; + } + /* If there is no properly configured CARP status check IP, then stop */ + if (!is_ipaddr($openbgpd_conf['carpstatusip'])) { + return null; + } + list($vhid, $iface) = explode("@", trim($pluginparams['interface'])); + $friendly = convert_real_interface_to_friendly_interface_name($iface); + $carp_iface = "{$friendly}_vip${vhid}"; + + /* If this CARP transition is not from the IP address to check, then stop. */ + if (get_interface_ip($carp_iface) != $openbgpd_conf['carpstatusip']) { + return null; + } + + /* Start or stop the service as needed based on the CARP transition. */ + if ($pluginparams['event'] == "rc.carpmaster") { + start_service("bgpd"); + } elseif ($pluginparams['event'] == "rc.carpbackup") { + stop_service("bgpd"); + } +} + ?> diff --git a/config/openbgpd/openbgpd.xml b/config/openbgpd/openbgpd.xml index ff40452a..e7d77786 100644 --- a/config/openbgpd/openbgpd.xml +++ b/config/openbgpd/openbgpd.xml @@ -105,6 +105,11 @@ <url>/openbgpd_status.php</url> </tab> </tabs> + <plugins> + <item> + <type>plugin_carp</type> + </item> + </plugins> <fields> <field> <fielddescr>Autonomous Systems (AS) Number</fielddescr> @@ -143,8 +148,13 @@ <description>Set the router ID to the given IP address, which must be local to the machine.</description> <type>input</type> </field> - - + <field> + <fielddescr>CARP Status IP</fielddescr> + <fieldname>carpstatusip</fieldname> + <description>IP address used to determine the CARP status. When the VIP is in BACKUP status, bgpd will not be started. <br/>NOTE: On 2.1.x and before this requires changes to /etc/rc.carpmaster to start bgpd and /etc/rc.carpbackup to stop bgpd or it will not be fully effective. On pfSense 2.2.x and later, full support is automatic.</description> + <type>input</type> + <size>25</size> + </field> <field> <fielddescr>Networks</fielddescr> <fieldname>network</fieldname> |