Thursday, April 10, 2014

JNCIA -- Backing up Config Files

Okay, this is cool. You've set up your JunOS device (switch, router, whatever) just the way you want it, so you really should make a copy of the config so that, if the device ever fails, you can restore the configuration to replacement hardware with minimal effort (that whole, "the best sys admin is a lazy sys admin" thing again). Sure, after committing a config, you can always issue the commands to copy the config to an FTP server on your network, but, show of hands,...have you ever forgotten to do it? Look around -- everyone who didn't raise their hands is either very, very new to networking, or is lying ;)

Because we are all human, JunOS provides a very cool feature to work around the human limitation: a setting that dumps your config to an FTP server when you commit the config. Here's how you do it:

[edit]
root@branch-3200# edit system archival configuration

[edit system archival configuration]
root@branch-3200# transfer-on-commit;

[edit system archival configuration]
root@branch-3200# archive-sites {

[edit system archival configuration archive-sites]
"ftp://username:password@myftphost.example.com";


Of course, the ability to save your configuration is not terribly useful without the ability to restore it, so JunOS provides that ability, as well (natch):

[edit] root@branch-3200# edit system archival configuration

[edit system archival configuration]
root@branch-3200# load merge ftp://username:password@myftphost.example.com/branch-3200.conf.gz_20140410_111217

load complete

[edit system archival configuration]
root@branch-3200#


Wednesday, December 11, 2013

Configuring Port Security on a Foundry/Brocade FastIron Switch

I recently spoke with a user at a remote site on my network who was running into trouble getting on-line. During the troubleshooting session, I asked him to retrieve his IP address, and he gave me an address that was on a different subnet than I expected for his location. Puzzled, I asked a few follow-up questions, and found that he had connected a wireless router to my LAN switch at the remote site, a violation of our corporate compliance policies. In general, I'm not a fan of "Big Brother" IT/MIS policies, but in this case, I got a little torqued. This user is not MIS, he is not the guy who will get called out on the carpet if our network is breached because he didn't properly secure his wireless access point, and therefore, he is not supposed to be connecting wireless devices without explicit approval and knowledge of either me or one of the other network admins.

Unfortunately, this is not an uncommon occurrence. Fortunately, the Foundry FES2402 switches that we are using at these remote sites gives the network admin(s) some tools to help prevent users from connecting unauthorized devices to our networks.

The first tool is a simple MAC filter. In this case, there is a fixed number of devices that are supposed to be connected to our network, the MAC addresses of these devices are known, and therefore, we can create a filter to allow only these MAC addresses on a given port(s). Alternatively, if there is a known MAC address (or multiple addresses) that we *don't* want connected to a given port, we can create a filter to disallow it (or them). Here's how you do it:

  conf t
  mac filter 1 deny 0015.c507.ae6b ffff.ffff.ffff any
  mac filter 128 permit any any
    interface ethernet 7
      mac filter-group 1 128
      mac filter-group log-enable

This filter denies access from MAC address 0015.c507.ae6b to eth7, but allows access from all other MAC addresses.

Keep in mind that there are a few tips and a couple of "gotchas" in the simple MAC filter. First, just as when creating an Access Control List (ACL) or firewall rule for an IP address, you can filter for a portion of the MAC address, if you like:

  conf t
    mac filter 1 deny 0015.c507.ae6b ffff.0000.0000 any
    mac filter 128 permit any any
    interface ethernet 7
      mac filter-group 1 128
      mac filter-group log-enable

This will only match the "0015" portion of the given MAC address.

For a "gotcha," while there are many interface parameters that you can set using a range of Ethernet ports on a Foundry/Brocade switch, this isn’t one of them. For example, this…:

  conf t
  int eth 1 to 24
    mac filter-group 1 128
    mac filter-group log-enable

…doesn’t work. You can only apply a filter to a single interface at a time.

Another "gotcha" is that if you create multiple filters, then when applying the filters to an interface, you MUST include all of the filter groups on one line. If you try to put the filter groups on multiple lines, you will only get the LAST filter:

  conf t
  mac filter 1 deny 0015.c507.ae6b ffff.ffff.ffff any
  mac filter 128 permit any any
  int eth 7
      mac filter-group 1
      mac filter-group 128
      mac filter-group log-enable

This will result in ONLY filter 128 ("permit any any") being applied to the interface -- NOT AT ALL what you (presumably) intended.

