diff --git a/tbsetup/snmpit.in b/tbsetup/snmpit.in
index a61aa397e08dbad9c525f341b0c7d314c9004f90..72d6e660a872ddec2ee6e99dc1aa5a049f8e26b1 100755
--- a/tbsetup/snmpit.in
+++ b/tbsetup/snmpit.in
@@ -43,6 +43,8 @@ sub usage {
 Usage: $0 [-h] [-v] [-n] [-i device]
 	  [-l] [-s] [-g]
 	  [-m name [ports]]
+	  [-T port name]
+	  [-U port]
 	  [-o name]
           [-r pid eid]
 	  [-t pid eid]
@@ -83,6 +85,9 @@ Port Control:
   -a <ports>             Enable auto-negotiation of port speed/duplex
   -p <10|100> <ports>    Set speed of <ports> to 10 or 100 Mbps
   -u <half|full> <ports> Set duplex of <ports> to half or full
+  -T <port> <names>      Enable trunking on the given <port>, and allow VLANs
+                             with the given <names> across it
+  -U <port>              Turn off trunking for the given <port>
 
 More than one operation can be specified - However, beware that the order in
 which operations will occur is undefined, and some combinations of operations
@@ -96,7 +101,7 @@ END
 my %opt = ();
 Getopt::Long::Configure("no_ignore_case");
 GetOptions(\%opt, 'a','c','d','e','g','h','i=s@','l','m=s@','M','n','o=s@',
-    'p=s','r','s','t','u=s','v','w','y=s','x=s','z=s');
+    'p=s','r','s','t','T=s','u=s','U','v','w','y=s','x=s','z=s');
 # Unused: b,f,j,q
 
 if ($opt{h}) {
@@ -133,11 +138,27 @@ if ($opt{t} || $opt{r}) {
     if (@ARGV) {
 	@optvlanids = @ARGV;
     }
-} elsif ($opt{d} || $opt{e} || $opt{a} || $opt{p} || $opt{u} || $opt{m}) {
+} elsif ($opt{d} || $opt{e} || $opt{a} || $opt{p} || $opt{u} || $opt{m}
+         || $opt{U}) {
     #
     # Options that take a list of ports
     #
     @ports = @ARGV;
+} elsif ($opt{T}) {
+    #
+    # Options that take both a port and a list of VLANs - we require at least
+    # one VLAN to be given
+    #
+    if (!@ARGV) {
+	warn "ERROR: At least one VLAN required";
+	exit &usage;
+    }
+    @optvlanids = @ARGV;
+
+    #
+    # Set the @ports array so that we'll do proper permission checking on it
+    #
+    @ports = ($opt{T});
 } else {
     #
     # Everything else
@@ -164,6 +185,7 @@ if ($opt{g}) { push @commands, ["getstats"]; }
 if ($opt{t}) { push @commands, ["tables"]; }
 if ($opt{r}) { push @commands, ["reset"]; }
 if ($opt{c}) { push @commands, ["recreate"]; }
+if ($opt{U}) { push @commands, ["trunkdisable"]; }
 
 #
 # Commands that can appear once, and take an agurment
@@ -171,6 +193,7 @@ if ($opt{c}) { push @commands, ["recreate"]; }
 if ($opt{d}) { push @commands, ["portcontrol","disable"]; }
 if ($opt{e}) { push @commands, ["portcontrol","enable"]; }
 if ($opt{a}) { push @commands, ["portcontrol","auto"]; }
+if ($opt{T}) { push @commands, ["trunkenable", $opt{T}]; }
 
 #
 # Commands that can occur more than once
@@ -375,7 +398,7 @@ foreach my $command (@commands) {
 	    @devicenames = $opt{i}? @{$opt{i}} : getTestSwitches();
 	    last;
 	};
-	(/portcontrol/) && do {
+	(/portcontrol/ || /trunkdisable/) && do {
 	    @devicenames = $opt{i}? @{$opt{i}} : getDeviceNames(@ports);
 	    last;
 	};
@@ -390,6 +413,11 @@ foreach my $command (@commands) {
 	    @devicenames = getTestSwitches();
 	    last;
 	};
+	(/trunkenable/) && do {
+	    @devicenames = $opt{i}? @{$opt{i}} : getDeviceNames(@ports);
+	    @vlans = @optvlanids;
+	    last;
+	}
     }
 
     debug("Device names: " . join(",",@devicenames) . "\n");
@@ -510,6 +538,15 @@ foreach my $command (@commands) {
 	    $exitval += doRecreateVlans(\@stacks);
 	    last;
 	};
+	/trunkenable/ && do {
+	    my ($port) = @args;
+	    $exitval += doTrunkEnable(\@stacks,$port,@vlans);
+	    last;
+	}; # /trunkenable/ && do
+	/trunkdisable/ && do {
+	    $exitval += doTrunkDisable(\@stacks,@ports);
+	    last;
+	}; # /trunkenable/ && do
     }
 }
 
