Junos Configuration Groups

Introduction

Junos provides an oddly named but quite useful mechanism called “groups” for creating reusable configuration snippets. In this article I will describe what they are and how to use them to make your life a little easier.

The Basics: Creating and Applying a Group

Almost anything you can set under the main configuration hierarchy can also be set under the groups section:

wayne@vr1# set groups foo ?
Possible completions:
Execute this command
> access Network access configuration
> access-profile Access profile for this instance
> accounting-options Accounting data configuration
> applications Define applications by protocol characteristics
[...]

Here’s a sample group:

groups {
    foo {
        system {
            default-address-selection;
            services {
                netconf {
                    ssh;
                }
            }
        }
    }
}

By itself, that doesn’t do anything other than make your configuration larger. In order for those settings to take effect, you have to apply the group using the apply-groups setting:

wayne@vr1# set apply-groups foo

Even then, when you look at your configuration you won’t see your new settings:

wayne@vr1# show system
host-name vr1;
services {
  ssh;
}

In order to see the effective settings, you need to pipe the show command through the “display inheritance” filter:

wayne@vr1# show system | display inheritance                 
host-name vr1;
##
## 'default-address-selection' was inherited from group 'foo'
##
default-address-selection;
services {
    ssh;
    ##
    ## 'netconf' was inherited from group 'foo'
    ##
    netconf {
        ##
        ## 'ssh' was inherited from group 'foo'
        ##
        ssh;
    }
}

Configuration groups do not need to be applied at the root of the configuration. Any settings that reside above where the group was applied will be ignored:

wayne@vr1# delete apply-groups foo 
wayne@vr1# set sysetm services apply-groups foo
wayne@vr1# show system | display inheritance | except ##$   
host-name vr1;
services {
    ## 'netconf' was inherited from group 'foo'
    netconf {
        ## 'ssh' was inherited from group 'foo'
        ssh;
    }
}

Getting a Little Fancier: Patterns and Exceptions

A single group can be applied to multiple places (such as interfaces) by using a pattern (in UNIX-style glob format) for the name. In order to be treated as a pattern, it must be enclosed in <angle brackets>.

Here are a few sample groups using patterns:

/* matches all interfaces */
all-interfaces {
    interfaces {
        <*> {
            mtu 1500;
        }
    }
}
/* matches all ge and xe interfaces */
all-gig-interfaces {
    interfaces {
        "<[gx]e-*>" {
            mtu 9000;
        }
    }
}
/* matches all interfaces on fpc0 */
all-fpc0-interfaces {
    interfaces {
        <*-0/*> {
            mtu 2000;
        }
    }
}

So, let’s say you apply all three of these groups at the root of the configuration (or under interfaces – it doesn’t really matter) – what happens if you want or need to exclude an interface? For instance, members of LAGs are not allowed to have MTU settings:

wayne@fw1# commit check
[edit interfaces fe-0/0/5 fastether-options]
  '802.3ad'
     ae child device mtu setting and vlan-tagging is not allowed
error: configuration check-out failed

This can be done with the help of apply-groups-except:

wayne@fw1# set interfaces fe-0/0/5 apply-groups-except all-interfaces 
wayne@fw1# commit check 
configuration check succeeds

Precedence and Stacking

One thing that I found to be poorly documented is the expected behavior when multiple groups try to apply conflicting values for the same setting. The groups in the previous section, for instance, have different MTUs and all 3 would apply to all ge and xe interfaces on fpc0. Well, from what I can tell, it’s a combination of best match and first match:

  • Groups applied further down in the hierarchy override groups applied above them
  • When applied at the same level, the first group in the apply-groups list trumps those that come after it
wayne@fw1# set interfaces apply-groups [ all-interfaces all-gig-interfaces all-fpc0-interfaces ] 
wayne@fw1# set interfaces fe-0/0/3 apply-groups all-fpc0-interfaces
ge-0/0/0 {
    ## '9000' was inherited from group 'all-gig-interfaces'
    mtu 9000;
    unit 0 {
        family ethernet-switching;
    }
}
ge-0/0/1 {
    ## '9000' was inherited from group 'all-gig-interfaces'
    mtu 9000;
    unit 0 {
        family ethernet-switching;
    }
}
fe-0/0/2 {
    ## '1500' was inherited from group 'all-interfaces'
    mtu 1500;
    unit 0 {
        family ethernet-switching;
    }
}
fe-0/0/3 {
    ## '2000' was inherited from group 'all-fpc0-interfaces'
    mtu 2000;
    unit 0 {
        family ethernet-switching;
    }
}

Groups can also build upon one another – and in fact order does not always matter in the way you think it would. Consider the following groups:

foo {
    security {
        ike {
            proposal <pre-*> {
                authentication-method pre-shared-keys;
                lifetime-seconds 86400;
            }
            proposal <*-g2-*> {
               dh-group group2;
            }
            proposal <*-g5-*> {
                dh-group group5;
            }
            proposal <*-aes192-*> {
                encryption-algorithm aes-192-cbc;
            }
            proposal <*-aes256-*> {
                encryption-algorithm aes-256-cbc;
            }
            proposal <*-sha1> {
                authentication-algorithm sha1;
            }
            proposal <*-sha256> {
                authentication-algorithm sha-256;
            }
        }
    }
}
bar {
    security {
        ike {
            proposal pre-g2-aes192-sha1;
            proposal pre-g2-aes256-sha1;
            proposal pre-g5-aes192-sha1;
            proposal pre-g5-aes256-sha1;
            proposal pre-g5-aes256-sha256;
        }
    }
}

Regardless of the order in which they are applied, the proposals from bar are filled in with the values from foo:

wayne@fw1# set security ike apply-groups [ foo bar ] 

[edit]
wayne@fw1# show security ike | display inheritance | except ##$    
## 'pre-g2-aes192-sha1' was inherited from group 'bar'
proposal pre-g2-aes192-sha1 {
    ## 'pre-shared-keys' was inherited from group 'foo'
    authentication-method pre-shared-keys;
    ## 'group2' was inherited from group 'foo'
    dh-group group2;
    ## 'sha1' was inherited from group 'foo'
    authentication-algorithm sha1;
    ## 'aes-192-cbc' was inherited from group 'foo'
    encryption-algorithm aes-192-cbc;
    ## '86400' was inherited from group 'foo'
    lifetime-seconds 86400;
}
[...]
wayne@fw1# delete security ike apply-groups   

[edit]
wayne@fw1# set security ike apply-groups [ bar foo ] 

[edit]
wayne@fw1# show security ike | display inheritance | except ##$
## 'pre-g2-aes192-sha1' was inherited from group 'bar'
proposal pre-g2-aes192-sha1 {
    ## 'pre-shared-keys' was inherited from group 'foo'
    authentication-method pre-shared-keys;
    ## 'group2' was inherited from group 'foo'
    dh-group group2;
    ## 'sha1' was inherited from group 'foo'
    authentication-algorithm sha1;
    ## 'aes-192-cbc' was inherited from group 'foo'
    encryption-algorithm aes-192-cbc;
    ## '86400' was inherited from group 'foo'
    lifetime-seconds 86400;
}
[...]

These settings also work fine if you put them in a single group – I broke them up only to show what can be done.

One More Feature – apply-path

The policy-options/prefix-list[name] section of the hierarchy has a nifty option called apply-path that can be used to pull IP addresses from other sections of the configuration:

wayne@fw1# show policy-options 
prefix-list foo {
    apply-path "interfaces <*> unit <*> family inet address <*>";
}
wayne@fw1# show policy-options | display inheritance 
prefix-list foo {
    ##
    ## apply-path was expanded to:
    ##     192.168.0.0/24; 
    ##     192.168.0.0/24; 
    ##     192.168.128.0/24; 
    ##
    apply-path "interfaces <*> unit <*> family inet address <*>";
}

Note: This feature pulls from the configuration, so it doesn’t work with addresses from DHCP and the like.
For more examples using apply-path see “Day One: Securing the Routing Engine on M, MX, and T Series” – it’s free and well worth the read.

Conclusion

The groups mechanism in Junos provides a simple but powerful way to create configuration templates. There are a few small limitations, but overall they are more flexible than mechanisms such as interface macros yet not nearly as complex to implement as XSLT, SLAX, expect scripts, etc.

In a follow-up article I’m planning to write, I will talk more about a framework I used to centrally manage configuration templates at a previous job.

Wayne Tucker

Wayne Tucker

Wayne Tucker is a network engineer/architect/nerd who works for a large retail and web services company. Prior to that he spent 3 years working for a hospital and 11 years at a mid-sized ISP. He loves good CLIs and APIs, doesn't care for most GUIs, and hopes that onePK doesn't turn out to be a disappointment. He also feels weird describing himself in the third person.
Wayne Tucker

Latest posts by Wayne Tucker (see all)

  • Allen Baylis

    Just laughing … ” He also feels weird describing himself in the third person” … get used to it …

  • http://twitter.com/IPv6Freely Chris Jones

    apply-path is great when used in conjunction with loopback filters for protecting the RE. Can be used for things like BGP, NTP, SNMP, etc.

  • Michael Gonnason

    Can you also use this to define multiple things at once?

    workstation group
    interfaces * mtu 1516 unit 0 port-mode access vlan members workstations
    protocol mstp interfaces * edge
    ethernet-switching voip interface * vlans voice forwarding-class ef

    servers:
    interfaces * mtu 9216unit 0 port-mode access vlan members servers
    protocol mstp interfaces * edge

    • Wayne Tucker

      Nope, there’s no easy way to make that work using just the apply-groups mechanism.

      If you apply the group under interfaces/<interface> then all of the configuration in ethernet-switching/voip will be out of scope.

      Even if you apply your group at the root of the configuration and use patterns in both places (which would get tricky unless you were very rigid with your port assignments) then you probably still wouldn’t get the outcome you want. The reason for this is that apply-groups patterns only match existing configuration – so every interface would need to be listed under ethernet-switching/voip/interfaces in order to be matched.

      At my last job I did a commit script that would add configuration based on which interface “template” was applied. I’ll try to post a write up about that this week.

      • Michael Gonnason

        Thanks for taking the time to rely.

        Yeah, a template config object would be awesome to have someday.

  • http://twitter.com/PerWesterlund Per Westerlund

    When you do a follow up, perhaps mention the “when” statement that was introduced in 12.1, solves some of my problems of using different BW for customers during different times of day. Now it is easy to modify any portion of the configuration based on time/date (and other parameters). Earlier, it was only possible with event scripts and commit scripts.