The second tool is a lock that allows the admin to limit the number of devices that can access a given port on the switch. Unfortunately, this only sends an SNMP trap for a violation -- it does not actually disable the port or drop traffic from an unauthorized MAC address. Here's how you do it:

  conf t
  lock ethernet 15 addr-count 1

This applies a "lock" to allow only a single MAC address to eth 15 on a FES2402 switch. However, this isn't a terribly useful tool, as it only notifies the admin when someone attempts to attach an unauthorized device.

However, there is a third tool that takes the "lock" concept and gives it some teeth, so to speak. This is the MAC Port Security feature, and it can be applied either globally or directly to an Ethernet interface. Here is how you apply the MAC Port Security feature to a specific interface:

  conf t
  int eth 0/1/15
    port security
      enable
      maximum 1
      age 5
      violation restrict

In this example, we applied Port Security to Ethernet 0/1/15, enabled port security, set a maximum of 1 authorized IP address to this port, set the aging timer to drop the authorized IP address after 5 minutes (that is, if five minutes elapse without receiving a frame from a device, it will clear the MAC address entries for the interface, allowing a new device to connect), and telling the port to drop frames from any unrecognized device. You can set up to a maximum of 64 known MAC addresses per port. The aging timer can be set from zero (never time out a recognized MAC address) to 1440 minutes. The admin can choose between "restrict" and "shutdown" when a violation occurs; restrict will simply drop frames from an unknown device, whereas shutdown will disable the Ethernet interface for a specified period. If you choose "shutdown", then the next parameter is a number between 0 and 1440, where zero means shut down the port permanently, and any other number is the time to shut down the port, in minutes.

In addtion, you can manually specify allowed MAC addresses on the port, or you can configure to automatically discover and save allowed MAC addresses to the startup configuration. To manually specify an allowed MAC address:

  conf t
  int eth 0/1/15
    port security
      enable
      secure 0123.4567.89ab

This configuration manually specifies that only the device with the MAC address "0123.4567.89ab" should be allowed to access the port.

Alternatively, to have the Foundry auto-discover an allowed device, then write the MAC address to the startup configuration:

  conf t
  int eth 0/1/15
    port security
      enable
      autosave 60

This will automatically detect the MAC address of the device connected to the port and write its MAC address to the startup configuration every 60 minutes. Only that device will be allowed to connect from then on.

Wednesday, December 4, 2013

Brocade BCNP Resources

I recently found this post containing links to a number of resources for Brocade BCNP test preparation. I used the Brocade IP Primer to prepare for my BCNE, so I can verify that it's a great resource.

Thursday, November 14, 2013

JNCIA Lesson 4 1/2 -- More on Routing Policies and Firewall Filtering

One of the concepts that I have struggled with the most while trying to learn JunOS is the filtering language used on Juniper devices. That's a pretty significant problem too, because the filtering language is basically a core feature of JunOS, cropping up in Class of Service/Quality of Service, routing policies, and, of course, basic firewall/security on JunOS devices. It's pretty safe to say that if you don't understand this core concept, you will not be proficient in JunOS, and therefore, I decided I needed to spend a little while playing with the filtering syntax so I can understand it better. In it's most basic form, the filtering rules follow the pattern, "match-action" -- that is, you define a pattern to match, then upon a match, you perform some action on incoming packets -- and then you apply the filter to an interface or VLAN. There are three important concepts to keep in mind when trying to compose a filter rule:
  1. Within a single term, match rules are logical-AND'ed together. That is, if you put a rule to match a source IP address inside a term, then put a second rule to match a destination port, the filter will only match packets from that particular source IP address AND to that particular destination port (i.e., from 192.168.1.17, to port 23). If you want to logically OR rules, you have to create separate terms in the firewall rule-set;
  2. Packets are compared to each term from the top down, and the firewall stops comparing the packet to the firewall rules when it finds a match. In other words, if you put an "allow any" rule as the first term in your match rules, then put specific "deny ..." rules below, all packets will match against the "allow any" and no packet will ever be compared against the "deny ..." rules;
  3. There is an implicit "deny all" at the very end of the firewall rules, even though it is not shown in the configuration. Therefore, you must always make sure that you include rules to match all of the traffic that you want to allow. For example, suppose you are seeing brute-force password guessing attacks through SSH from the IP address 1.2.3.4, so you create a rule to drop traffic matching the source address of 1.2.3.4 and destination port 22. Unless you configure a rule to allow everything else, the implicit "deny all" rule will drop all traffic coming in on the interface or VLAN to which you applied the firewall rule.


