cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
3981
Views
5
Helpful
9
Replies

Identify If VLAN is Applied to Switchports

How do I conclusively identify if a VLAN is applied to a trunk port?

 

I'm trying to configure a compliance policy in PRIME Infrastructure 3.2.  I can base it on the running-config, or the output of a command (I'm a bit new to PRIME compliance policies/profiles... there might be other ways but this is all I've figured out so far).

 

The specific policy I'm trying to determine, is if there is a VLAN defined, but not applied to any physical switchport (I'm only concerning myself with transparent bridges, specifically Catalyst 3850 and 9300 running 16.6).

 

I'm not worried about removing VLANs from a port that's no longer in-use (either the port no longer in use, or the VLAN no longer needed on a trunk).  That will be a compliance profile developed later.

 

I've pretty much got access ports licked; I'm not worrying about nuances regarding ports configured with switchport monitor or switchport capture; I'm not worrying about the trunk native VLANs or voice VLANs; and I'm assuming zero private vlans on any campus.

 

But how do I identify trunk ports that use a VLAN?

 

Specifically, if I were to issue any combination of "show" command (though I'm open to any suggestion including non-show commands, or a different approach within PRIME compliance), I want to accept VLAN 700 as "in-use" by these three ports.  How would I do that?

 

interface GigabitEthernet1/0/1
switchport mode trunk
switchport trunk allowed vlan 699-701
shutdown
!
interface GigabitEthernet1/0/2
description Port is either not patched, or other end is turned off
switchport mode trunk
switchport trunk allowed vlan 699-701
no shutdown
!
interface GigabitEthernet1/0/3
description Port is in state "up/up"
switchport mode trunk
switchport trunk allowed vlan 699-701
no shutdown

 

Any ideas?

 

weylin

2 Accepted Solutions

Accepted Solutions

Or, you can write a tcl script to perform a "show" in for loop and ... do something.

 

Regards.

View solution in original post

My first attempt I would compare to software that a high schooler might produce.  I decided I didn't like it, so I re-wrote it (also, a software upgrade broke the script, so I needed to anyway).

 

This also catches the issue about this interface config:

! switchport access 1 is default, so not shown
! therefor this is an access port on vlan 1, and the "switchport trunk" command is non-functional
interface Gi0/0/1
  switchport mode access
  switchport trunk vlan allowed 17-19
shutdown

 

This script to me feels like 2nd- or 3rd-year undergrad quality.

 

#!/usr/bin/tclsh

# no idea why: hast-tags at the beginning of the line is treated as an invalid command in Cisco's TCL shell
# luckily it has effect on the actual execution of the script and the error can be safely ignored

###########################################
###########################################
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
###
### change this list of VLANs to define search criteria
### this should (in theory) be the only change necessary
### all other criteria should be auto-detected
###
### example:
### set VLAN_MATCH_LIST {367 368 369 703}
###########################################
###########################################
set VLAN_MATCH_LIST {27 367 368 369 703}

###########################################
###########################################
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
###
### once VLAN_MATCH_LIST is defined,
### copy/paste this entire script into tclsh of any NX-OS device
### it will then auto-execute with no further input required
###########################################
###########################################

# return the access vlan applied to interface
# this will happily execute on a non-access interface and return results, it's incumbent on the calling function to check for that
proc getaccessvlan {iFace} {
  set FullOpState [cli "show interface $iFace switchport"]
  regexp -line -all {Access Mode VLAN.*} $FullOpState OpStatement
  set AccessVLAN [regsub {.*Access Mode VLAN: ([[:digit:]]*).*} $OpStatement {\1}]
  return $AccessVLAN
}

# return a list of VLANs in vlan_list that are applied trunk-mode interface
# this will happily execute on a non-trunk interface and return results, it's incumbent on the calling function to check for that
proc gettrunkvlanlist {interface vlan_list} {
  set return_list {}

  # get list of VLANs in Cisco-format
  set FullOpState [cli "show interface $interface switchport"]
  regexp -line -all {Trunking VLANs Allowed.*} $FullOpState OpStatement
  set InterfaceVlans [regsub {.*Trunking VLANs Allowed: ([[:digit:]\,\-]*).*} $OpStatement {\1}]

  # expand VLAN ranges into individual VLANs
  # end result is comma-delimited list of VLANs applied to the interface
  foreach VlanGroup [split [string trim $InterfaceVlans] ","] {
    if {[llength [split $VlanGroup "-"]] == 1} {
      # individual VLAN
      lappend InterfaceVlansExpanded $VlanGroup

    } else {
      # VLAN range
      set FirstVLAN [lindex [split $VlanGroup -] 0]
      set LastVLAN  [lindex [split $VlanGroup -] 1]
      for {set i $FirstVLAN} {$i <= $LastVLAN} {incr i} {
        lappend InterfaceVlansExpanded $i
      }
    }
  }

  # InterfaceVlansExpanded is now a list of VLANs (1 VLAN per list element)
  foreach VLAN $InterfaceVlansExpanded {
    if {[lsearch $vlan_list $VLAN] != -1} {
      lappend return_list $VLAN
    }
  }

  return $return_list
}
puts [gettrunkvlanlist Eth1/48 $VLAN_MATCH_LIST]

# get the operational mode of an interface
proc GetInterfaceMode {iFace} {
  set FullOpState [cli "show interface $iFace switchport"]
  regexp -line -all {Operational Mode.*} $FullOpState ModeStatement
  set OpMode [regsub {Operational Mode: (.*)} $ModeStatement {\1}]
  return $OpMode
}

# get the list of physical interfaces on the system, return them as a list
proc GetInterfaces {} {
  set RunningConfig [cli "show running-config"]

  foreach InterfaceInConfig [regexp -inline -line -all {^interface Eth.*} $RunningConfig] {
    lappend ListOfInterfaces [regsub {.*(Ethernet\w*)} $InterfaceInConfig {\1}]
  }

  return $ListOfInterfaces
}

# begin main function

set output {"================\nSTART EVALUATION HERE\n================"}

foreach interface [GetInterfaces] {
   puts "evaluating interface $interface\n"
   set int_mode [GetInterfaceMode $interface]
   puts "Interface mode: $int_mode"
   if {$int_mode eq "access"} {
      set access_vlan [getaccessvlan $interface]
      puts "Access VLAN: $access_vlan"
      if {[lsearch $VLAN_MATCH_LIST $access_vlan] != -1} { lappend output "$interface is an access port on VLAN of concern: $access_vlan" }

   } elseif {$int_mode eq "trunk"} {
      set trunk_matched_vlan_list [gettrunkvlanlist $interface $VLAN_MATCH_LIST]
      puts "VLANs matched on trunk: $trunk_matched_vlan_list"
      if {[llength $trunk_matched_vlan_list] > 0} { lappend output "$interface is a trunk port, that includes these VLANs of concern: $trunk_matched_vlan_list" }

   } elseif {$int_mode eq "fex-fabric"} {
      continue
   } elseif {$int_mode eq "FabricPath"} {
      continue
   } else {
      puts "$interface indeterminate mode"
      lappend output "$interface is indeterminate"
   }
}

#puts $output
foreach line $output {
  puts "$line"
}

View solution in original post

9 Replies 9

Hello

 

 

 


@weylin.piegorsch wrote:

How do I conclusively identify if a VLAN is applied to a trunk port?

 

I'm not worried about removing VLANs from a port that's no longer in-use (either the port no longer in use, or the VLAN no longer needed on a trunk). 

 

But how do I identify trunk ports that use a VLAN?

 


sh interface trunk  <--- will show you what vlans are allowed to traverse the, that are currently active and the trunk ports relative spanning-tree state

sh vlan brief <----- will show what ports are assigned to each vlan

sh interface switchport | in Trunk|Prun <----  What vlans are allowed to traverse the trunk and what vlans are edgible to be pruned.


Please rate and mark as an accepted solution if you have found any of the information provided useful.
This then could assist others on these forums to find a valuable answer and broadens the community’s global network.

Kind Regards
Paul

Any interesting start, but incomplete.  Your suggestion could be made even easier by testing if there are any interfaces on that VLAN in the STP domain.

 

nseg-lab-es15#show spanning-tree vlan 700
 
VLAN0700
  Spanning tree enabled protocol rstp
  Root ID    Priority    12988
             Address     001e.f6e2.c400
             Cost        20000
             Port        25 (GigabitEthernet1/1/1)
             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec
 
  Bridge ID  Priority    33468  (priority 32768 sys-id-ext 700)
             Address     6899.cde6.6780
             Hello Time   2 sec  Max Age 20 sec  Forward Delay 15 sec
             Aging Time  300 sec
 
Interface           Role Sts Cost      Prio.Nbr Type
------------------- ---- --- --------- -------- --------------------------------
Gi1/0/7             Desg FWD 20000     128.7    P2p Edge
Gi1/0/8             Desg FWD 20000     128.8    P2p Edge
Gi1/1/1             Root FWD 20000     128.25   P2p
 
 
nseg-lab-es15#

 

That's an easy test for ports that are in an "up/up" state.  But what about ports that are shutdown?  They won't be in the spanning-tree domain.  This next example is on the same switch, you can see above that Gi1/1/2 is not in spanning-tree on this VLAN.

 

nseg-lab-es15#show running-config interface GigabitEthernet 1/1/2
Building configuration...
 
Current configuration : 388 bytes
!
interface GigabitEthernet1/1/2
switchport trunk native vlan 4
switchport trunk allowed vlan 699-701
switchport mode trunk
switchport nonegotiate
device-tracking attach-policy DT_NETWORK
shutdown
history BPS all
udld port aggressive
no vtp
spanning-tree guard root
service-policy input qos-ingress-marking
service-policy output qos-egress-uplink
ip dhcp snooping trust
end
 
nseg-lab-es15#

 

And, that same port doesn't show anything in "show interface trunk":

 

nseg-lab-es15#show interfaces GigabitEthernet 1/1/2 trunk 
 
Port        Mode             Encapsulation  Status        Native vlan
Gi1/1/2     on               802.1q         other         4
 
Port        Vlans allowed on trunk
Gi1/1/2     none
 
Port        Vlans allowed and active in management domain
Gi1/1/2     none
 
Port        Vlans in spanning tree forwarding state and not pruned
Gi1/1/2     none
nseg-lab-es15#

 

"show vlan brief" doesn't highlight this either:

 

nseg-lab-es15#show vlan brief | section ^700
700  VLAN0700                         active    Gi1/0/2, Gi1/0/3, Gi1/0/7, Gi1/0/8
nseg-lab-es15#

 

"show interface switchport" shows this, unfortunately while I can VISUALLY see it, I need something I can parse against a Regular Expression to test true/false if the VLAN is applied to the port.  "700" doesn't appear in the output (see highlighted line).

 

nseg-lab-es15#show interfaces GigabitEthernet 1/1/2 switchport | include Trunk|Prun
Administrative Trunking Encapsulation: dot1q
Negotiation of Trunking: Off
Trunking Native Mode VLAN: 4 (Unused_Ports, Suspended)
Trunking VLANs Enabled: 699-701
Pruning VLANs Enabled: 2-1001
nseg-lab-es15#

 

I'm flummoxed at this point, and am open to any ideas.

 

weylin

What about "show vlan" ?

The output is similar to this:

 

VLAN Name Status Ports
---- -------------------------------- --------- -------------------------------
1 default active Fa0/8, Fa0/11, Fa0/17

7 comm active Fa0/25
37 voice active
40 VOIP2 active Fa0/8, Fa0/11, Fa0/17, Fa0/18, Fa0/19, Fa0/20, Fa0/21, Fa0/22, Fa0/40

In this way you can see global configured vlan not used by any ports (in tmy example is the vlan 37).

 

Regards.

If you want an output with the list of active vlan configured on a port, you can use this statement:

 

show vlan brief | include ^3 | active    .

(there are 4 space between "active" and the dot)

show vlan brief | include ^3 | active    [A-Z]

(there are 4 space between "active" and the square)

show vlan brief | include ^3 | active.*[0-9]

 

Regards.

Or, you can write a tcl script to perform a "show" in for loop and ... do something.

 

Regards.

I ended up doing exactly that - writing a TCL script.  It's not perfect, but it got a similar job done that I pressingly needed it for.

That other task: write a change, that would be covered by my organization's formal change control process, to convert set of VLANs from {set a} to {set b}, where {set a} and {set b} had a strict 1:1 mapping.  This was for a Nexus environment using FEX and FabricPath, so the available switchport modes I needed to contend with were access, trunk, fabricpath, and fex-fabric.  It helped that all VLANs 1-4094 were configured, and pre-defined as mode fabricpath.

For this, I didn't need the script to identify the old -> new configuration, I just needed to identify mode trunk and mode access ports that were using VLANs in {set a}, and which VLANs each port used; and I could ignore ports that were mode fabricpath or mode fex-fabric.

Here's the script I rote.  Again - there's issues with the script and it would need to be cleaned up to use on a recurring basis.  But I only needed it one-time, and I haven't written "real" code in the 20years since I graduated college, so whatever.

This will output all the intermediary processing, since this is an in-line script.  invoking tclsh with a URL would drop all that, but due to the restrictions organizationally imposed for formal change control, I needed to avoid reliance on a remote (tftp:// or scp:// or whatever) or local (sup-bootdisk:// etc) datastore.

The command "cli" could be replaced with "exec" to make it more portable... eh good enough for here.

 

# no idea why, but every time a CLI output is captured, the first line never evaluates properly
# this script accounts for that by including a single extra line of input, and discarding it.
#
# the "counter" trick used here is ugly, but works since the loops always re-start when counter=1

set VLAN_SET_A [list 102 122 232 242 243 246 259 283 286 288 334 341 346 356 358 373 375 385 405 406 410 411 421]

proc getaccessvlan {interface} {
  set counter 0
  foreach line [cli "show interface $interface switchport | inc Switchport:|Access.Mode.VLAN | cut -d ' ' -f 6"] {
    if {$counter == 0} {
      set counter 1
      continue
    }
    return [string trim $line]
  }
}

proc gettrunkvlanlist {interface} {
  global VLAN_SET_A
  set return_list {}

  set counter 0
  foreach line [cli "show interface $interface switchport | inc Switchport:|Trunking.VLANs.Allowed | cut -d ' ' -f 6"] {
    if {$counter == 0} {
      set counter 1
      continue
    }
    foreach vlan_in_list [split [string trim $line] ","] {
      if {[llength [split $vlan_in_list "-"]] == 1} {
        if {[lsearch $VLAN_SET_A $vlan_in_list] != -1} {
          lappend return_list $vlan_in_list
        }
      } else {
        set vlan_to_add [lindex [split $vlan_in_list "-"] 0]
        while {$vlan_to_add <= [lindex [split $vlan_in_list "-"] 1]} {
          if {[lsearch $VLAN_SET_A $vlan_to_add] != -1} {
            lappend return_list $vlan_to_add
          }
          incr vlan_to_add
        }
      }
    }
  }
  return $return_list
}

set output {"================\nSTART EVALUATION HERE\n================"}

# begin main function
set counter 0
foreach interface [cli "sh int status | inc ^\[EP\] | egrep inv \"f-path| 1 \" | cut -d ' ' -f 1"] {
  if {$counter == 0} {
    set counter 1
    continue
  }

  set counter 0
puts "evaluating interface $interface"
  foreach int_mode [cli "show interface $interface switchport | inc \"Operational.Mode:|Switchport:\" | cut -d ' ' -f 5"] {
    if {$counter == 0} {
      set counter 1
      continue

    } else {
      set int_mode [string trim "$int_mode"]

      if {$int_mode eq "access"} {
        set access_vlan [getaccessvlan "$interface"]
        if {[lsearch $VLAN_SET_A $access_vlan] != -1} { lappend output "$interface is an access port on VLAN of concern: $access_vlan" }

      } elseif {$int_mode eq "trunk"} {
        set trunk_vlan_list [gettrunkvlanlist "$interface"]
        if {[llength $trunk_vlan_list] > 0} { lappend output "$interface is a trunk port, that includes these VLANs of concern: $trunk_vlan_list" }

      } else { lappend output "$interface is indeterminate" }
    }
  }
}

foreach line $output {
  puts "$line"
}

 

 

My first attempt I would compare to software that a high schooler might produce.  I decided I didn't like it, so I re-wrote it (also, a software upgrade broke the script, so I needed to anyway).

 

This also catches the issue about this interface config:

! switchport access 1 is default, so not shown
! therefor this is an access port on vlan 1, and the "switchport trunk" command is non-functional
interface Gi0/0/1
  switchport mode access
  switchport trunk vlan allowed 17-19
shutdown

 

This script to me feels like 2nd- or 3rd-year undergrad quality.

 

#!/usr/bin/tclsh

# no idea why: hast-tags at the beginning of the line is treated as an invalid command in Cisco's TCL shell
# luckily it has effect on the actual execution of the script and the error can be safely ignored

###########################################
###########################################
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
###
### change this list of VLANs to define search criteria
### this should (in theory) be the only change necessary
### all other criteria should be auto-detected
###
### example:
### set VLAN_MATCH_LIST {367 368 369 703}
###########################################
###########################################
set VLAN_MATCH_LIST {27 367 368 369 703}

###########################################
###########################################
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
### ATTENTION USERS OF THIS SCRIPT
###
### once VLAN_MATCH_LIST is defined,
### copy/paste this entire script into tclsh of any NX-OS device
### it will then auto-execute with no further input required
###########################################
###########################################

# return the access vlan applied to interface
# this will happily execute on a non-access interface and return results, it's incumbent on the calling function to check for that
proc getaccessvlan {iFace} {
  set FullOpState [cli "show interface $iFace switchport"]
  regexp -line -all {Access Mode VLAN.*} $FullOpState OpStatement
  set AccessVLAN [regsub {.*Access Mode VLAN: ([[:digit:]]*).*} $OpStatement {\1}]
  return $AccessVLAN
}

# return a list of VLANs in vlan_list that are applied trunk-mode interface
# this will happily execute on a non-trunk interface and return results, it's incumbent on the calling function to check for that
proc gettrunkvlanlist {interface vlan_list} {
  set return_list {}

  # get list of VLANs in Cisco-format
  set FullOpState [cli "show interface $interface switchport"]
  regexp -line -all {Trunking VLANs Allowed.*} $FullOpState OpStatement
  set InterfaceVlans [regsub {.*Trunking VLANs Allowed: ([[:digit:]\,\-]*).*} $OpStatement {\1}]

  # expand VLAN ranges into individual VLANs
  # end result is comma-delimited list of VLANs applied to the interface
  foreach VlanGroup [split [string trim $InterfaceVlans] ","] {
    if {[llength [split $VlanGroup "-"]] == 1} {
      # individual VLAN
      lappend InterfaceVlansExpanded $VlanGroup

    } else {
      # VLAN range
      set FirstVLAN [lindex [split $VlanGroup -] 0]
      set LastVLAN  [lindex [split $VlanGroup -] 1]
      for {set i $FirstVLAN} {$i <= $LastVLAN} {incr i} {
        lappend InterfaceVlansExpanded $i
      }
    }
  }

  # InterfaceVlansExpanded is now a list of VLANs (1 VLAN per list element)
  foreach VLAN $InterfaceVlansExpanded {
    if {[lsearch $vlan_list $VLAN] != -1} {
      lappend return_list $VLAN
    }
  }

  return $return_list
}
puts [gettrunkvlanlist Eth1/48 $VLAN_MATCH_LIST]

# get the operational mode of an interface
proc GetInterfaceMode {iFace} {
  set FullOpState [cli "show interface $iFace switchport"]
  regexp -line -all {Operational Mode.*} $FullOpState ModeStatement
  set OpMode [regsub {Operational Mode: (.*)} $ModeStatement {\1}]
  return $OpMode
}

# get the list of physical interfaces on the system, return them as a list
proc GetInterfaces {} {
  set RunningConfig [cli "show running-config"]

  foreach InterfaceInConfig [regexp -inline -line -all {^interface Eth.*} $RunningConfig] {
    lappend ListOfInterfaces [regsub {.*(Ethernet\w*)} $InterfaceInConfig {\1}]
  }

  return $ListOfInterfaces
}

# begin main function

set output {"================\nSTART EVALUATION HERE\n================"}

foreach interface [GetInterfaces] {
   puts "evaluating interface $interface\n"
   set int_mode [GetInterfaceMode $interface]
   puts "Interface mode: $int_mode"
   if {$int_mode eq "access"} {
      set access_vlan [getaccessvlan $interface]
      puts "Access VLAN: $access_vlan"
      if {[lsearch $VLAN_MATCH_LIST $access_vlan] != -1} { lappend output "$interface is an access port on VLAN of concern: $access_vlan" }

   } elseif {$int_mode eq "trunk"} {
      set trunk_matched_vlan_list [gettrunkvlanlist $interface $VLAN_MATCH_LIST]
      puts "VLANs matched on trunk: $trunk_matched_vlan_list"
      if {[llength $trunk_matched_vlan_list] > 0} { lappend output "$interface is a trunk port, that includes these VLANs of concern: $trunk_matched_vlan_list" }

   } elseif {$int_mode eq "fex-fabric"} {
      continue
   } elseif {$int_mode eq "FabricPath"} {
      continue
   } else {
      puts "$interface indeterminate mode"
      lappend output "$interface is indeterminate"
   }
}

#puts $output
foreach line $output {
  puts "$line"
}

Nice script...

Thanks :-)

Review Cisco Networking for a $25 gift card