-
Notifications
You must be signed in to change notification settings - Fork 1
/
WritePortsDirectory.pm
211 lines (187 loc) · 7.17 KB
/
WritePortsDirectory.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
57
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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
208
209
210
211
package WritePortsDirectory;
use strict;
use Log::Log4perl qw(get_logger :levels);
use WriteUnusedDirectory;
use WritePoePortsFile;
use WriteSuspiciousPortsFile;
sub SpareHeader () {
return <<EHEAD;
<p>
This web page lists switches that do not have <i>spare ports</i> for
one or more VLANs.
</p>
<p>
<strong>What is a spare port?</strong><br>
A spare port is an inactive port that is configured for a VLAN other
than VLAN 1 (remember, VLAN 1 is for unused ports).
Spare ports are intentionally configured on real VLANs even though
there may be nothing actually connected to the port. Spare ports
have switch port labels that say "SPARE".
<p>
<strong>Why have spare ports?</strong><br>
We use spare ports for two reasons:
<ol>
<li>To speed up activations<br>
When a new connection needs to be made to a VLAN, we have to identify
the nearest switch to the site where the connection is needed, find
an unused port on the switch, configure the port onto the VLAN, and
connect a patch cable. Only then can the new connection be tested.
This process goes faster if there's already a spare port for the
VLAN on the switch.
</li>
<li>To provide on-site laptop access for network engineers<br>
When a network engineer is on-site, physically near a deployed switch,
s/he may need access to the switch's command-line interface. The
serial console port can be used to execute "show" commands and other
configuration commands, but doesn't provide access to the Internet
for email or to tftp new software into the switch. By permanently
allocating a known port on each switch as a spare, physical access
to switches is enhanced.
</ol>
<p>
This web page lists, for each switch, the number of ports configured
in each VLAN and and the number of such ports that are inactive. To
use it, find the switch you want, scan across to the column for the
VLAN you want, and see the total ports configured in the VLAN and the
number of those ports that are inactive (spare). To find the actual
spare port(s), click on the switch name and manually search by VLAN
number.
<p>
EHEAD
}
sub SpareSubtable ($$$) {
my $SwitchesRef = shift;
my $cut = shift;
my $VlanNbrSubListRef = shift;
my $logger = get_logger('log4');
$logger->debug("called");
my $RetVal;
my $StartingVlan = @$VlanNbrSubListRef[0];
my $EndingVlan = @$VlanNbrSubListRef[$cut-1];
$RetVal .= <<ETABLEHEAD;
<table class="Port">
<tr class="tblHead">
<th> Switch </th>
<th colspan="$cut"> ports on VLANs $StartingVlan through $EndingVlan (total : unused) </th>
</tr>
<tr class="tblHead"><th> </th><th>
ETABLEHEAD
$RetVal .= join '<th>', @$VlanNbrSubListRef;
$RetVal .= "</tr>\n";
foreach my $Switch (@$SwitchesRef) {
my $SwitchName = GetName $Switch;
next if $SwitchName =~ /^---/; # skip it if it's a group name
$RetVal .= "<tr><td> <a href=\"../switches/$SwitchName.html\">$SwitchName</a> </td>";
foreach my $VlanNbr (@$VlanNbrSubListRef) {
my $PortTuple = ' ';
my $Color = '';
if (exists $Switch->{PortCountByVlan}{$VlanNbr}) {
$PortTuple = $Switch->{PortCountByVlan}{$VlanNbr};
my $UnusedCount = 0;
if (exists $Switch->{UnusedPortCountByVlan}{$VlanNbr}) {
$UnusedCount = $Switch->{UnusedPortCountByVlan}{$VlanNbr};
}
$Color = " class=cellWarning" if $UnusedCount == 0;
$PortTuple .= ':' . $UnusedCount;
}
$RetVal .= "<td$Color>$PortTuple</td>";
}
$RetVal .= "</tr>\n";
}
$RetVal .= <<ETABLETAIL;
</table>
<p>
ETABLETAIL
$logger->debug("returning");
return $RetVal;
}
sub SpareTables ($$) {
my $SwitchesRef = shift; # passed in, list of Switch objects
my $VlansRef = shift; # passed in, hash of Vlan objects, indexed by Vlan number
my $logger = get_logger('log3');
$logger->debug("called");
my $RetVal = '';
my $MaxVlanColumns = 20;
my @SortedVlanNbrs = sort {$a <=> $b} keys %$VlansRef;
while (@SortedVlanNbrs) {
my $cut = $MaxVlanColumns;
my $NbrSortedVlans = $#SortedVlanNbrs + 1;
$cut = $NbrSortedVlans if $NbrSortedVlans < $MaxVlanColumns;
$logger->debug("cut = $cut");
my @VlanNbrSubList = splice(@SortedVlanNbrs, 0, $cut);
$RetVal .= SpareSubtable($SwitchesRef, $cut, \@VlanNbrSubList);
}
$logger->debug("returning");
return $RetVal;
}
sub WriteSparePortsFile ($$) {
my $SwitchesRef = shift; # passed in, list of Switch objects
my $VlansRef = shift; # passed in, hash of Vlans indexed by Vlan number
my $logger = get_logger('log2');
$logger->debug("called");
my $SparePortsFileName = File::Spec->catfile($Constants::PortsDirectory, $Constants::SparePortsFile);
open SPAREPORTSFILE, ">$SparePortsFileName" or do {
$logger->fatal("Couldn't open $SparePortsFileName for writing, $!");
exit;
};
$logger->info("writing $SparePortsFileName");
print SPAREPORTSFILE SwitchUtils::HtmlHeader("Spare Port Availability Report");
print SPAREPORTSFILE SpareHeader();
print SPAREPORTSFILE SpareTables($SwitchesRef, $VlansRef);
print SPAREPORTSFILE SwitchUtils::HtmlTrailer();
close SPAREPORTSFILE;
SwitchUtils::AllowAllToReadFile $SparePortsFileName;
$logger->debug("returning");
}
sub WritePortsIndexFile () {
my $logger = get_logger('log3');
my $PortsIndexFileName = File::Spec->catfile($Constants::PortsDirectory, 'index.html');
$logger->debug("called, writing $PortsIndexFileName");
open PORTSINDEXFILE, ">$PortsIndexFileName" or do {
$logger->fatal("Couldn't open $PortsIndexFileName for writing, $!");
exit;
};
print PORTSINDEXFILE SwitchUtils::HtmlHeader("Ports");
print PORTSINDEXFILE <<IDX1;
<ul>
<li><a href = "unused/index.html">Unused Ports</a></li>
<li><a href = "$Constants::SparePortsFile">Spare Ports</a></li>
<li><a href = "gigeportspervlan/index.html">Gigabit Ethernet Ports</a></li>
IDX1
if ($ThisSite::HasConfRooms) {
print PORTSINDEXFILE <<IDX2;
<li><a href = "../conference-search/">Conference room ports</a></li>
IDX2
}
print PORTSINDEXFILE <<IDX3;
<li><a href = "$Constants::PoeFile">Power-over-Ethernet Ports</a></li>
IDX3
if ($ThisSite::DnsDomain eq '.ucar.edu') { # only if we're at NCAR
print PORTSINDEXFILE <<IDX4;
<li><a href = "$Constants::PortLabelAnalysisFile">Port label analysis</a></li>
<li><a href = "$Constants::SuspiciousFile">Suspicious ports</a></li>
IDX4
}
print PORTSINDEXFILE <<IDX5;
</ul>
IDX5
print PORTSINDEXFILE SwitchUtils::HtmlTrailer();
close PORTSINDEXFILE;
SwitchUtils::AllowAllToReadFile $PortsIndexFileName;
$logger->debug("returning");
}
sub WritePortsDirectory ($$) {
my $SwitchesRef = shift; # passed in
my $VlansRef = shift; # passed in
my $logger = get_logger('log2');
$logger->debug("called");
SwitchUtils::SetupDirectory $Constants::PortsDirectory; # create or empty out the directory
WriteUnusedDirectory::WriteUnusedDirectory($SwitchesRef, $VlansRef);
WriteSparePortsFile($SwitchesRef, $VlansRef);
WriteGigePerVlansDirectory::WriteGigePerVlansDirectory($SwitchesRef, $VlansRef);
WritePoePortsFile::WritePoePortsFile($SwitchesRef);
WriteSuspiciousPortsFile::WriteSuspiciousPortsFile($SwitchesRef) if $ThisSite::DnsDomain eq '.ucar.edu'; # if we're at NCAR
WritePortsIndexFile();
$logger->debug("returning");
}
1;