Let's start with a simple example: suppose I have a switch on the 192.168.1.0/24 network, I have a host at 192.168.1.1, and on my switch, I want to block ICMP messages from that host with an "ICMP Administratively Prohibited" notification, while allowing any other protocol from 192.168.1.1 or all traffic from other source addresses.

root@branch-3200# set firewall family inet filter no-icmp term drop-icmp from source-address 192.168.1.1

[edit]
root@branch-3200# set firewall family inet filter no-icmp term drop-icmp from protocol icmp

[edit]
root@branch-3200# set firewall family inet filter no-icmp term drop-icmp then reject administratively-prohibited

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


If we attempt to ping 192.168.1.2 (the EX3200 switch) from 192.168.1.1 at this point, we will find the firewall isn't particularly effective:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
64 bytes from 192.168.1.2: icmp_seq=0 ttl=64 time=3.630 ms
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=2.408 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=2.395 ms
^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 2.395/2.811/3.630/0.579 ms

root@main3200>


Since we haven't applied the firewall to an interface or VLAN yet, no incoming packets are being compared against the firewall rules, and therefore all inbound traffic is still allowed. Let's take care of that, now:

root@branch-3200# set interfaces vlan unit 0 family inet filter input no-icmp

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


To create our firewall, we started by adding a rule that drops traffic only if the source address is 192.168.1.1. However, we only want to drop ICMP traffic, so we then added a second rule (with the same term name, namely "drop-icmp") that drops ICMP traffic. Since the terms are cumulative, we've essentially created a rule that says, "if the source address matches 192.168.1.1 AND the protocol is ICMP..." Then, we created an action to reject matching packets with the "administratively prohibited" message. Let's see how it works:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 d4e0   0 0000  40  01 2275 192.168.1.1  192.168.1.2
<...snip...>
^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
root@main3200>


Good, good...

root@main3200> telnet 192.168.1.2
Trying 192.168.1.2...
telnet: connect to address 192.168.1.2: Operation timed out
telnet: Unable to connect to remote host

root@main3200>


Hrmmm...Well, we're half-way there. We are successfully blocking ICMP, but apparently, we are also blocking telnet. Remember, JunOS adds an implicit "deny all" at the end of the firewall rules. Since we create a rule to block ICMP from 192.168.1.1, but we didn't include a rule to allow any packets, we are actually blocking ALL packets on vlan.0. To fix this, we have to add a new term to allow anything that isn't ICMP and from 192.168.1.1:

root@branch-3200# set firewall family inet filter no-icmp term everything-else source 0.0.0.0/0

[edit]
root@branch-3200# set firewall family inet filter no-icmp term everything-else then accept

[edit]
root@branch-3200# commit
commit complete

[edit]
root@branch-3200#


Let's see if that solves the problem:

root@main3200> ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2): 56 data bytes
36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f4c   0 0000  40  01 c809 192.168.1.1  192.168.1.2

36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f76   0 0000  40  01 c7df 192.168.1.1  192.168.1.2

36 bytes from 192.168.1.2: Communication prohibited by filter
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
4  5  00 0054 2f9c   0 0000  40  01 c7b9 192.168.1.1  192.168.1.2

^C
--- 192.168.1.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

root@main3200> telnet 192.168.1.2
Trying 192.168.1.2...
Connected to 192.168.1.2.
Escape character is '^]'.

branch-3200 (ttyp0)

login:
telnet> quit
Connection closed.

root@main3200>


That's more better :) We are now successfully blocking ICMP from 192.168.1.1 while still allowing other protocols, such as TCP/23 (telnet) to the switch.

However, looking at the firewall rules, something doesn't seem to be right. We have two rules to block source-address 192.168.1.1 and protocol ICMP, but the allow rule only specifies a source-address. How does this rule work?

Keep in mind that JunOS firewall rules work from top down, and they stop looking for matches as soon as a packet matches a term. Consequently, any packet originating from 192.168.1.1 and using the ICMP protocol matches our "reject ..." rule. However, if the packet comes from another source address or is a protocol other than ICMP, JunOS continues comparing the packet with the firewall rules. Therefore, anything not matching the "drop-icmp" term is compared to the "everything-else" term. The "everything-else" term tries to match the packet against the source-address of 0.0.0.0/0 -- in other words, against all possible source IP addresses. Since this second term will match a packet coming from any IP address, it is essentially an "allow any" rule. Therefore, our rule effectively reads, "if the packet matches 192.168.1.1 and matches the ICMP protocol, then reject it with the 'administratively-prohibited' message. If it is anything else, allow it."

