snmpit_intel_stack.pm 10.7 KB
Newer Older
1
#!/usr/bin/perl -w
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2 3

#
4
# Copyright (c) 2000-2003 University of Utah and the Flux Group.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# 
# {{{EMULAB-LGPL
# 
# This file is part of the Emulab network testbed software.
# 
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or (at
# your option) any later version.
# 
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
# License for more details.
# 
# You should have received a copy of the GNU Lesser General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
# 
# }}}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
24 25
#

26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#
# snmpit module for Intel EtherExpress 510T switches. This module is largely
# just a wrapper around snmpit_intel, but is here just in case we ever need to
# contact multiple switches (which may happen if we move to port-based (instead
# of MAC-based) VLANs.) For now, though, pretty much everything just calls
# $self->{LEADER}->foo()
#

package snmpit_intel_stack;
use strict;

$| = 1;				# Turn off line buffering on output

use English;
use SNMP;
use snmpit_lib;

use libdb;

#
# Creates a new object. A list of devices that will be operated on is given
# so that the object knows which to connect to. A future version may not 
# require the device list, and dynamically connect to devices as appropriate
#
# For an Intel stack, the stack_id happens to also be the name of the stack
# leader.
#
# usage: new(string name, string stack_id, int debuglevel list of devicenames)
# returns a new object blessed into the snmpit_intel_stack class
#

57
sub new($$$@) {
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

    # The next two lines are some voodoo taken from perltoot(1)
    my $proto = shift;
    my $class = ref($proto) || $proto;

    my $stack_id = shift;
    my $debuglevel = shift;
    my @devicenames = @_; # Devicenames are not presently needed for Intel
			  # stacks


    #
    # Create the actual object
    #
    my $self = {};

    #
    # Set up some defaults
    #
    if (defined $debuglevel) {
	$self->{DEBUG} = $debuglevel;
    } else {
	$self->{DEBUG} = 0;
    }

    #
    # The stackid just happens to also be leader of the stack
    # 
    $self->{STACKID} = $stack_id;

    #
    # We only need to create 1 snmpit_intel object, since we only have to
90 91 92
    # talk to one (for now) to do all the setup we need. We fall back on the
    # old behavior of using the stack name as the leader if the leader is not
    # set
93
    #
94 95 96 97 98 99
    my $leader_name = getStackLeader($stack_id);
    if (!$leader_name) {
        $leader_name = $stack_id;
    }
    $self->{LEADERNAME} = $leader_name;

100
    use snmpit_intel;
101 102 103 104 105 106 107 108 109 110 111 112
    $self->{LEADER} = new snmpit_intel($leader_name,$self->{DEBUG});

    #
    # Check for failed object creation
    #
    if (!$self->{LEADER}) {
        #
        # The snmpit_intel object has already printed an error message,
        # so we'll just return an error
        #
        return undef;
    }
113

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
    bless($self,$class);
    return $self;
}

#
# NOTE: See snmpit_cisco_stack for descriptions of these functions.
# XXX: Document these functions
#

sub listVlans($) {
    my $self = shift;

    return $self->{LEADER}->listVlans();
}

sub listPorts($) {
    my $self = shift;

    return $self->{LEADER}->listPorts();
}

sub setPortVlan($$@) {
    my $self = shift;
    my $vlan_id = shift;
    my @ports = @_;

    return $self->{LEADER}->setPortVlan($vlan_id,@ports);
}

143
sub createVlan($$$;@) {
144 145
    my $self = shift;
    my $vlan_id = shift;
146 147 148 149
    my @ports = @{shift()};
    #
    # We ignore other args for now, since Intels don't support private VLANs
    #
150

151
    return $self->{LEADER}->createVlan($vlan_id,@ports);
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

}

sub addDevicesToVlan($$@) {
    my $self = shift;
    my $vlan_id = shift;
    my @devicenames = @_; # Note: This is not used for Intel switches

    #
    # This function is not needed on Intel stacks, but it may be someday
    #
    if (!$self->vlanExists($vlan_id)) {
	return 1;
    }

    return 0;
}

sub vlanExists($$) {
    my $self = shift;
    my $vlan_id = shift;

174
    if ($self->{LEADER}->findVlan($vlan_id,1)) {
175 176 177 178 179 180
	return 1;
    } else {
	return 0;
    }
}

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
#
# Return a list of which VLANs from the input set exist on this stack
#
# usage: existantVlans(self, vlan identifiers)
#
# returns: a list containing the VLANs from the input set that exist on this
# 	stack
#
sub existantVlans($@) {
    my $self = shift;
    my @vlan_ids = @_;

    #
    # The leader holds the list of which VLANs exist
    #
    my %mapping = $self->{LEADER}->findVlans(@vlan_ids);

    my @existant = ();
    foreach my $vlan_id (@vlan_ids) {
	if (defined $mapping{$vlan_id}) {
	    push @existant, $vlan_id;
	}
    }

    return @existant;

}
208

209
sub removeVlan($@) {
210
    my $self = shift; 
211
    my @vlan_ids = @_;
212
		    
213 214 215 216 217 218 219 220 221 222 223 224 225 226
    my $errors = 0;
    foreach my $vlan_id (@vlan_ids) {
	#
	# First, make sure that the VLAN really does exist
	#
	my $vlan_number = $self->{LEADER}->findVlan($vlan_id);
	if (!$vlan_number) {
	    warn "ERROR: VLAN $vlan_id not found on switch!";
	    $errors++;
	}
	my $ok = $self->{LEADER}->removeVlan($vlan_id);
	if (!$ok) {
	    $errors++;
	}
227 228
    }

229
    return ($errors == 0);
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
}       

sub portControl ($$@) { 
    my $self = shift;
    my $cmd = shift;
    my @ports = @_;

    return $self->{LEADER}->portControl($cmd,@ports);
}

sub getStats($) {
    my $self = shift;

    return $self->{LEADER}->getStats();
}
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261


#
# Openflow enable function for Intel stack
# Till now it just report an error.
#
# enableOpenflow(self, vlan_id)
# return # of errors
#
sub enableOpenflow($$) {
    my $self = shift;
    my $vlan_id = shift;
    
    my $errors = 0;
    foreach my $devicename (keys %{$self->{DEVICES}})
    {
	my $device = $self->{DEVICES}{$devicename};
262 263 264 265 266 267 268 269 270
	my $vlan_number = $device->findVlan($vlan_id, 2);
	if (!$vlan_number) {
	    #
	    # Not sure if this is an error or not.
	    # It might be possible that not all devices in a stack have the given VLAN.
	    #
	    print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
	} else {
	    if ($device->isOpenflowSupported()) {
271
		print "Enabling Openflow on $devicename for VLAN $vlan_id".
272
		    "..." if $self->{DEBUG};
273 274 275

		my $ok = $device->enableOpenflow($vlan_number);
		if (!$ok) { $errors++; }
276 277 278 279 280 281 282 283
		else {print "Done! \n" if $self->{DEBUG};}
	    } else {
		#
		# TODO: Should this be an error?
		#
		warn "ERROR: Openflow is not supported on $devicename \n";
		$errors++;
	    }
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	}
    }
        
    return $errors;
}

#
# Disable Openflow
#
# disableOpenflow(self, vlan_id);
# return # of errors
#
sub disableOpenflow($$) {
    my $self = shift;
    my $vlan_id = shift;
    
    my $errors = 0;
    foreach my $devicename (keys %{$self->{DEVICES}})
    {
	my $device = $self->{DEVICES}{$devicename};
304 305 306 307 308 309 310 311 312
	my $vlan_number = $device->findVlan($vlan_id, 2);
	if (!$vlan_number) {
	    #
	    # Not sure if this is an error or not.
	    # It might be possible that not all devices in a stack have the given VLAN.
	    #
	    print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
	} else {
	    if ($device->isOpenflowSupported()) {
313
		print "Disabling Openflow on $devicename for VLAN $vlan_id".
314
		    "..." if $self->{DEBUG};
315 316 317

		my $ok = $device->disableOpenflow($vlan_number);
		if (!$ok) { $errors++; }
318 319 320 321 322 323 324 325
		else {print "Done! \n" if $self->{DEBUG};}
	    } else {
		#
		# TODO: Should this be an error?
		#
		warn "ERROR: Openflow is not supported on $devicename \n";
		$errors++;
	    }
326 327 328 329 330 331 332 333 334 335 336 337
	}
    }
        
    return $errors;
}

#
# Set Openflow controller on VLAN
#
# setController(self, vlan_id, controller);
# return # of errors
#
338
sub setOpenflowController($$$) {
339 340 341 342 343 344 345 346
    my $self = shift;
    my $vlan_id = shift;
    my $controller = shift;
    
    my $errors = 0;
    foreach my $devicename (keys %{$self->{DEVICES}})
    {
	my $device = $self->{DEVICES}{$devicename};
347 348 349 350 351 352 353 354 355
	my $vlan_number = $device->findVlan($vlan_id, 2);
	if (!$vlan_number) {
	    #
	    # Not sure if this is an error or not.
	    # It might be possible that not all devices in a stack have the given VLAN.
	    #
	    print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
	} else {
	    if ($device->isOpenflowSupported()) {
356
		print "Setting Openflow controller on $devicename for VLAN $vlan_id".
357
		    "..." if $self->{DEBUG};
358

359
		my $ok = $device->setOpenflowController($vlan_number, $controller);
360
		if (!$ok) { $errors++; }
361 362 363 364 365 366 367 368
		else {print "Done! \n" if $self->{DEBUG};}
	    } else {
		#
		# TODO: Should this be an error?
		#
		warn "ERROR: Openflow is not supported on $devicename \n";
		$errors++;
	    }
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	}
    }
        
    return $errors;
}

#
# Set Openflow listener on VLAN
#
# setListener(self, vlan_id, listener);
# return # of errors
#
# This function might be replaced by a enableListener(vlan_id)
# that sets the listener on switches automatically and returns
# the listener connection string.
#
385
sub setOpenflowListener($$$) {
386 387 388 389 390 391 392 393
    my $self = shift;
    my $vlan_id = shift;
    my $listener = shift;
    
    my $errors = 0;
    foreach my $devicename (keys %{$self->{DEVICES}})
    {
	my $device = $self->{DEVICES}{$devicename};
394 395 396 397 398 399 400 401 402
	my $vlan_number = $device->findVlan($vlan_id, 2);
	if (!$vlan_number) {
	    #
	    # Not sure if this is an error or not.
	    # It might be possible that not all devices in a stack have the given VLAN.
	    #
	    print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
	} else {
	    if ($device->isOpenflowSupported()) {
403
		print "Setting Openflow listener on $devicename for VLAN $vlan_id".
404
		    "..." if $self->{DEBUG};
405

406
		my $ok = $device->setOpenflowListener($vlan_number, $listener);
407
		if (!$ok) { $errors++; }
408 409 410 411 412 413 414 415 416
		else {print "Done! \n" if $self->{DEBUG};}
	    } else {
		#
		# TODO: Should this be an error?
		#
		warn "ERROR: Openflow is not supported on $devicename \n";
		$errors++;
	    }
	}	
417 418 419 420
    }
        
    return $errors;
}
421

422 423 424
#
# Get used Openflow listener ports
#
425 426
# getUsedOpenflowListenerPorts(self, vlan_id)
#
427 428
sub getUsedOpenflowListenerPorts($$) {
    my $self = shift;
429 430
    my $vlan_id = shift;
    my %ports = ();
431 432 433 434

    foreach my $devicename (keys %{$self->{DEVICES}})
    {
	my $device = $self->{DEVICES}{$devicename};
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
	my $vlan_number = $device->findVlan($vlan_id, 2);
	if (!$vlan_number) {
	    #
	    # Not sure if this is an error or not.
	    # It might be possible that not all devices in a stack have the given VLAN.
	    #
	    print "$device has no VLAN $vlan_id, ignore it. \n" if $self->{DEBUG};
	} else {
	    if ($device->isOpenflowSupported()) {		
		my %tmports = $device->getUsedOpenflowListenerPorts();
		@ports{ keys %tmports } = values %tmports;		
	    } else {
		#
		# YES this be an error because the VLAN is on it.
		#
		warn "ERROR: Openflow is not supported on $devicename \n";
	    }
	}	
453
    }
454 455

    return %ports;
456 457
}

458 459
# End with true
1;