@@ -1008,3 +1045,56 @@ sub doRecreateVlans($) {
     return 1;
 
 }
+
+#
+# Enable trunking on a port, and enable a set of VLANs on it 
+#
+sub doTrunkEnable($$@) {
+    my $stacks = shift;
+    my $port = shift;
+    my @vlans = @_;
+
+    #
+    # Sanity checking
+    #
+    if (@$stacks != 1) {
+	die "Enabling trunk ports should only involve one stack\n" .
+	    "Stacks are " . join(",",@$stacks) . "\n";
+    }
+
+    #
+    # Simple, just call the right function on the stack
+    #
+    my $stack = $$stacks[0];
+    print "Enabling trunking on $port ...\n";
+    return $stack->enableTrunking($port,@vlans);
+}
+
+#
+# Disable trunking on a port
+#
+sub doTrunkDisable($$) {
+    my $stacks = shift;
+    my $port = shift;
+
+    #
+    # Sanity checking
+    #
+    if (@$stacks != 1) {
+	die "Disabling trunk ports should only involve one stack\n" .
+	    "Stacks are " . join(",",@$stacks) . "\n";
+    }
+
+    #
+    # Simple, just call the right function on the stack
+    #
+    my $stack = $$stacks[0];
+    my $errors = 0;
+    foreach my $port (@ports) {
+	print "Disabling trunking on port $port ...\n";
+	if (!$stack->disableTrunking($port)) {
+	    $errors++;
+	}
+    }
+    return $errors;
+}
diff --git a/tbsetup/snmpit_cisco.pm b/tbsetup/snmpit_cisco.pm
index 33c13cef79cb1508694d313ab43e0e938c1f8ca1..7721ccebe54f0fd93ec65dd3eb2e86b1f70acef6 100644
--- a/tbsetup/snmpit_cisco.pm
+++ b/tbsetup/snmpit_cisco.pm
@@ -1311,7 +1311,7 @@ sub setVlansOnTrunk($$$$) {
 	die "VLAN 1 passed to setVlanOnTrunk\n"
     }
 
-    my $ifIndex = $self->{IFINDEX}{$modport};
+    my ($ifIndex) = $self->convertPortFormat($PORT_FORMAT_IFINDEX,$modport);
 
     #
     # If this is part of an EtherChannel, we have to find the ifIndex for the
@@ -1356,6 +1356,166 @@ sub setVlansOnTrunk($$$$) {
 
 }
 
