# Ospfd.pm
#
# The ospfd plugin
package ospfd;
@ISA = qw(Exporter);
@EXPORT = qw(createPlugin
bootingCreateFiles
bootingCommands
execCreateFiles
execCommands
shutdownCommand
finalizePlugin);
###########################################################
# Modules import
###########################################################
use strict;
use XML::DOM; # XML management library
use File::Basename; # File management library
use Switch;
use Socket; # To resolve hostnames to IPs
use XML::DOM::ValParser; # To check DTD
###########################################################
# Global variables
###########################################################
my $globalNode;
my $valid_fail;
###########################################################
# Subroutines
###########################################################
###########################################################
# Create plugin
#
# To be called always, just before starting procesing the scenario specification
#
# Arguments:
# - the operation mode ("t","x","d" or "P")
# - the plugin configuration file
#
# Returns:
# - an error message or 0 if all is ok
#
#
###########################################################
sub createPlugin{
my $self = shift;
my $mode = shift;
my $conf = shift;
my $error;
eval{
$error = &checkConfigFile($conf);
};
if ($@){
$error = $@;
}
return $error;
}
###########################################################
# bootingCreateFiles
#
# To be called during "t" mode, for each vm in the scenario
#
# Arguments:
# - vm name
#
# Returns:
# - a hashname which keys are absolute pathnames of files in vm filesystem and
# values the the pathname of the file in the host filesystem. The file in the
# host filesytesm is removed after VNUML processed it, so temporal files in
# /tmp are preferable)
###########################################################
sub bootingCreateFiles{
my $self = shift;
my $vm = shift;
my %files;
my $virtualmList=$globalNode->getElementsByTagName("vm");
my $longitud = $virtualmList->getLength;
for (my $m=0; $m<$longitud; $m++){
my $virtualm = $virtualmList->item($m);
my $virtualm_name = $virtualm->getAttribute("name");
if ($virtualm_name eq $vm){
my $zebra_file = "/tmp/$vm"."_zebra.conf";
my $ospfd_file = "/tmp/$vm"."_ospfd.conf";
my $zebraTagList = $virtualm->getElementsByTagName("zebra");
my $zebraTag = $zebraTagList->item($0);
my $zebra_hostname = $zebraTag->getAttribute("hostname");
my $zebra_password = $zebraTag->getAttribute("password");
chomp(my $date = `date`);
open(ZEBRA, ">$zebra_file") or $files{"ERROR"} = "Cannot open $zebra_file file";
print ZEBRA "! zebra.conf file generated by ospfd.pm VNUML plugin at $date\n";
print ZEBRA "hostname $zebra_hostname\n";
print ZEBRA "password $zebra_password\n";
print ZEBRA "log file /var/log/zebra/zebra.log\n";
close (ZEBRA);
open(OSPFD, ">$ospfd_file") or $files{"ERROR"} = "Cannot open $ospfd_file file";
print OSPFD "! ospfd.conf file generated by ospfd.pm VNUML plugin at $date\n";
print OSPFD "hostname $zebra_hostname\n";
print OSPFD "password $zebra_password\n";
print OSPFD "log file /var/log/zebra/ospfd.log\n!\n";
print OSPFD "router ospf\n";
my $networkTagList = $virtualm->getElementsByTagName("network");
my $longitudNetwork = $networkTagList->getLength;
for (my $n=0; $n<$longitudNetwork; $n++){
my $networkTag = $networkTagList->item($n);
my $ipTagList = $networkTag->getElementsByTagName("ip");
my $ipTag = $ipTagList->item($0);
my $ipMask = $ipTag->getAttribute("mask");
my $ipData = $ipTag->getFirstChild->getData;
my $areaTagList = $networkTag->getElementsByTagName("area");
my $areaTag = $areaTagList->item($0);
my $areaData = $areaTag->getFirstChild->getData;
print OSPFD " network $ipData/$ipMask area $areaData\n";
}
print OSPFD "!\n";
close (OSPFD);
$files{"/etc/quagga/zebra.conf"} = $zebra_file;
$files{"/etc/quagga/ospfd.conf"} = $ospfd_file;
}
}
return %files;
}
sub bootingCommands{
}
sub execVmsToUse {
my $self = shift;
my $seq = shift;
# The plugin has nothing to do for VMs with sequences other than
# start, restart or stop, so in that case it returns an empty list
unless ($seq eq "start" || $seq eq "ospf-start" || $seq eq "restart" || $seq eq "ospf-restart" || $seq eq "stop" || $seq eq "ospf-stop" || $seq eq "redoconf" || $seq eq "ospf-redoconf") {
return ();
}
my @vm_list = ();
my $virtualmList=$globalNode->getElementsByTagName("vm");
my $longitud = $virtualmList->getLength;
for (my $m=0; $m<$longitud; $m++){
my $virtualm = $virtualmList->item($m);
push (@vm_list,$virtualm->getAttribute("name"));
}
return @vm_list;
}
###########################################################
# execCreateFiles
#
# To be called during "x" mode, for each vm in the scenario
#
# Arguments:
# - vm name
# - seq command sequence
#
# Returns:
# - a hashname which kyes are absolute pathnames of files in vm filesystem and
# values the the pathname of the file in the host filesystem. The file in the
# host filesytesm is removed after VNUML processed it, so temporal files in
# /tmp are preferable)
#
###########################################################
sub execCreateFiles{
my $self = shift;
my $vm = shift;
my $seq = shift;
my %files;
if (($seq eq "redoconf") || ($seq eq "ospf-redoconf")){
my $virtualmList=$globalNode->getElementsByTagName("vm");
my $longitud = $virtualmList->getLength;
for (my $m=0; $m<$longitud; $m++){
my $virtualm = $virtualmList->item($m);
my $virtualm_name = $virtualm->getAttribute("name");
if ($virtualm_name eq $vm){
my $zebra_file = "/tmp/$vm"."_zebra.conf";
my $ospfd_file = "/tmp/$vm"."_ospfd.conf";
my $zebraTagList = $virtualm->getElementsByTagName("zebra");
my $zebraTag = $zebraTagList->item($0);
my $zebra_hostname = $zebraTag->getAttribute("hostname");
my $zebra_password = $zebraTag->getAttribute("password");
chomp(my $date = `date`);
open(ZEBRA, ">$zebra_file") or $files{"ERROR"} = "Cannot open $zebra_file file";
print ZEBRA "! zebra.conf file generated by ospfd.pm VNUML plugin at $date\n";
print ZEBRA "hostname $zebra_hostname\n";
print ZEBRA "password $zebra_password\n";
print ZEBRA "log file /var/log/zebra/zebra.log\n";
close (ZEBRA);
open(OSPFD, ">$ospfd_file") or $files{"ERROR"} = "Cannot open $ospfd_file file";
print OSPFD "! ospfd.conf file generated by ospfd.pm VNUML plugin at $date\n";
print OSPFD "hostname $zebra_hostname\n";
print OSPFD "password $zebra_password\n";
print OSPFD "log file /var/log/zebra/ospfd.log\n!\n";
print OSPFD "router ospf\n";
my $networkTagList = $virtualm->getElementsByTagName("network");
my $longitudNetwork = $networkTagList->getLength;
for (my $n=0; $n<$longitudNetwork; $n++){
my $networkTag = $networkTagList->item($n);
my $ipTagList = $networkTag->getElementsByTagName("ip");
my $ipTag = $ipTagList->item($0);
my $ipMask = $ipTag->getAttribute("mask");
my $ipData = $ipTag->getFirstChild->getData;
my $areaTagList = $networkTag->getElementsByTagName("area");
my $areaTag = $areaTagList->item($0);
my $areaData = $areaTag->getFirstChild->getData;
print OSPFD " network $ipData/$ipMask area $areaData\n";
}
print OSPFD "!\n";
close (OSPFD);
$files{"/etc/quagga/zebra.conf"} = $zebra_file;
$files{"/etc/quagga/ospfd.conf"} = $ospfd_file;
}
}
}
return %files;
}
###########################################################
# execCommands
#
# To be called during "x" mode, for each vm in the scenario
#
# Arguments:
# - vm name
# - seq command sequence
#
# Returns:
# - list of commands to execute in the virtual machine after <exec> processing
###########################################################
sub execCommands{
my $self = shift;
my $vm = shift;
my $seq = shift;
my @commands;
my $type;
my $subtype;
my $zebra_bin = "";
my $ospfd_bin = "";
my $virtualmList=$globalNode->getElementsByTagName("vm");
my $longitud = $virtualmList->getLength;
for (my $m=0; $m<$longitud; $m++){
my $virtualm = $virtualmList->item($m);
my $virtualm_name = $virtualm->getAttribute("name");
if ( $vm eq $virtualm_name){
$type = $virtualm->getAttribute("type");
$subtype = $virtualm->getAttribute("subtype");
my $zebraBinTagList = $virtualm->getElementsByTagName("zebra_bin");
my $longitudZebra = $zebraBinTagList->getLength;
if ($longitudZebra == 1){
$zebra_bin = $zebraBinTagList->item($0)->getFirstChild->getData;
}
my $ospfdBinTagList = $virtualm->getElementsByTagName("ospfd_bin");
my $longitudOspfd = $ospfdBinTagList->getLength;
if ($longitudOspfd == 1){
$ospfd_bin = $ospfdBinTagList->item($0)->getFirstChild->getData;
}
switch ($type) {
case "quagga"{
switch ($subtype){
case "lib-install"{
if ($zebra_bin eq ""){
$zebra_bin = "/usr/lib/quagga/zebra";
}
if ($ospfd_bin eq ""){
$ospfd_bin = "/usr/lib/quagga/ospfd";
}
unshift (@commands, "");
}
case "sbin-install"{
if ($zebra_bin eq ""){
$zebra_bin = "/usr/sbin/zebra";
}
if ($ospfd_bin eq ""){
$ospfd_bin = "/usr/sbin/ospfd";
}
unshift (@commands, "");
} else {
unshift (@commands, "Your choice $subtype is not a recognized subtype (yet)\n");
}
}
} else {
unshift (@commands, "Your choice $type is not a recognized type (yet)\n");
}
}
if (($seq eq "start") || ($seq eq "ospf-start")){
push (@commands, "$zebra_bin -d");
push (@commands, "$ospfd_bin -d");
}elsif(($seq eq "restart") || ($seq eq "ospf-restart")){
push (@commands, "killall zebra");
push (@commands, "killall ospfd");
push (@commands, "$zebra_bin -d");
push (@commands, "$ospfd_bin -d");
}elsif(($seq eq "stop") || ($seq eq "ospf-stop")){
push (@commands, "killall zebra");
push (@commands, "killall ospfd");
}
}
}
return @commands;
}
sub finalizePlugin{
}
sub shutdownCommands{
}
#############################################################
#
# Checks existence and semantics in ospf conf file.
# Currently this check consist in:
#
# 1. Configuration file exists.
# 2. Check DTD.
#
#############################################################
sub checkConfigFile{
# 1. Configuration file exists.
my $config_file = shift;
open(FILEHANDLE, $config_file) or {
return "cannot open config file $config_file\n",
};
close (FILEHANDLE);
# 2. Check DTD
my $parser = new XML::DOM::ValParser;
my $dom_tree;
$valid_fail = 0;
eval {
local $XML::Checker::FAIL = \&validation_fail;
$dom_tree = $parser->parsefile($config_file);
};
if ($valid_fail) {
return ("$config_file is not a well-formed OSPF plugin file\n");
}
$globalNode = $dom_tree->getElementsByTagName("ospf_conf")->item(0);
return 0;
}
sub validation_fail {
my $code = shift;
# To set flag
$valid_fail = 1;
# To print error message
XML::Checker::print_error ($code, @_);
}
1