For Nokia 7×50 Platforms (7250 IXR, 7450 ESS, 7750 SR and 7950 XRS) Nokia SROS Model Driven CLI (MD-CLI) is the modern CLI used for these platforms. The original “Classic” CLI is still available, however it is no longer enabled by default starting with SROS 23.7.R1 and would need to be reconfigured to use that interface.
MD-CLI has a number of advantages over Classic CLI:
- Firstly as the name suggests – the interface is tightly coupled with the system configuration and operational states of the platforms it runs in – the models are reachable using NetConf and GRPc (SNMP is supported in some limited forms but is definitely not a first class citizen here – if SNMP is your bag, you will need to stay with Classic CLI, or enable Mixed-Mode management which is a hybrid of the two.
- Transaction based configs are actively used now, in Classic CLI these were optional and often not used
- Leverages Configuration Groups (which is one of the topics of discussion in this blog post) – this concept is not unique to Nokia and some vendors have had this concept for a really long time however it is great to see that it exists
- Supports automation friendly actions – you can view config and state information in the same way your automation tools might use using JSON or XML and displaying things in xpath format – this is also described on the Nokia Network Developer Portal using tools like gNMIc
- Advanced capabilities through PySROS enabling cool things like adding tools on the router to enable the creation of new CLI commands, or for advanced automation/reconfiguration actions based on system events
The biggest disadvantage is that MD-CLI is not available on the smaller platforms (7705 SAR and 7210 SAS) and for those at least at the moment Classic CLI is all that is available.
Annotations (configuration comments)
The annotation (configuration comment) feature which was introduced in SROS 21.5.R1. This capability enables the insertion of a comment within the router configuration at a particular configuration section, this might be helpful to help document why something is done in a particular manner, or to mention that something had been changed on purpose – and might stop someone at 2:00am working on a fault and trying to revert/remove an intended config.
Let me give an example – this is a configuration section of a router that we are going to change the system address and would like to annotate what happened and when.
A:admin@R1# info ipv4 { primary { address 192.168.1.1 prefix-length 32 } } [gl:/configure router "Base" interface "system"]
We are going to change the IP Address and include a note as to what changed and when
[gl:/configure router "Base" interface "system"] A:admin@R1# ipv4 primary [gl:/configure router "Base" interface "system" ipv4 primary] A:admin@R1# annotate "Changed on 18-Aug-23 (Was 192.168.1.1)" address *[gl:/configure router "Base" interface "system" ipv4 primary] A:admin@R1# address 1.1.1.1 *[gl:/configure router "Base" interface "system" ipv4 primary]
Let’s Look at the resulting configuration
A:admin@R1# /configure router interface "system" *[gl:/configure router "Base" interface "system"] A:admin@R1# info ipv4 { primary { # comment: Changed on 18-Aug-23 (Was 192.168.1.1) address 1.1.1.1 prefix-length 32 } }
Before we commit this change we can see that this documentation matches the changes, however it will start part of the configuration and can be reviewed by others in the future
*[gl:/configure router "Base" interface "system"] A:admin@R1# compare ipv4 { primary { - address 192.168.1.1 + # comment: Changed on 18-Aug-23 (Was 192.168.1.1) + address 1.1.1.1 } } *[gl:/configure router "Base" interface "system"]
Configuration Groups
Config Groups enable you to create resuable configurable blocks that are defined once and used multiple times. This should result in:
- smaller and easier to read configurations
- less chance of a “fat fingered” mistake when copying configuration blocks across sections
- changes to the configuration group – get propogated to the other things consuming it
Below is an example of a configuration group infra-if-v4.
The regular expression “<.*>” will match any string (in a production environment this may be too aggressive and may need to be modified to something like “<to_pe-.*>” to only match interfaces that are similar to “to_pe-123”
[/] A:admin@R1# configure global INFO: CLI #2054: Entering global configuration mode [gl:/configure] A:admin@R1# groups [gl:/configure groups] A:admin@R1# info group "infra-if-v4" { router "<.*>" { interface "<.*>" { ipv4 { icmp { mask-reply false redirects { admin-state disable } unreachables { number 10 seconds 10 } } urpf-check { mode loose } bfd { admin-state enable transmit-interval 100 receive 100 multiplier 3 type auto } primary { prefix-length 31 } neighbor-discovery { proactive-refresh true } } } } } [gl:/configure groups]
In this case, this takes a bunch of configuration boiler plate that we want all relevant interfaces to share. Interface “to-R2” will be created
[gl:/configure groups] A:admin@R1# /configure router interface to-R2 *[gl:/configure router "Base" interface "to-R2"] A:admin@R1# port 1/1/c1/1 *[gl:/configure router "Base" interface "to-R2"] A:admin@R1# ipv4 primary address 172.16.0.1 *[gl:/configure router "Base" interface "to-R2"] A:admin@R1# apply-groups "infra-if-v4" *[gl:/configure router "Base" interface "to-R2"] A:admin@R1# admin-state enable *[gl:/configure router "Base" interface "to-R2"] A:admin@R1# info apply-groups ["infra-if-v4"] admin-state enable port 1/1/c1/1 ipv4 { primary { address 172.16.0.1 } }
Through the info instruction we can see what was specifically configured in that interface, however we cannot review what the configuration pulled in from the configuration group unless we use the inheritance keyword
*[gl:/configure router "Base" interface "to-R2"] A:admin@R1# info inheritance apply-groups ["infra-if-v4"] admin-state enable port 1/1/c1/1 ipv4 { icmp { ## inherited: from group "infra-if-v4" mask-reply false redirects { ## inherited: from group "infra-if-v4" admin-state disable } unreachables { ## inherited: from group "infra-if-v4" number 10 ## inherited: from group "infra-if-v4" seconds 10 } } ## inherited: from group "infra-if-v4" urpf-check { ## inherited: from group "infra-if-v4" mode loose } bfd { ## inherited: from group "infra-if-v4" admin-state enable ## inherited: from group "infra-if-v4" transmit-interval 100 ## inherited: from group "infra-if-v4" receive 100 ## inherited: from group "infra-if-v4" multiplier 3 ## inherited: from group "infra-if-v4" type auto } primary { address 172.16.0.1 ## inherited: from group "infra-if-v4" prefix-length 31 } neighbor-discovery { ## inherited: from group "infra-if-v4" proactive-refresh true } }
The messaging ## inherited: from group “infra-if-v4” is particularly helpful if there are multiple groups applied and you wish to see which part contributed to that part of the configuration, however if it clutters the output too much it is possible to filter it out
*[gl:/configure router "Base" interface "to-R2"] A:admin@R1# info inheritance | match "##" invert-match apply-groups ["infra-if-v4"] admin-state enable port 1/1/c1/1 ipv4 { icmp { mask-reply false redirects { admin-state disable } unreachables { number 10 seconds 10 } } urpf-check { mode loose } bfd { admin-state enable transmit-interval 100 receive 100 multiplier 3 type auto } primary { address 172.16.0.1 prefix-length 31 } neighbor-discovery { proactive-refresh true } }
This is just a taste of what configuration groups can bring. If you would like to see more I have developed a containerlab demonstration to show the power of configuration groups to support Ethernet Port, IP Interface and OSPF Interface related configuration. The containerlab topology and walkthrough is is available on my github
Recent Comments