+#
+# Clear the list of allowed VLANs from a trunk
+#
+# usage: clearAllVlansOnTrunk(self, modport)
+#        modport: module.port of the trunk to operate on
+#        Returns 1 on success, 0 otherwise
+#
+sub clearAllVlansOnTrunk($$) {
+    my $self = shift;
+    my ($modport) = @_;
+
+    my ($ifIndex) = $self->convertPortFormat($PORT_FORMAT_IFINDEX,$modport);
+
+    #
+    # If this is part of an EtherChannel, we have to find the ifIndex for the
+    # channel.
+    # TODO: Perhaps this should be general - ie. $self{IFINDEX} should have
+    # the channel ifIndex the the port is in a channel. Not sure that
+    # this is _always_ beneficial, though
+    #
+    my $channel = snmpitGetFatal($self->{SESS},["pagpGroupIfIndex",$ifIndex]);
+    if (($channel =~ /^\d+$/) && ($channel != 0)) {
+	$ifIndex = $channel;
+    }
+
+    #
+    # Get the exisisting bitfield for allowed VLANs on the trunk
+    #
+    my $bitfield = snmpitGetFatal($self->{SESS},
+	    ["vlanTrunkPortVlansEnabled",$ifIndex]);
+    my $unpacked = unpack("B*",$bitfield);
+    
+    # Put this into an array of 1s and 0s for easy manipulation
+    my @bits = split //,$unpacked;
+
+    # Clear the bit for every VLAN
+    foreach my $index (0 .. $#bits) {
+	$bits[$index] = 0;
+    }
+
+    # Pack it back up...
+    $unpacked = join('',@bits);
+
+    $bitfield = pack("B*",$unpacked);
+
+    # And save it back...
+    my $rv = $self->{SESS}->set(["vlanTrunkPortVlansEnabled",$ifIndex,$bitfield,
+    	    "OCTETSTR"]);
+    if ($rv) {
+	return 1;
+    } else {
+	return 0;
+    }
+
+}
+
+#
+# Enable trunking on a port
+#
+# usage: enablePortTrunking(self, modport, nativevlan)
+#        modport: module.port of the trunk to operate on
+#        nativevlan: VLAN number of the native VLAN for this trunk
+#        Returns 1 on success, 0 otherwise
+#
+sub enablePortTrunking($$$) {
+    my $self = shift;
+    my ($port,$native_vlan) = @_;
+
+    my ($ifIndex) = $self->convertPortFormat($PORT_FORMAT_IFINDEX,$port);
+
+    #
+    # Clear out the list of allowed VLANs for this trunk port, so that when it
+    # comes up, there is not some race condition
+    #
+    my $rv = $self->clearAllVlansOnTrunk($port);
+    if (!$rv) {
+	warn "ERROR: Unable to clear VLANs on trunk\n";
+	return 0;
+    } 
+
+    #
+    # Set the type of the trunk - we only do dot1q for now
+    #
+    my $trunkType = ["vlanTrunkPortEncapsulationType",$ifIndex,"dot1Q","INTEGER"];
+    $rv = snmpitSetWarn($self->{SESS},$trunkType);
+    if (!$rv) {
+	warn "ERROR: Unable to set encapsulation type\n";
+	return 0;
+    }
+
+    #
+    # Set the native VLAN for this trunk
+    #
+    my $nativeVlan = ["vlanTrunkPortNativeVlan",$ifIndex,$native_vlan,"INTEGER"];
+    $rv = snmpitSetWarn($self->{SESS},$nativeVlan);
+    if (!$rv) {
+	warn "ERROR: Unable to set native VLAN on trunk\n";
+	return 0;
+    }
+
+    #
+    # Finally, enable trunking!
+    #
+    my $trunkEnable = ["vlanTrunkPortDynamicState",$ifIndex,"on","INTEGER"];
+    $rv = snmpitSetWarn($self->{SESS},$trunkEnable);
+    if (!$rv) {
+	warn "ERROR: Unable to enable trunking\n";
+	return 0;
+    }
+
+    #
+    # Allow the native VLAN to cross the trunk
+    #
+    if (!$rv) {
+	warn "ERROR: Unable to enable native VLAN on trunk\n";
+	return 0;
+    }
+
+
+    return 1;
+    
+}
+
+#
+# Disable trunking on a port
+#
+# usage: disablePortTrunking(self, modport)
+#        modport: module.port of the trunk to operate on
+#        Returns 1 on success, 0 otherwise
+#
+sub disablePortTrunking($$) {
+    my $self = shift;
+    my ($port) = @_;
+
+    my ($ifIndex) = $self->convertPortFormat($PORT_FORMAT_IFINDEX,$port);
+
+
+    #
+    # Clear out the list of allowed VLANs for this trunk port
+    #
+    my $rv = $self->clearAllVlansOnTrunk($port);
+    if (!$rv) {
+	warn "ERROR: Unable to clear VLANs on trunk\n";
+	return 0;
+    } 
+
+    #
+    # Disable trunking!
+    #
+    my $trunkDisable = ["vlanTrunkPortDynamicState",$ifIndex,"off","INTEGER"];
+    $rv = snmpitSetWarn($self->{SESS},$trunkDisable);
+    if (!$rv) {
+	warn "ERROR: Unable to enable trunking\n";
+	return 0;
+    }
+
+    return 1;
+    
+}
+
 #
 # Reads the IfIndex table from the switch, for SNMP functions that use 
 # IfIndex rather than the module.port style. Fills out the objects IFINDEX