Wednesday, November 13, 2013

JNCIA Lesson 8 -- Link Aggregation

In the lesson on Spanning Tree, we addressed the issue of redundancy, but what if your users are consuming more bandwidth than a single Gig-E uplink port can provide? STP/RSTP/MSTP allows you to connect multiple links between switches, but only ONE path can be active at any time, so you are still limited to 1Gbps between switches (assuming a Gig-E switch, of course).

Fortunately, there is a standardized protocol, known as "Link Aggregation Control Protocol" (LACP) or sometimes simply "LAG" (Link AGgregation) for creating bundled Ethernet links between switches. That is, in much the same way that a T1 line is a bundle of individual 64kbps lines that have been concatenated together to provide 1.544Mbps of bandwidth, there is also a way to bundle several individual Ethernet channels together to create a single, virtual channel with a bandwidth equal to the sum of the physical Ethernet links in the bundle. For example, if we were to take two Gig-E ports on our EX3200 switches and aggregate them together using LACP, we would have a 2Gbps (2 x 1Gbps) uplink between the switches. Even better, having multiple Ethernet ports in a LAG group provides not only increased bandwidth between switches, but also provides redundancy. If a single channel in the LAG group fails, the LAG bundle continues to carry traffic, albeit at a reduced rate.

Fortunately, it is very simple to create a LAG group between ports on the EX3200 switch, taking only four, easy steps:
  1. Create the virtual aggregated interface for the LAG group using the "set chassis aggregated-devices..." command (this will create a new interface, ae0, on the switch);
  2. Delete unit 0 in the interfaces that you want to bundle together;
  3. Use the "set interfaces...ether-options 802.3ad..." command to associate the physical interfaces that you want to aggregate with the virtual aggregated interface that you created in step 1; and
  4. Set the configuration options for the virtual aggregated interface with the "set interfaces...aggregated-ether-options..." and "set interfaces...family ethernet-switching" commands.
Let's set up a LAG group between ge-0/0/22 and ge-0/0/23 on two of our Juniper switches:

root@main3200# set chassis aggregated-devices ethernet device-count 1

[edit]
root@main3200# delete interfaces ge-0/0/22 unit 0

[edit]
root@main3200# delete interfaces ge-0/0/23 unit 0

[edit]
root@main3200# set interfaces ge-0/0/22 ether-options 802.3ad ae0

[edit]
root@main3200# set interfaces ge-0/0/23 ether-options 802.3ad ae0

[edit]
root@main3200# set interfaces ae0 aggregated-ether-options lacp active

[edit]
root@main3200# set interfaces ae0 unit 0 family ethernet-switching

[edit]
root@main3200# commit
commit complete

[edit]
root@main3200#
You now have a working LAG bundle between the switches, but if you try to ping from a host connected to one switch to a host connected on the other, you will find your pings failing with a "destination unreachable" error. Since you have multiple VLANs on the two switches, you will need to tag the VLANs on the aggregated Ethernet port, ae0, before hosts on the two switches can communicate with each other:

root@main3200# edit interfaces ae0 unit 0 family ethernet-switching

[edit interfaces ae0 unit 0 family ethernet-switching]
root@main3200# set port-mode trunk

[edit interfaces ae0 unit 0 family ethernet-switching]
root@main3200# set vlan members 20

[edit interfaces ae0 unit 0 family ethernet-switching]
root@main3200# set native-vlan-id default

[edit interfaces ae0 unit 0 family ethernet-switching]
root@main3200# commit
commit complete

[edit interfaces ae0 unit 0 family ethernet-switching]
root@main3200#


Now, connect a pair of Ethernet cables between the switches -- one from ge-0/0/22 on one switch to ge-0/0/22 on the second switch, and likewise for ge-0/0/23 -- and let's see if we can ping from a host on one switch to a host on the second switch:

me@myllt:~$ ping -c4 192.168.10.8
PING 192.168.10.8 (192.168.10.8) 56(84) bytes of data.
64 bytes from 192.168.10.8: icmp_req=1 ttl=64 time=0.795 ms
64 bytes from 192.168.10.8: icmp_req=2 ttl=64 time=0.502 ms
64 bytes from 192.168.10.8: icmp_req=3 ttl=64 time=0.519 ms
64 bytes from 192.168.10.8: icmp_req=4 ttl=64 time=0.501 ms

