Perhaps you’re curious about Junos, but never had the opportunity to try it. This article is intended for well-seasoned network engineers with a Cisco background, but little exposure to Junos. There are many similarities between the two operating systems, however there are some significant differences which are designed to make your life easier.
There are some high-level points that you should know about Junos:
- It’s built on top of FreeBSD; with this comes all of the benefits of a monolithic kernel as a control plane:
- Each component of Junos executes as a separate process.
- Because each control plane component executes as a separate process, the network operating system becomes more stable. For example a bug with SNMP wouldn’t impact BGP and vice versa.
- Tools such as tcpdump can be used to sniff control packets sourced or destined to the control plane such as STP BPDUs and OSPF Hellos.
- Provides a true separation of control and data plane. Management functions do not impact transit traffic and vice versa. For example if the data plane was running at line-rate, the control plane is still perfectly accessible and responsive.
- Starting as of Junos 12.1, there are three releases of the software each year.
- The major release is tied to the year and the minor release is tied to the release number. For example 12.1 was released in 2012 and was the first release of that year.
- The first release is scheduled roughly around March; the second release is scheduled roughly around July; and the third release is scheduled roughly around November.
- Each release is supported for two years.
- The last release of the year is supported for three years. For example 12.3 is the last release of 2012 and will be supported for three years.
- Change control is built into Junos.
- As soon as you enter the configuration mode, a copy of the running configuration presented to you and is referred to the as candidate configuration.
- As you make changes only the candidate configuration is modified. For example if you add a new OSPF area to the candidate configuration, it will not impact the running configuration.
- All changes must be committed to the system in order to take effect. As changes are committed to the system, all changes are logged into a database. This database of previous changes can be used to rollback to a previous state of the system. This allows network engineers to treat changes to the system as snapshots; if somethings breaks, simply rollback to a previous snapshot or last known good configuration.
- Configuration commits can be marked with a comment. For example it’s common practice to associate the change control number of the network maintenance wit the commit comment. In addition to a commit comment, Junos will also log which user made the change, what exactly was modified, and what time the change took place. This makes auditing of the device very simple as it answers the who, what, and when questions with a single command.
- Junos supports full automation.
- Junos leverages XML for all inter-process communication and configuration data. Using a common language allows for the automation and programming of the entire network operating system.
- All major programming languages such as Java and Perl can be used to interact with Junos.
- Junos supports a custom programming language called SLAX that can be used off-box or on-box to fully program and automate Junos.
- Junos also supports three types of automation scripts:
- Commit scripts. These scripts are executed with each commit. For example a commit script could check all interfaces descriptions that contain the keyword “CORE” and ensure that the MTU is at least 4,000 or return a commit error.
- Operation scripts. These scripts are executed as regular operational commands. For example if you don’t like the output of the “show interfaces” command, you can simply write your own version of the command instead.
- Event scripts. These scripts are executed when an event takes place. For example if an interface went down or a destination IP address became unreachable, you can trigger an event such as installing a new static route.
Junos is such a pleasure to use because every detail has been thought about and polished to ensure your complete comfort. A good user interface should be able to step out of the user’s way and let you focus on the task at hand. Let’s begin with some simple things.
Just the Simple Things
Like most of you, I spend a lot of time on the command-line. I have a silly saying that Junos was “designed by network engineers, for network engineers.” The Junos command-line was designed specifically to get out of the way and let you work with the system. One of the subtle features that many people take for granted is automatic word completion. We all know that there’s no need to fully type out “show” and we use “sh” instead; it’s shorter and easier to type. However in Junos as soon as you hit the spacebar the cli daemon will query a database of commands and will see if there’s a unique match and fully spell out the command.
For example this is what is typed on the keyboard:
sh int
And this is what is displayed on the terminal:
root> show interfaces
Such a simple feature that gives you feedback as you type. Of course if there isn’t enough data to find a unique command, the cli will return a set of possible completions. For example if you simply typed “s” into the keyboard and then hit space, Junos would display the following:
root> s
^
's' is ambiguous.
Possible completions:
save Save information to file
set Set CLI properties, date/time, craft interface message
show Show system information
ssh Start secure shell on another host
start Start shell
Obviously the character “s” isn’t enough to create a unique match, so the most logical thing to do would be display a list of commands that match your input up to this point. Obviously many of us are conditioned to use the “?” character to get a list of commands; the good news is that this method works in Junos as well.
So What?
Why is this a big deal? Because it works and it works well. It’s critical that a user receive constant feedback from a user interface. My biggest pet peeve is typing out a long string of commands and hit enter to only find out that I misspelled the first command. Being forced to either up arrow, move the cursor all the way over and correct the mistake or just correctly type the first command and then cut and paste the rest of the command doesn’t make any sense at all; it’s just a waste of time. As you type commands into Junos, each character is constantly parsed against a command database to ensure that each command is spelled correctly and has the correct context.
Variables
Parsing characters to ensure that commands meet the criteria of a command database is nice, but it isn’t enough. As you build a network you have to create firewall filters, routing policies, and other components that require names. I try and be clever and create consistent variable names, but I always forget them. Going back to the first tenant that a user interface should always provide feedback, Junos performs the grunt work of keeping track of variable names so that you can focus on the task at hand. Let’s suppose you’ve created a couple of firewall filters, but forgot what they were called. You could always check the configuration, but why bother. Simply use the show command and your friend the “?” character.
root> show firewall filter ? Possible completions: <filtername> Filter name JUST-ANOTHER-LONG-AND-ANNOYING-NAME REALLY-LONG-AND-GOOFY-FILTER-NAME __default_bpdu_filter__ application Owner application counter Counter name version Show filter version installed
Junos does the grunt work for you. There are currently two filters defined: JUST-ANOTHER-LONG-AND-ANNOYING-NAME and REALLY-LONG-AND-GOOFY-FILTER-NAME. This trick works for any type of variable name in Junos. A few examples are:
- BGP group names.
- Policy statements.
- Term names inside of a firewall filter.
- Class of service classifier and scheduler names.
Obviously that’s just a simple list of examples to get you thinking, but be aware that Junos supports variable listing at any point in the command-line. For the really lazy, Junos supports variable name completion using the tab key. For example if you wanted to take a look at the firewall filter REALLY-LONG-AND-GOOFY-FILTER-NAME, but didn’t want to type it out, simply type in:
sh fir fil REA<tab>
And the command-line will be displayed as:
root> show firewall filter REALLY-LONG-AND-GOOFY-FILTER-NAME
Junos is the ultimate tool for networking short-hand. Being able to use short-hand with a user interface allows you to work more quickly, but a common problem with short-hand is that you need know what all of the short hand means. Junos fixed this problem with automatic command completion; this feature works as a real-time training tool to teach the user what they can and cannot get away with because Junos will instantly give you feedback with each character typed, instead of waiting for you to finish typing and hit enter, then punish you with a sarcastic message about the command syntax being incorrect.
How to Edit Like a Boss
The Junos configuration is big. That’s because a non-negotiable requirement is that the configuration must be human-readable and conform to a strict command hierarchy. Making a change in production is serious business, and there should be no question which part of the configuration is in scope and what exactly is being modified.
Moving Around
When you enter the configuration mode, the default location is at the top of the hierarchy. That’s why the prompt just says “[edit]” to indicate you’re at the top of the hierarchy. Let’s assume you were going to make a change to the routing protocol OSPF under the master routing instance and area 0.0.0.0 is in scope. A good way to make sure you don’t goof up anything else is to change the scope of the command-line to that specific section of configuration:
[edit] root# edit protocols ospf area 0.0.0.0
[edit protocols ospf area 0.0.0.0]
Now whatever you type will only modify the configuration within OSPF under the master routing instance in area 0.0.0.0. Let’s add the interface fe-0/0/6.0 into area 0.0.0.0 as a point-to-point interface:
[edit protocols ospf area 0.0.0.0] root# set interface fe-0/0/6.0 interface-type p2p
[edit protocols ospf area 0.0.0.0]
root# show
interface fe-0/0/6.0 {
interface-type p2p;
}
Obviously since the edit-mode has been changed to the context of [edit protocols ospf area 0.0.0.0] there’s no need to type out all of that information when adding the fe-0/0/6.0 interface. All commands entered within this context are executed relative to the context in the configuration prompt. For example the “show” command will only show configuration within the [edit protocols ospf area 0.0.0.0] context.
Top
Configuration context is nice, but sometimes makes life difficult because you can feel trapped within this context. One trick is to use the “top” command followed by a command that you would normally use as if you were at the root of the configuration. For example let’s set a new firewall filter and check it out while we’re still in the [edit protocols ospf area 0.0.0.0] context:
[edit protocols ospf area 0.0.0.0] root# top set firewall family inet filter TEST term 1 then accept
[edit protocols ospf area 0.0.0.0]
root# top show firewall family inet
filter TEST {
term 1 {
then accept;
}
}
If you want to stop editing OSPF and move to another part in the configuration, simply change the context with the “edit” command. Let’s assume we want to edit the firewall filter “TEST.” Let’s save some time and combine the “top” and “edit” commands:
[edit protocols ospf area 0.0.0.0] root# top edit firewall family inet filter TEST
[edit firewall family inet filter TEST] root# set term 2 then discard
[edit firewall family inet filter TEST]
root# show
term 1 {
then accept;
}
term 2 {
then {
discard;
}
}
Firewall filters are evaluated from the top down. It’s a common misconception that firewall terms need to be named with incrementing numbers, but this is just a habit of many network engineers. The truth is that the firewall terms can be named anything and the filter is simply evaluated from the top down. Since the order is critical to the firewall filter evaluation process, it’s important to understand how to move terms around easily.
Insert
Let’s assume that we want to have the term “2″ come before the term “1″. Most engineers that are new to Junos are tempted to simply delete the firewall filter and type in the new firewall filter with the term “2″ being first. This works, but it’s time consuming and just annoying. Let’s use the “insert” command instead. This command will allow you to move configuration components before or after other configuration components.
[edit firewall family inet filter TEST] root# insert term 2 before term 1
[edit firewall family inet filter TEST]
root# show
term 2 {
then {
discard;
}
}
term 1 {
then accept;
}
That was easy. The “insert” command simply moved the term named “2″ before the term named “1.” The same trick can be used to add a new term between terms “1″ and “2.”
[edit firewall family inet filter TEST] root# set term MIDDLE then reject
[edit firewall family inet filter TEST] root# insert term MIDDLE after term 2
[edit firewall family inet filter TEST]
root# show
term 2 {
then {
discard;
}
}
term MIDDLE {
then {
reject;
}
}
term 1 {
then accept;
}
Up
Sometimes you’re deep into a configuration and you need to move into another part of the configuration. For example let’s assume you’re editing in the [edit firewall family inet filter TEST] context and you want to change the context within the firewall configuration, but into a different family and filter name. Use the “up” command followed by the number of levels to move up into the configuration then go from there:
[edit firewall family inet filter TEST] root# up 2 edit family mpls filter MPLS-TEST
[edit firewall family mpls filter MPLS-TEST] root#
This example shows moving up 2 levels from [edit firewall family inet filter TEST], then begin editing the mpls family and a filter called MPLS-TEST.
What Did I Change?
Recall that Junos doesn’t change anything until the configuration is committed. It’s always best practice to double-check exactly what was changed in the configuration before committing it. Junos supports piping the output of commands to other commands. One pipe command that is helpful is “compare.” This will take the running configuration and compare it to the modified/candidate configuration and list out any differences. Lines that are added to the configuration are listed with a “+” while lines that are removed are listed with a “-”.
[edit firewall family mpls filter MPLS-TEST] root# top
[edit]
root# show | compare
[edit protocols]
+ ospf {
+ area 0.0.0.0 {
+ interface fe-0/0/6.0 {
+ interface-type p2p;
+ }
+ }
+ }
From the above output it’s pretty obvious that the only thing that will be changed is the addition of the OSFP routing protocol in the master routing instance and that the interface fe-0/0/6.0 will be added into area 0.0.0.0.
Rollback
The rollback command is probably my favorite command of all. It’s like being able to take a mulligan in golf, but considered legal. Make a mistake? Do over! Let’s assume we want to throw away all of the previous OSPF configurations from the previous section. Just type rollback and you’re set.
[edit] root# rollback load complete
Using the rollback command by itself will take a copy of the running configuration and load it into the candidate configuration. All previous modifications to the candidate configuration is lost and you’re just left with a simple copy of the running configuration at your finger tips. As previously mentioned in the last section, Junos keeps a copy of all previous configurations and you’re able to load them at any time. The rollback command accepts a numerical argument that is associated with a rollback number. To get a list of rollback numbers use the “?” character as shown below:
[edit] root# rollback ? Possible completions: <[Enter]> Execute this command 0 2012-07-01 15:34:56 UTC by root via cli 1 2012-07-01 15:30:43 UTC by root via cli 2 2012-06-30 12:15:16 UTC by root via other 3 2012-06-30 11:58:20 UTC by root via cli 4 2012-06-30 11:57:03 UTC by root via cli 5 2012-06-30 11:56:41 UTC by root via cli 6 2011-09-14 12:47:51 UTC by root via cli 7 2011-09-14 12:45:59 UTC by root via cli 8 2011-09-14 12:16:08 UTC by root via cli | Pipe through a command
This system has eight snapshots going all the way back to 2011-09-14 at 12:16:08 UTC. Junos also logs which user made the change and via what method; in this example most of the changes were made by the command-line with the user root. If you wanted to rollback to the snapshot on 2011-09-14 12:16:08 simply use the command rollback 8.
If you aren’t sure which rollback to use, you can also take a peek at the snapshots using the rollback in a pipe command.
[edit]
root@R1# show | compare rollback 8
[edit firewall family inet]
filter REALLY-LONG-AND-GOOFY-FILTER-NAME { ... }
+ filter JUST-ANOTHER-LONG-AND-ANNOYING-NAME {
+ term 1 {
+ then accept;
+ }
+ }
This command output looks very similar to the previous compare command, but the order is reversed. When the compare command is joined with the rollback command, the “+” indicates lines that would be added on the rollback and the “-” indicates lines that would be removed on the rollback. This is a great method to spot check the delta between various rollback snapshots.
Commit Comments
Let’s check out the commit comment feature. The comment can be any sort of string; most people use it to reference a change control number as shown below:
[edit] root@TEST# set system host-name R1
[edit] root@TEST# commit comment "Change control #96294" and-quit commit complete Exiting configuration mode
root@R1> show system commit 0 2012-07-02 10:11:48 UTC by root via cli Change control #96294 1 2012-07-02 10:11:21 UTC by root via cli Change control #96293 2 2012-07-01 15:34:56 UTC by root via cli 3 2012-07-01 15:30:43 UTC by root via cli 4 2012-06-30 12:15:16 UTC by root via other 5 2012-06-30 11:58:20 UTC by root via cli 6 2012-06-30 11:57:03 UTC by root via cli 7 2012-06-30 11:56:41 UTC by root via cli 8 2011-09-14 12:47:51 UTC by root via cli 9 2011-09-14 12:45:59 UTC by root via cli 10 2011-09-14 12:16:08 UTC by root via cli
Here we can see that the system hostname was changed to R1 then committed with a comment referencing the change control #96294. To see a list of previous system commits and the respective comments the show system commit command can be used.
Configuration Automation
Junos has several methods to apply simple automation to the configuration. The less work you have to do, the less chance of introducing an error into the environment.
Apply Groups
Imagine that you have four interfaces in OSPF area 0.0.0.0 and you want to apply BFD to each interface. It’s such a repetitive task: apply the BFD configuration statements to the first interface, second interface, so on and so forth. Why not just apply the configuration once and be done with it?
[edit] root@R1# set groups bfd-ospf-area-0.0.0.0 protocols ospf area 0.0.0.0 \ interface <*> bfd-liveness-detection minimum-interval 300 multiplier 3
[edit]
root@R1# show groups
bfd-ospf-area-0.0.0.0 {
protocols {
ospf {
area 0.0.0.0 {
interface <*> {
bfd-liveness-detection {
minimum-interval 300;
multiplier 3;
}
}
}
}
}
}
This has created a group called bfd-ospf-area-0.0.0.0 that will match any interface already defined in the [protocols ospf area 0.0.0.0] configuration context and apply the bfd-liveness-detection configuration to each interface. The next step is to use the apply-groups option and associated the group with the configuration context to which you want to apply it to:
[edit] root@R1# set protocols ospf area 0.0.0.0 apply-groups \ bfd-ospf-area-0.0.0.0
[edit]
root@R1# show protocols ospf
area 0.0.0.0 {
apply-groups bfd-ospf-area-0.0.0.0;
interface fe-0/0/0.0;
interface fe-0/0/1.0;
}
Now that the group bfd-ospf-area-0.0.0.0 has been applied to the [protocols ospf area 0.0.0.0] context, the BFD configuration will be applied to each interface ground within that configuration context. To double check that the apply group is working correctly use the display inheritance command to verify:
[edit]
root@R1# show protocols ospf area 0.0.0.0 | display inheritance
interface fe-0/0/0.0 {
##
## 'bfd-liveness-detection' was inherited from group
## 'bfd-ospf-area-0.0.0.0'
##
bfd-liveness-detection {
##
## '300' was inherited from group 'bfd-ospf-area-0.0.0.0'
##
minimum-interval 300;
##
## '3' was inherited from group 'bfd-ospf-area-0.0.0.0'
##
multiplier 3;
}
}
interface fe-0/0/1.0 {
##
## 'bfd-liveness-detection' was inherited from group
## 'bfd-ospf-area-0.0.0.0'
##
bfd-liveness-detection {
##
## '300' was inherited from group 'bfd-ospf-area-0.0.0.0'
##
minimum-interval 300;
##
## '3' was inherited from group 'bfd-ospf-area-0.0.0.0'
##
multiplier 3;
}
}
If the apply group matched any portion of the configuration, the double hash (##) will display what apply group was applied and what configuration elements were added. With a simple apply group we have now reduce the amount of configuration and work to apply BFD to all interfaces under [protocols ospf area 0.0.0.0].
Apply Path
Another great feature of Junos is the ability to create dynamic prefix lists. Let’s assume that we have a BGP configuration with three neighbors defined. Instead of creating a static prefix list and defining each BGP neighbor, it would make more sense to let Junos manage the prefix list for us. Apply path is able to match the existing configuration and apply it to a prefix list. Take the following BGP configuration:
[edit]
root@R1# show protocols bgp
group TRANSIT {
type internal;
neighbor 192.168.1.1;
neighbor 192.168.1.2;
neighbor 192.168.1.3;
}
There are three neighbors ranging from 192.168.1.1 to 192.168.1.3. Now let’s build a dynamic prefix list using the apply path to match the [protocols bgp group TRANSIT] configuration context:
[edit] root@R1# set policy-options prefix-list TRANSIT-NEIGHBORS apply-path \ "protocols bgp group TRANSIT neighbor <*>"
This creates a new prefix list called TRANSIT-NEIGHBORS and uses the apply-path feature to find all of the neighbor IP addresses in the [protocols bgp group TRANSIT] configuration context. Let’s use the display inheritance trick to verify that the apply path feature matches the correct IP addresses:
[edit] root@R1# show policy-options prefix-list TRANSIT-NEIGHBORS | display \ inheritance ## ## apply-path was expanded to: ## 192.168.1.1/32; ## 192.168.1.2/32; ## 192.168.1.3/32; ## apply-path "protocols bgp group TRANSIT neighbor <*>";
The apply-path has successfully matched all three IP addresses in the [protocols bgp group TRANSIT] configuration context and inserted them into the prefix list TRANSIT-NEIGHBORS. Now that this is setup, all future changes to [protocols bgp group TRANSIT] neighbor IP addresses will instantly reflect into the TRANSIT-NEIGHBORS prefix list.
Conclusion
This was a lengthy post, but Junos has much to share. Part 2 will dive deeper into other configuration options that are designed to make your life easier by making change control windows shorter and more deterministic. Junos lives by the motto of “less is more.”
