#!/usr/bin/perl

# Author:	Sascha Rohrmann
# Company:	Citkomm
# E-Mail:	Rohrmann@citkomm.de
#
# This script checks the bird routing table for incoming BGP routes.
# BGP routes are labeled with "AS" is the bird routing table 
# (check "birdc show route" for that).
# If a line contains "AS" a counter increments.
# The counter itself is a fixed integer value which can be adjusted
# for your need.
# If there are enough routes, recieved via BGP, then the bird daemon
# throws the default route into OSPF.
#
# In order to make this script runnable you need to adjust
# your BIRD config:
# protocol static static_ospf {
# 	route 0.0.0.0/0 reject;
# 	import all;
#	}
# protocol ospf {
#	 ....
#	export where proto = "static_ospf";
#	}
#
# You can simply customize the following variables: 
# route_rounter		-> counts the incoming routes via bgp
# CHECK_TIME		-> checking interval
#
# Furthermore you can start this script with debug parameters
# in order to check if everything works well:
# ./check_bgp.pl -d

use Getopt::Std;
use strict;
use warnings;
use birdctl;

$ENV{PERL5LIB} = "/etc/scripts/";

$Getopt::Std::STANDARD_HELP_VERSION=1;

# variables for debug option
my %opts;
my $r = getopts('d', \%opts);

my $socket_path = '/var/run/bird.ctl';

# create a new socket
my $bird = new birdctl(
	socket => $socket_path,
	restrict => 0,
) or die "Could not connect to socket $!";

# you can adjust this value if you want a higher or a lower
# amount of bgp routes.
use constant ROUTE_COUNTER => 5;

# you can adjust this value if you desire a higher check interval
use constant CHECK_TIME => 5;

# logfile
my $logfile = "/var/log/check_bgp.log";

open(LOGFILE, '>>', $logfile)
	or die "could not open $logfile : $!";
print LOGFILE localtime() . " : watchdog started \n";
close (LOGFILE)
	or die "could not close $logfile : $!";

while (1)
{
	# current time
	my $date = localtime();
	
	# array for protocols
	my @protocols 	= $bird->long_cmd("show protocols");
	
	# $proto_name 	= name of the instance of a protocol
	# $proto	= protocol (e.g. BGP, OSPF, RIP etc)
	my ($proto_name, $proto);

	# scalar for the recieved routes
	my $route_count = 0;
	foreach (@protocols)
	{
		# substitute
		# four numbers between 0 and 9
		# a - which matches zero or one time
		# or one or multiplie whitespaces at the beginning
		# and split the string at the whitespaces
		# where $1 = proto_name
		# and $2   = protocol	
		$_=~s/(^(([0-9]{4}-{0,1})|\s+))// and ($proto_name,$proto)=split m/\s+/, $_;
		if ($proto =~ /BGP/)
		{
			my $route_string = $bird->cmd("show route where proto ~ \"$proto_name\" count");
				
			# scalar for counting the recivied bgp routes
			my @split_array = (split /\s+/ ,$route_string);
			$route_count += $split_array[1];
		}
		# if the limit is reached we can break the loop
		# to not stress birdctl more than needed
		last if ($route_count >= ROUTE_COUNTER);
		
	}	
	
	if ($route_count >= ROUTE_COUNTER)
	{
		open (LOGFILE, '>>', $logfile)
			or die "cannot open $logfile : $!";
		print LOGFILE $date . " BGP state: established \n";
		print LOGFILE "number of routes: $route_count \n";
		close (LOGFILE)
			or die "cannot close $logfile : $!";
		print "current routes recieved via BGP: $route_count\n"
			if (defined ($opts{'d'}));	
		
		foreach my $line (@protocols)
		{
			if ($line =~ /static_ospf/ && $line =~ /up/)
			{
				print "default route already threw into OSPF area \n" 
					if (defined ($opts{'d'}));
			}
			if ($line =~ /static_ospf/ && $line =~ /down/)
			{
			print "throwing default route into OSPF area...\n"
				if (defined ($opts{'d'}));
				$bird->cmd("enable static_ospf");
			}
		}
	}
	else
	{
		open (LOGFILE, '>>', $logfile)
			or die "cannot open $logfile : $!";
		print LOGFILE "not enough routes via BGP recieved...\n";
		close (LOGFILE)
			or die "cannot close $logfile : $!";
		# delete default route from OSPF
		print "not enough routes recieved \n"
			if (defined ($opts{'d'}));
		
		foreach my $line (@protocols)
		{
			if ($line =~ /static_ospf/ && $line =~ /up/)
			{
				print "stop throwing default route in OSPF \n"
					if (defined ($opts{'d'}));
				$bird->cmd("disable static_ospf");
			}
			if ($line =~ /static_ospf/ && $line =~ /down/)
			{
			print "static_ospf down\n"
				if (defined ($opts{'d'}));
			}
		}
	}

sleep CHECK_TIME;
}