--- 192.168.10.8 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.501/0.579/0.795/0.125 ms
me@myllt:~$


Sweet! We have connectivity :) Now, let's see what happens when we pull an Ethernet cable:

me@myllt:~$ ping 192.168.10.8
PING 192.168.10.8 (192.168.10.8) 56(84) bytes of data.
64 bytes from 192.168.10.8: icmp_req=1 ttl=64 time=0.948 ms
64 bytes from 192.168.10.8: icmp_req=2 ttl=64 time=0.312 ms
64 bytes from 192.168.10.8: icmp_req=3 ttl=64 time=0.484 ms
64 bytes from 192.168.10.8: icmp_req=4 ttl=64 time=0.500 ms
64 bytes from 192.168.10.8: icmp_req=5 ttl=64 time=0.493 ms
64 bytes from 192.168.10.8: icmp_req=6 ttl=64 time=0.492 ms
64 bytes from 192.168.10.8: icmp_req=7 ttl=64 time=0.506 ms
64 bytes from 192.168.10.8: icmp_req=9 ttl=64 time=0.496 ms
64 bytes from 192.168.10.8: icmp_req=10 ttl=64 time=0.489 ms
64 bytes from 192.168.10.8: icmp_req=11 ttl=64 time=0.492 ms
64 bytes from 192.168.10.8: icmp_req=12 ttl=64 time=0.493 ms
64 bytes from 192.168.10.8: icmp_req=13 ttl=64 time=0.481 ms
64 bytes from 192.168.10.8: icmp_req=14 ttl=64 time=0.492 ms
64 bytes from 192.168.10.8: icmp_req=15 ttl=64 time=0.505 ms
^C
--- 192.168.10.8 ping statistics ---
15 packets transmitted, 14 received, 6% packet loss, time 13998ms
rtt min/avg/max/mdev = 0.312/0.513/0.948/0.129 ms
me@myllt:~$


Cool -- we only dropped one packet while the Junipers rerouted all of the traffic onto the good Ethernet link, and unlike STP/RSTP/MSTP, when both links are active, we can use all of the available bandwidth, rather than just a single 1Gbps link at a time.

Tuesday, November 12, 2013

JNCIA Lesson 7 -- DHCP

It is, perhaps, a little unfair that for many of these labs, I have been cheating slightly.

Don't get me wrong; I have configured all of the protocols and examples that we have discussed, and I have verified that the examples I have provided work as advertised. However, many of these examples have required that we connect one or more hosts to the various networks that we have built so that we can test end-to-end connectivity across the network(s). While there is certainly no reason why a network admin cannot configure such hosts by hand, I must confess that I do not like doing more work than is necessary. Again, do not be mislead; I am not claiming that I am unwilling to work when it is necessary, but rather I am saying that if there is an easy way to accomplish a task and a difficult way to accomplish a task, then, all else being equal, I will choose the easy way. To that end, when I have needed a PC connected to the Juniper switches to test connectivity, I have -- without providing you with the instructions on how to do likewise -- made use of the DHCP protocol to automatically assign IP addresses to my devices. I apologize, and in penance, I will endeavour to right that wrong in this lesson ;)

As I am sure you know -- or at least have by now guessed -- DHCP is a standard protocol for automatically assigning various network settings to computers on a LAN. Most obvious, of course, is the ability to automatically assign an IP address to a host on the network. However, DHCP can also assign a number of other settings such as the default gateway, DNS (name server) addresses, and domain name. Needless to say, the ability to automatically provision network settings to any device that connects to a LAN can be a huge time-saver for a busy network admin. Do you really want to visit the workstation of every user in your company first thing in the morning to assign an IP address for the day? Of course, not! Fortunately, this is another example of the kind of routine, mundane, repetitive task that computers perform extremely well, so let's set up our main office EX3200 to do so.