diff --git a/tbsetup/snmpit_cisco_stack.pm b/tbsetup/snmpit_cisco_stack.pm
index 48d050a62156adb79586e11948ee0f6fc19c78cd..9a7afaea32220adbbdd113e4a7b01c7f8c859054 100644
--- a/tbsetup/snmpit_cisco_stack.pm
+++ b/tbsetup/snmpit_cisco_stack.pm
@@ -555,6 +555,111 @@ sub getStats($) {
     return map $stats{$_}, sort {tbsort($a,$b)} keys %stats;
 }
 
+#
+# Turns on trunking on a given port, allowing only the given VLANs on it
+#
+# usage: enableTrunking(self, port, vlan identifier list)
+#
+# returns: 1 on success
+# returns: 0 on failure
+#
+sub enableTrunking($$@) {
+    my $self = shift;
+    my $port = shift;
+    my @vlan_ids = @_;
+
+    #
+    # On a Cisco, the first VLAN given becomes the native VLAN for the trunk
+    #
+    my $native_vlan_id = shift @vlan_ids;
+    if (!$native_vlan_id) {
+	print STDERR "ERROR: No native VLAN passed to enableTrunking()!\n";
+	return 0;
+    }
+
+    #
+    # Grab the VLAN number for the native VLAN
+    #
+    my $vlan_number = $self->{LEADER}->findVlan($native_vlan_id);
+    if (!$vlan_number) {
+	print STDERR "ERROR: Native VLAN $native_vlan_id does not exist!\n";
+	return 0;
+    }
+
+    #
+    # Split up the ports among the devices involved
+    #
+    my %map = mapPortsToDevices($port);
+    my ($devicename) = keys %map;
+    my $device = $self->{DEVICES}{$devicename};
+    if (!defined($device)) {
+	warn "ERROR: Unable to find device entry for $devicename\n";
+	return 0;
+    }
+
+    #
+    # Simply make the appropriate call on the device
+    #
+    print "Enable trunking: Port is $port, native VLAN is $native_vlan_id\n"
+	if ($self->{DEBUG});
+    my $rv = $device->enablePortTrunking($port, $vlan_number);
+
+    #
+    # If other VLANs were given, add them to the port too
+    #
+    if (@vlan_ids) {
+	my %vlan_numbers = $self->{LEADER}->findVlans(@vlan_ids);
+	my @vlan_numbers;
+	foreach my $vlan_id (@vlan_ids) {
+	    #
+	    # First, make sure that the VLAN really does exist
+	    #
+	    my $vlan_number = $vlan_numbers{$vlan_id};
+	    if (!$vlan_number) {
+		warn "ERROR: VLAN $vlan_id not found on switch!";
+		next;
+	    }
+	    push @vlan_numbers, $vlan_number;
+	}
+	$device->setVlansOnTrunk($port,1,@vlan_numbers);
+    }
+
+    return $rv;
+
+}
+
+#
+# Turns off trunking for a given port
+#
+# usage: disableTrunking(self, ports)
+#
+# returns: 1 on success
+# returns: 0 on failure
+#
+sub disableTrunking($$) {
+    my $self = shift;
+    my $port = shift;
+
+    #
+    # Split up the ports among the devices involved
+    #
+    my %map = mapPortsToDevices($port);
+    my ($devicename) = keys %map;
+    my $device = $self->{DEVICES}{$devicename};
+    if (!defined($device)) {
+	warn "ERROR: Unable to find device entry for $devicename\n";
+	return 0;
+    }
+
+    #
+    # Simply make the appropriate call on the device
+    #
+    my $rv = $device->disablePortTrunking($port);
+
+    return $rv;
+
+}
+
 #
 # Not a 'public' function - only needs to get called by other functions in
 # this file, not external functions.