In one of the earlier lessons, we agreed that the default VLAN on our main3200 switch would use the network 192.168.1.0/24. However, we also stated that we would have a handful of network devices and servers on this network. Network devices almost always have their IP addresses assigned statically, as it becomes very difficult to configure your LAN equipment to reach a default gateway, for example, when the gateway address changes periodically. Servers, for exactly the same reason, often have statically assigned IP addresses also, and therefore, we will set aside the first 15 IP addresses -- 192.168.1.1 through 192.168.1.15 -- for servers and network equipment. Consequently, our DHCP server will assign addresses in the range 192.168.1.16 through 192.168.1.254 to client PCs. Also, our DNS servers for all three networks are located at 192.168.1.6 and 192.168.2.6; we'll assign those name server addresses to client PC's, as well. Let's get started:

root@main3200# edit system services

[edit system services]
root@main3200# set dhcp domain-name main.example.com

[edit system services]
root@main3200# set dhcp router 192.168.1.1

[edit system services]
root@main3200# set dhcp pool 192.168.1.0/24 address-range low 192.168.1.16 high 192.168.1.254

[edit system services]
root@main3200# set dhcp name-server 192.168.1.6

[edit system services]
root@main3200# set dhcp name-server 192.168.2.6

[edit system services]
root@main3200# commit
commit complete

[edit system services]
root@main3200#


That's it!

Now, hook up a PC to one of the ports in the default VLAN, and see if it obtains an address in the 192.168.1.0/24 net block:

me@myllt:~$ ip addr | egrep -A3 "eth0:"
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:24:e8:cb:f9:e9 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.16/24 brd 192.168.1.255 scope global eth0
    inet6 fd04:4879:556a:0:24:e8ff:fecb:f9e9/64 scope global
me@myllt:~$


Sweet! My laptop obtained the IP address 192.168.1.16/24 automatically from the DHCP service on the EX3200 switch!

However, we still have a problem. If you recall, we had planned not just one, but two VLANs on this physical network: the default VLAN for hosts like my laptop, but also a Voice-over-IP VLAN for our internal PBX. It's nice not to have to statically assign IP addresses to desktops and laptops, but wouldn't it be nice to also have DHCP hand off IP addresses automatically to the VoIP telephones, too?

Fortunately, that's not a problem, either. All we have to do is set up a separate DHCP pool using the same net block that we put the VoIP VLAN into:

root@main3200# set dhcp router 192.168.10.1

[edit system services]
root@main3200# set dhcp pool 192.168.10.0/24 address-range low 192.168.10.8 high 192.168.10.254

[edit system services]
root@main3200# set dhcp sip-server address 192.168.10.2

[edit system services]
root@main3200# commit
commit complete

[edit system services]
root@main3200#


Now, to test, we'll connect another laptop to one of the ports in the VoIP VLAN and see if we get a 192.168.10.xxx address:

me@myllt2:~$ ip addr | egrep -A3 "eth0:"
2: eth0: mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:15:c5:08:5d:92 brd ff:ff:ff:ff:ff:ff
    inet 192.168.10.8/24 brd 192.168.10.255 scope global eth0
    inet6 fd04:4879:556a:0:15:c5ff:fe08:5d92/64 scope global
me@myllt2:~$


Yep, it worked! We now have both the default VLAN and the VoIP VLAN receiving IP addresses automatically.

It's outside of the scope of this lesson, but just for grins, let's see if OSPF will route across the VLANs for us:

me@myllt2:~$ ping -c1 192.168.1.16
PING 192.168.1.16 (192.168.1.16) 56(84) bytes of data.
64 bytes from 192.168.1.16: icmp_req=1 ttl=63 time=1.82 ms

--- 192.168.1.16 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.822/1.822/1.822/0.000 ms
me@myllt2:~$


There's that "routing-on-a-stick" we discussed earlier in action for ya' ;)

JNCIA Lesson 6 -- Spanning Tree, Rapid Spanning Tree and Multiple Spanning Tree

In our network design, we have two EX3200 switches at the main office, connected through a single copper cross-over cable. A savvy network administrator would probably look at our design and ask, "What would happen if either Ethernet port, or more likely, the Ethernet cable itself were to fail?" The link from our main3200 switch to our main2-3200 switch is indeed a single point of failure on our network. Many a junior network admin have had the sudden realization that such a design is a problem waiting to happen, and in their eagerness to show how pro-active and fore-sighted they are, have then run a second Ethernet cable between the two switches in order to create a redundant connection between them.

If the junior admin was lucky, (s)he probably just spent a while wondering why one of the redundant Ethernet ports suddenly went off-line (had a customer do that to me once, on a Metro-Ethernet ring, in fact). If the junior admin was not so lucky, however, (s)he created a broadcast storm, crashing the entire Layer-2 network with (her)his well-intentioned, but naive, blunder:



In actual practice, the diagrams above are an over-simplification: if Switch A was actually sending a broadcast, it would have forwarded the frame out the ports to *both* Switch B and Switch C, and both Switch B and Switch C would have forwarded the broadcast frame to each other, resulting in multiple copies of the same frame circulating through the network simultaneously. In fact, if there are four or more switches in the network connected in a full-mesh network, then with every cycle there are more and more frames circulating through the network until the switches can no longer keep up with traffic (with three or less switches, the number of frames circulating won't grow, since the switches will not forward a broadcast back out the interface upon which it was received).

In our example with the junior admin, (her)his instincts were good; the network, as originally designed, was vulnerable to failure, and it would be a good idea to design a redundant path between switches, if there were a way to prevent such loops from occurring. Fortunately, this is exactly the type of problem that the Spanning Tree protocol (STP), and it's later refinements, Rapid Spanning Tree (RSTP) and Muliple Spanning Tree (MSTP), were designed to solve.

The method through with STP prevents loops is quite simple: essentially, the protocol just shuts down redundant network ports until/unless the switches in the tree detect a failure on an active port. In our example above, and assuming that Switch A was the "root bridge" (we'll define that term shortly), Spanning Tree (or RSTP or MSTP) would put one of the ports on either Switch B or Switch C into a "blocking" state, thus breaking the loop. Now, if Switch A sends a broadcast frame to Switches B and C, they will each forward the packet to devices connected to their switch ports, but NOT to each other.

This (simplified) explanation of Spanning Tree raises an important question: how do the switches determine if there is a loop, or if there is a network port which needs to be shut down? When a switch (or group of switches) is first powered on, it sends a query out each of its enabled switch ports, called a "Bridge Protocol Data Unit." Routers and PCs ignore the BPDU, but other switches examine the BPDU to check for loops in the layer-2 topology. Some of the data transferred during this process is used to elect a "root bridge" -- the switch that will be the pinnacle of the spanning tree network. As we've already stated, spanning tree will shut down ports to break loops in the layer-2 network, but the root bridge is special: all enabled ports on the root bridge always remain active. On any switches with a single port connected to the root bridge, those ports will also always remain active, and are known as "root ports." If there are multiple ports to the root bridge, the switch will select a single port as a root port, and shut down the rest. Any ports that spanning tree uses to reach other switches, but which do not provide a path for that switch to reach the root bridge will are called "designated ports." Confused yet? Let's look a drawing to try to make it a little clearer:



As you can see, all of the switch ports that are directly connected to Switch A are root ports, all of the switch ports in a forwarding state that are NOT directly connected to Switch A are designated ports, and the ports in a blocking state are non-designated ports.

One other question that might come to mind at this point is, "how do the switches determine which switch is the root bridge?" Spanning Tree uses two metrics for electing a root bridge: first, the admin can set a value known as "root bridge priority" when configuring spanning tree, and lowest priority wins; second, if two or more switches have the same priority, then the switch with the lowest MAC address wins. In JunOS, the root bridge priority and MAC address are concatenated into a single value known as the "root ID" which can be shown with the "show spanning-tree bridge" command:

root@main3200# run show spanning-tree bridge

STP bridge parameters
Context ID                          : 0
Enabled protocol                    : RSTP
<...snip...>
  Local parameters
    Bridge ID                       : 32768.3c:8a:b0:99:df:c1
<...snip...>
root@main3200#


As you can see, the root ID on this switch is 32768.3c:8a:b0:99:df:c1. Suppose we had two other switches in a full-mesh, layer-2 network, and the other switches had root ID's of 32768.3c:8a:b0:99:e5:41 and 32768.3c:8a:b0:9a:22:01. Which switch would be elected root bridge? Let's connect these three switches together and find out! I'll connect ge-0/0/23 on the first switch to ge-0/0/22 on the second switch, connect ge-0/0/23 on the second switch to ge-0/0/22 on the third switch, then connect ge-0/0/23 on the third switch to ge-0/0/22 on the first switch. Once the switches are wired up to create a loop at layer-2, we'll re-run the "show spanning-tree bridge" command and see which switch was actually elected to be the root bridge:

root@main3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@main3200#


root@branch1-3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@branch1-3200#


root@branch2-3200# run show spanning-tree bridge | match "Root ID"
  Root ID                           : 32768.3c:8a:b0:99:df:c1

[edit]
root@branch2-3200#


Since all three switches have the same priority (JunOS' default of 32768), the election was determined by the lowest MAC address, which belongs to main3200.

If we wanted to know which ports were shut down, we would use the "show spanning-tree interface" command, but here, I have to make an admission: I couldn't actually find enough cross-over cables to connect all three switches in a full-mesh network, so I had to disconnect branch2-3200 for the following portion of the lab:

root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:535  32768.3c8ab099dfc1     20000  FWD    DESG
ge-0/0/23.0    128:536      128:536  32768.3c8ab099dfc1     20000  FWD    DESG

[edit]
root@main3200#


root@branch1-3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  32768.3c8ab099dfc1     20000  BLK    ALT
ge-0/0/23.0    128:536      128:535  32768.3c8ab099dfc1     20000  FWD    ROOT

[edit]
root@branch1-3200#


If you notice, ge-0/0/22 on branch1-3200 is blocked by Spanning Tree, which shows that, when a link between two switches is determined to be redundant, if the path-cost back to the root bridge is equal, the lowest port number will be shut down (however, you can manually assign a port-cost to bias for or against a particular port, if you want).

RSTP is enabled on Juniper EX-series switches by default, but if you need to manually configure Spanning Tree, Rapid Spanning Tree or Multiple Spanning Tree, it's a very easy process. All three protocols are configured in exactly the same way, with just a couple of exceptions, which we'll cover in just a minute. Consequently, we'll only run through the configuration steps once, using RSTP. If you are using STP or MSTP, then rather than using "edit protocols rstp" (or "set protocols rstp ..."), you will use "edit protocols stp" or "edit protocols mstp" as appropriate.

First, we'll set the bridge priority to be lower on branch1-3200, to make it the root bridge instead of main3200:

root@branch1-3200# edit protocols rstp

[edit protocols rstp]
root@branch1-3200# set bridge-priority 20k

[edit protocols rstp]
root@branch1-3200#


Next, we will disable RSTP on ge-0/0/12.0 and commit the config:
root@branch1-3200# set interface ge-0/0/12.0 disable

[edit protocols rstp]
root@branch1-3200# commit
commit complete

[edit protocols rstp]
root@branch1-3200#


Now, one of the ports on main3200 should be in the blocking state, rather than on branch1-3200:

root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  20480.3c8ab099e541     20000  BLK    ALT  
ge-0/0/23.0    128:536      128:535  20480.3c8ab099e541     20000  FWD    ROOT

[edit protocols rstp]
root@main3200#


...and sure enough, ge-0/0/22.0 on main3200 is now in the blocking state. Let's adjust the priority to put ge-0/0/23 in the blocking state, instead:

root@main3200# set interface ge-0/0/22 cost 1000

[edit protocols rstp]
root@main3200# commit
commit complete

[edit protocols rstp]
root@main3200# run show spanning-tree interface

Spanning tree interface parameters for instance 0

Interface    Port ID    Designated      Designated         Port    State  Role
                         port ID        bridge ID          Cost
ge-0/0/22.0    128:535      128:536  20480.3c8ab099e541      1000  FWD    ROOT
ge-0/0/23.0    128:536      128:535  20480.3c8ab099e541     20000  BLK    ALT  

[edit protocols rstp]
root@main3200#


One of the problems with spanning tree is the time it takes for the network to "converge" -- that is, the time it takes for the switches to elect a root bridge, determine if there are any loops in the topology, and then to shut down any redundant links. In STP, convergence can take almost a full minute, which is at least part of the reason RSTP was created. While RSTP is already quicker to converge than STP, it can converge even quicker if point-to-point links are declared as such with the "set protocols rstp interface ge-0/0/<whatever> mode point-to-point" command (Edit: if you are confused here, you are not alone. I'm not sure what a "point-to-point" link even means in a layer-2 network, but if I find out, I'll notate it here).

MSTP also differs from standard STP configuration in that you must add two more lines to the config:

root@main3200# set protocols mstp configuration-name jncia-example-1

[edit]
root@main3200# set protocols mstp msti 1 vlan [ 1 2 4 ]

[edit]
root@main3200# set protocols mstp msti 2 vlan [ 3 5 6 20 ]

[edit]
root@main3200#
<...etc...>


The only "gotcha" when putting VLANs into an MSTP instance (MSTI) is that every VLAN in a given instance must share a common topology.