Sign in to follow this  
Followers 0
pappyaar

TCL Scripting in IOS. Easy to understand Tutorial !

16 posts in this topic

Hi all. Here i am with yet another tutorial. Programming in IOS. Dont confuse it with programming IOS because you cant do it. IOS is not open source so you cant make extensions/modifications to it, But IOS allows you to use TCL (pronounced "tickle") scripting language to write scripts to get tasks done in a different and more feasible way, that was either not possible before or too complicated. One example is the recent query posted by our fellow member superr about how to monitor snmp OID to trigger events. Although the solution was in EEM, but the same could be done using tcl.

 

Those who are totally new to this stuff will be getting confused as to what i am talking about. So lets see a few examples, that are very practical and you may encounter tasks similar to these more often.

 

Example 1)

 

When router cpu utilization reaches 30%, send an email to me, plus give only the first five top processes in "sh process cpu sorted".

 

Example 2)

(this is a case of ARP flooding/looping which causes the router to nearly crash)

 

If router cpu utilization reaches above 80%, check the current processes to see if the top 2 processes contains ARP-Input, if this is the case, check the show int <interface-name> to see which interface is getting lots of broadcast. Find the interface and shut it down, Wait for 3 mins and recheck the process level to see if its ok (below 80%), if yes then check the WAN link to reach the email server, if the wan link is reachable, send an email to notify the support engineer that this event has occurred !!

 

(dont get your head spinning, there's a lot more to follow ;-))

 

Example 3)

 

You have 200+ routers in your access. You want to make sure that every WAN interface is configured with IPsec VPN. Considering 2 WAN links per router means checking of 400 interfaces, can you do that by

1) manually opening the router and viewing the running config ?

2) manually opening the backup config stored on your pc and viewing it ?

3) Or simply open the router, paste the tcl script, that will do all the checking, in the end telling you which interfaces are not vpn enabled and optionally enabling the IPSEC vpn on them !!

 

Depending on your views, these example might be appealing and might not. But if you are network administrator of 100+ routers, then i consider scripting/EEM to be a must-know knowledge, SIMPLE !!. There is no option, you must learn it. It gives you more control and chances of your completing complicated tasks increase dramatically.

 

I would recommend the following books to learn more about tcl and how to program.

 

Tcl and Tk Programming for the Absolute Beginner

 

Hello World!: Computer Programming for Kids and Other Beginners by Warren Sande and Carter Sande (its for python)

 

But remember, i have spend 4 years in my BS doing programming, and no book can teach you how to program. They will at best simply teach the syntax of the programming language but wont teach you, how to solve your problems using programming language. So you need to do a lot of practice in order to become a good programmer. Remember, scriping in IOS doesnt require or expects that you start building robotic arms, or robots that speak by themselves, no automatic cars are required, NOTHING !!!!!.

 

Q) So what the hell i will be doing ?

A) Trust me or not, most of the time, you will be required to do string parsing, extracting your desired result, comparing it with some predefined value and doing some action. Thats it !!

 

Q) Is it really that simple, or you think i am a dumbo ?

A) It is !!

 

Q) I dont trust you, na na....

A) Then just read on, i hope i will convince you on the way :-)

 

Q) What if i am not convinced ?

A) You will, trust me on that ;-)

 

NOTE: this entire tutorial will be very very specific to scripting in IOS. Remember that.

 

Some of the programming essentials !

 

Programming is same as scripting. I may use the word program and script interchangebly, so dont get confused, they are the same thing.

 

Variables.

 

Variables are fundamental in every programming language. You will never see a language without variables, and perhaps not a single proper program written without using variables. NEVER !!

 

Variables are simply places to hold values. Consider this

 

myfirstvar = 4

 

over here, the name of variable is "myfirstvar" and the value of this variable is 4. simple :-).

 

Q) Hey hey, what simple ? whats simple about this ? when and why i will be using variables ?

A) You will use variables under two conditions

 

1) When you are taking input from the user

2) When you need to use a same value more then "1" time in your program.

 

User input must be kept somewhere, so for that purpose its necassary to use variables or more properly storage areas.

 

Now before going into detail, lets see tcl in your router. login to your router and type tclsh from exec mode.

 

Printing on screen.

 

R1# tclsh

R1(tcl)# puts "hi, i am in tcl :-)"

hi, i am in tcl :-)

 

R1(tcl)#

 

"puts" keyword simply displays what ever is given under inverted commas on screen.

 

Variables.

 

R1(tcl)# set myfirstvar 10

10

 

R1(tcl)#

 

Over here, "set" is use to assigned a variable "myfirstvar" some value, which in this case is number "4". Now to print the variable do this,

 

R1(tcl)# puts myfirstvar

myfirstvar

 

R1(tcl)#

 

Now this was not i expected. the variable "myfirstvar" is simply a place to store the values. So if you have a locker in bank, then the stuff in that locker is important and not the locker. So variable is the locker, the value is the stuff you place in that locker. So to get the value inside myfirstvar, you have to put the dollar sign in front of it..

 

R1(tcl)# puts $myfirstvar

10

 

R1(tcl)#

 

Now lets create 2 variables, assign them numbers and add them. To do mathematical calculations, tcl uses keyword "expr"

 

R1(tcl)#set var1 100

100

R1(tcl)#set var2 200

200

R1(tcl)#set var3 [expr $var1 + $var2]

300

R1(tcl)#puts $var3

300

 

R1(tcl)#

 

over here "[expr $var1 + $var2]", $var1 says to tcl, that use the value kept in var1 which is 100. $var2 tells to use the value kept in var2 which is 200. expr tells tcl to perform the addition (or whatever like subtraction, multiplication, division, exponentiation). "[]" square brackets will be replaced with whatever value is calculated inside them, so the above expression is more like this

 

R1(tcl) set var3 300

 

[expr $var1 + $var2] gives value 300, which will be replaced with it and appears like above statement. We will be using square brackets alot so dont be confused.

 

In Tcl, you can execute IOS commands as well using following 2 keywords

 

1) exec -> to run privilege mode commands

2) ios_config -> to run all config mode commands.

 

Using Exec command

 

R1(tcl)#exec sh ip int brief

Interface IP-Address OK? Method Status Prot

ocol

Serial1/0 unassigned YES unset administratively down down

 

Serial1/1 unassigned YES unset administratively down down

 

Serial1/2 unassigned YES unset administratively down down

 

Serial1/3 unassigned YES unset administratively down down

 

R1(tcl)#

 

Using ios_config command

 

R1(tcl)# ios_config "int serial 1/0" "ip address 11.0.0.1 255.255.255.252" "no shut"

 

R1(tcl)#exec show ip int brief

Interface IP-Address OK? Method Status Prot

ocol

Serial1/0 11.0.0.1 YES unset up up

 

Serial1/1 unassigned YES unset administratively down down

 

Serial1/2 unassigned YES unset administratively down down

 

Serial1/3 unassigned YES unset administratively down down

 

R1(tcl)#

 

Note: While in tcl mode, you can run IOS commands directly without these keywords, but as we go deeper, you will understand why these keywords make a difference.

 

Now lets create a simple tcl program.

 

Program 1)

 

Create a tcl program to calculate the DRAM on your router.

 

Now lets see how to write a program.

 

1) First solve it on paper and follow the steps carefully, observe deeply how exactly did you solved this issue.

 

I would solve it like this

 

First i will do "show version"

 

R1#sh ver

Cisco IOS Software, 3600 Software (C3640-JS-M), Version 12.4(12), RELEASE SOFTWA

RE (fc1)

Technical Support: http://www.cisco.com/techsupport

Copyright © 1986-2006 by Cisco Systems, Inc.

Compiled Fri 17-Nov-06 13:59 by prod_rel_team

 

ROM: ROMMON Emulation Microcode

ROM: 3600 Software (C3640-JS-M), Version 12.4(12), RELEASE SOFTWARE (fc1)

 

R1 uptime is 1 hour, 21 minutes

System returned to ROM by unknown reload cause - suspect boot_data[bOOT_COUNT] 0

x0, BOOT_COUNT 0, BOOTDATA 19

System image file is "tftp://255.255.255.255/unknown"

 

Cisco 3640 (R4700) processor (revision 0xFF) with 116736K/6144K bytes of memory.

Processor board ID 00000000

R4700 CPU at 100MHz, Implementation 33, Rev 1.2

4 Serial interfaces

DRAM configuration is 64 bits wide with parity enabled.

125K bytes of NVRAM.

8192K bytes of processor board System flash (Read/Write)

 

Configuration register is 0x2142

--More--

 

I will locate the line in bold. then i will add both values i.e. 116736 and 6144 and to convert it to MB, divide it by 1024, which gives me the value of 120.

 

(i am using dynamips and have given exactly 120 ram, so this calculation producess perfect result :-) ).

 

Now remember, machines are simply dumb, you need to tell them each and everything to solve the issue, because whether you realize it or not, you also require all the pieces together in order to solve the issue. You can sure make some assumptions, but that assumption is usually not completely random, its always based on some prior knowledge. But in case of computers, you have to tell them everything. Now lets break the above solution to MOST SIMPLISTIC STEPS.

 

1) Run the command show version

2) locate the line which contains the value i.e. 116737k/6144

3) Add both the values before and after "/"

4) Divide them by 1024

5) Display the result

 

Now as you can see, these steps cant be further broken down. Now lets solve them 1 by 1,

 

1) set version [exec show version]

 

 

Now for second step, we have to go a bit more DEEPER. Here starts the most important topic

 

PARSING THE GIVEN INPUT FOR A SPECIFIC STRING.

 

Q) whats a string ?

A) String is the collection of characters. Everything you type whether a number or a letter is essentially a character. So what ever we type, if it contains more then 1 character, it will become string. So this whole tutorial can be thought of a very large string.

 

Q) what do you mean by parsing the string ?

A) Parsing the string means, going through the string looking for something. Like in our case, i will parse (look through) show version output to locate the line containing the DRAM values.

 

So how to search in a given string ?. There are usually 2 methods that i use

 

1) Taking the input, splitting it till i get to the value i want.

2) Using regular expression.

 

I wont be using method 1 till i have no other way. In start i used it alot but you will realize as i did, its better to get comfortable with regular

expressions. They are fast and easy way to search for a given string.

 

CCNP guys must have played with BGP and surely regexp. Those who havent, you must do it. I will be giving a brief tutorial on how to use regexp.

 

Q) What are regular expression ?

A) They are more general/dynamic way of respresenting a given string.

 

Q) Oh yeah !!! i know i am being dumb but it actually went over my head you know !

A) Ok so just read on.

 

Lets consider the essentials of regular expression

 

. means anything. Including space, newline, anything

* means zero or more occurence of the character preceding this.

+ means one or more occurence of the character preceding it.

- defines the range

[] encloses the range

 

Q) ..... WHAT ??? i have seen regexp and they are lot more, you are cheating !!!!!!

A) Explanining regexp is not a part of this tutorial. I will be using a simplified approach to use regular expressions.

 

Lets practice it a bit

 

suppose i am giving you the following string

 

Hi, my height is 100 foot 11 inches. My color is fair, i have bright blue eyes and shiny hairs. Yesterday i had fever measuring 100. WOW !!

 

Q) Are you talking about yourself ?

A) Ofcourse not...

 

Now using regular expression, EXTRACT the fever value.

 

Now, focus the surrounding of the value you need to extract. "Yesterday i had fever measuring 100. WOW !!" and ALSO "Hi, my height is 100 foot 11 inches"

 

We need the second 100 value thats after word "measuring". So in my opinion, i will tell the regexp to get me the value that is after "measuring <space>". Rest is all garbage right ?

 

So in regexp, you must define what is garbage for you and what part is important. In our case, all what is before "measuring" is garbage, and all after 100 is garbage too. Garbage in regexp is denoted by ".*"

 

. means anything and * means zero or more times. So it becomes

 

anything (zero or more)times

. *

 

so our partial regular exp becomes

 

.* measuring

 

keep in mind, that we want to write a general expression so that it will give us any value that comes after measuring<space>. Since this value (fever) is expected to change (since i am telling you !!), you have to generalize this using regexp.

 

Fever value will always be a number. its length would be 2 - 3 digits ( am i right ?) )

 

so regular expression for fever value might be

 

[0-9][0-9][0-9] TADAAAAAAAAAAAAAAAAAAAAA!!!!

 

Nope its wrong. This may evaluate too

 

First[0-9] = 1

Second[0-9] = 0

Third[0-9] = 0

 

This is right but not 100%. Fever values are usually like 98,99,100,102,104 etc.

 

So the more appropriate regexp would be

 

[0-9]+

 

Now, this says that number from 0-9 can appear more then once. Strictly speaking, it satisfies our need. But what if a value is given with 4 digits ?, or extremely high fever like 300 which is not possible, so let me give you a relief that, we wont be going into that much complication. AS long as we are able to extract our needed value out of given input, we are fine.

 

So the complete regular expression becomes

 

".*measuring [0-9]+\."

 

Q) Why have you written "\." ?

A) As you know that "." is the regexp itself. I wanted to write period as it was appearing in statement, so for this purpose i add "\" telling the regexp that period is the literal value and not a regexp. Same is true for other regexp such as +,* etc. When you need to specify them as literals, just place a "\" before them.

 

Now the syntax for tcl is as follows

 

first lets assign this whole statement to a variable.

 

R1(tcl)#set var1 "Hi, my height is 100 foot 11 inches. My color is fair, i hav$

Hi, my height is 100 foot 11 inches. My color is fair, i have bright blue eyes a

nd shiny hairs. Yesterday i had fever measuring 100. WOW !!

R1(tcl)#

R1(tcl)# regexp {.*measuring ([0-9]+)\.} $var1 complete_string fever_value

1 <- 1 means match was found. 0 means match wasnt found

 

R1(tcl)# puts $fever_value

100

 

R1(tcl)#

 

Now lets see the syntax. Regular expression is written after regexp keyword and in curly braces. The value you need to actually extract is placed with round brackets within those curly braces. Then you place the variable containing the string that will be evaluated by the regexp followed by yet 2 more variables. The first variable will contain the complete string (which is useless to us) and second variable contains the value that will be extracted by the round brackets, which in our case will be value 100 as show in above example.

 

Now lets get back to our example of extracting DRAM values from the entire show version string.

 

First just pick up the line contaning the values.

 

"Cisco 3640 (R4700) processor (revision 0xFF) with 116736K/6144K bytes of memory."

 

Now if you have multiple platform, then the first value "Cisco 3640" is likely to change. Just run sh version on couple of routers and see which part of this line always remain constant. In my view it was the last 3 words " bytes of memory". You can verify this by looking at the entire ouput and making sure that these 3 words dont appear anywhere else, thus making this line unique.

 

Now first try to write your own regexp for this.

 

.

.

.

.

.

.

.

.

.

 

Well, mine is

 

".*([0-9]+)K/([0-9]+)K bytes of memory."

 

R1(tcl)#regexp {.*with ([0-9]+)K/([0-9]+)K bytes of memory.} $version complete_string first_val second_val

1

R1(tcl)#puts $first_val

116736

 

R1(tcl)#puts $second_val

6144

 

R1(tcl)#

 

Now add them and divide them with 1024 to get the final result

 

R1(tcl)#puts "the DRAM is [expr ($first_val + $second_val) / 1024]"

the DRAM is 120

 

R1(tcl)#

 

If you want to test this before hand, paste the following lines once you are in privilege mode

 

---------------------------------------------------

tclsh

 

set version [exec show version]

 

regexp {.*with ([0-9]+)K/([0-9])+K bytes of memory.} $version complete_string first_val second_val

 

puts "the DRAM is [expr ($first_val + $second_val) / 1024]"

 

Check to see, if you get the correct output or not :-).

 

---------------------------------------------------

 

Now, instead of going any further, just practice the above, by extracting different strings from different inputs. Like for example, extract the following from the show version output

 

1) IOS name

2) Model name

3) How much Flash

4) Configuration register value.

 

 

Trust me, it just needs a practice of 1 or 2 days. We will move on once you are bit comfortable with regexp, since we will be using them alot. There would be rarely a script that will be written without them.

 

This is just the start. These are not TCL based EEM scripts but they use similar logic. I will be writing more if you guys are getting what i am explaining here. Just give it a little effort and you will never regret it.

 

Let me know of your feedback so i may write more. Plus, in your feedback, provide the regexp (complete scripts) for extracting all the 4 values i mentioned so i will also tell me that you actually learned something from this tutorial :-)

Edited by pappyaar
0

Share this post


Link to post
Share on other sites

Thank you! A very nice Christmas's present for us all!

0

Share this post


Link to post
Share on other sites

Hi all. if you completed the assignment then you probably have some idea about how to use regexp.

 

Q) Why are they so important ?

A) Like i said in start, most of the time, we will be parsing some input for some value and doing some configuration after. But this is not it, not all our tcl scripts will be event based. Like the previous one in which we calculated the DRAM, that was a simple TCL script. The goal of these tutorials is to get you working with TCL based EEM scripts. Which we will not start yet :-)

 

Q) WHY !!!!

A) Because you are not ready yet...

 

Q) When do you think i will be ready ?

A) After completing my assignments ...

 

There are lots of resources on understanding regexp, and explaining them so that a totally newcomer understands it, is i think out my scope but i will still try. And for your comfort, we will use simple IOS for now.

 

Any Cisco guy will be well aware with the following command

 

R1# sh run | include <reg exp>

 

Now if you knew it or not, when you use pipe "|", after include/begin/exclude you have been giving regexp all the time.

 

Q) No, thats a bluff, i havent read it on any cisco doc !!

A) How many cisco docs have you read on this topic ?

 

Q) None...

A) Yeah right

 

Q) But i have been writing the name of complete commands, how could that be a regexp ?

A) Ok tell me what you have been writing ?

 

Q) Like for example, i want to show all the routes in my running-config so this is what i do

sh running-config | include ip route

A) So what makes you think you havent typed a reg exp here ?

 

Q) You dont understand !!, there is no regexp here, i didnt use "*", ".", "+" etc any of the regexp operators here.

A) Now i understand your confusion.

 

There is one thing that we call "regular expression engine". Suppose you open a document, and want to search for all the ip addresses in it. How will you search it using simple notepad or wordpad ? As far as i know, you cant so dont consider regexp something that you can skip and move on.

 

Regexp are ways of defining a string in more general way.

 

For example, this whole tutorial could be represented by a regexp ".*". Regular expression engine, is basically a software that can evaluate your given regexp and searches the document for all the strings represented by that regexp.

 

Lets take a simple example. I want my router to display all the ip addresses in running config, whether appearing in ip route, protocols, interface, where ever. I just want all the ip addresses to be displayed using

 

show running | include <regexp>

 

First see the format for an ip address in context of a simple string

 

1) 10.1.10.1

2) 192.168.23.1

 

Taking 1) Follow me carefully.

i have a number 10 followed by a period then again i have a number 1 followed by a period, then again i have number 10 followed by period, then i have number 1.

It was too specific, lets make this statement a bit general

 

I have a number, followed by a period, then again i have a number, followed by a period, again a number followed by a period, again a number

 

Well, it was TOO GENERAL. What shall be the length of the number ? ask yourself.

 

Q) You mean to say the valid range like 0-255 ?

A) NO, i mean how many digits will every number contains ?

 

Q) Well, it could be one, two or three digits !

A) So the statement should be

 

I have a number of 1/2/3 digits followed by a period, then again i have a number of 1/2/3 digits followed by a period and so on

 

Now as we know that this number could be from 0-255. The valid numbers are always "0 - 9" that will fit in a single digit. So how about the following

 

(0-9)(1/2/3 times)period(0-9)(1/2/3 times)period(0-9)(1/2/3 times)period(0-9)(1/2/3 times)

 

In regexp the ranges are always enclosed inside square brackets where hypen "-" is the range operator.

 

10-15 means 10, 11, 12, 13, 14, 15.

 

so 0-9 means 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

 

so (0-9) becomes [0-9]

but what about (1/2/3 times) ? how to represent this in regexp. Remember, there is a little IOS secret i will gonna tell you in the end. Just understand it for now that when ever you are sure that something will appear "ONE AND MORE TIMES" just place "+" sign after it and you are done. Dont care how many times it will repeat, like in our case, numbers 0-9 can come in 1 digit or 2 digit or 3 digit, we simply dont care about it, as long as we are expecting number 0-9 being repeated more then once, we will put a "+" sign in front of it.

 

[0-9]+.[0-9]+.[0-9]+.[0-9]+

 

Now since period "." is appearing here as a normal character in this string but is also a regexp operator, we must tell the regexp engine to treat this period as a literal(normal) character and no a regexp. So for this purpose we need to place "\" in front of it.

 

[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+

 

Now on router R1

 

R1#sh running-config | include ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)

ip address 192.168.0.1 255.0.0.0

ip address 10.0.0.1 255.0.0.0

network 10.0.0.1 0.0.0.0 area 1

network 20.0.0.1 0.0.0.0 area 1

ip route 40.0.0.0 255.0.0.0 10.0.0.2

R1#

 

It has shown each and every occurence of IP address found anywhere in the entire running config. So we can say that, show running-config employs a regexp engine and is verified through this example :-)

 

Now, for our tcl scripts, as long as you are able to come up with a regexp that extracts the needed value out from a string, you are good. No need to write sophisticated regexp. Although learning to write them will surely benefit you and i would recommend learning regexp to much greater depth.

 

Now about the secret. Remember that IOS works and displays information in a very static and predefined manner. Generally when you see regexp defining IP ADDRESSes are lot more complex then what i have shown above. The reason is, IP ADDRESSES will be stored in their correct format in running-config right ? so why should we waste our time verifying the integrity of them when its already verified by IOS !!. You will never see an ip address of this format

 

278.1.1.1 right ? in normal regexp tutorials, they will put a check of this, but in our case we dont need to because we already know that this is not possible in IOS. So IOS already verifies the integrity of commands and input so we dont need to do it again.

 

Q) Where is the secret in this ?

A) I was talking about the way IOS can ease your job when you dont have to perform integrity checks.

 

Q) You know what ? i think this is what we call "giving a lollypop", and you have done just that !!!

A) Well, the more you play with scripts, the more you will remember this secret and the more you will appreciate it.

 

Secondly, consider the following example.

 

Program 1)

 

Display the 5 top processes from "show processes cpu sorted"

 

Now lets first see the output. Run the following command on your router.

 

R1# sh processes cpu sorted

 

CPU utilization for five seconds: 0%/100%; one minute: 0%; five minutes: 0%

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

70 88 18063 4 0.08% 0.08% 0.08% 0 ACCT Periodic Pr

115 24 1160 20 0.08% 0.06% 0.06% 0 DHCPD Receive

215 52 5800 8 0.08% 0.05% 0.04% 0 CCPROXY_CT

76 56 18063 3 0.08% 0.08% 0.08% 0 IP ARP Retry Age

5 348 67 5194 0.00% 0.07% 0.04% 0 Check heaps

4 4 1 4000 0.00% 0.00% 0.00% 0 EDDRI_MAIN

7 0 2 0 0.00% 0.00% 0.00% 0 Timers

3 0 1 0 0.00% 0.00% 0.00% 0 chkpt message ha

6 0 1 0 0.00% 0.00% 0.00% 0 Pool Manager

8 4 2 2000 0.00% 0.00% 0.00% 0 ATM AutoVC Perio

11 0 1 0 0.00% 0.00% 0.00% 0 IPC Zone Manager

12 4 583 6 0.00% 0.00% 0.00% 0 IPC Periodic Tim

13 8 583 13 0.00% 0.00% 0.00% 0 IPC Deferred Por

9 4 2 2000 0.00% 0.00% 0.00% 0 ATM VC Auto Crea

2 8 117 68 0.00% 0.00% 0.00% 0 Load Meter

16 28 582 48 0.00% 0.00% 0.00% 0 EnvMon

17 0 1 0 0.00% 0.00% 0.00% 0 OIR Handler

10 0 10 0 0.00% 0.00% 0.00% 0 IPC Dynamic Cach

1 68 928 73 0.00% 0.00% 0.00% 0 Chunk Manager

20 4 610 6 0.00% 0.00% 0.00% 0 ARP Background

21 0 2 0 0.00% 0.00% 0.00% 0 ATM Idle Timer

--More--

 

Now, if you focus a bit, you will see that processes will usually jump up and down in this result. At sometime, you may see IP-Input at top, sometime SSH process coming up. If you have a production router, try running this command frequently and you will see that the results are never constant and ofcourse they cant be, different processes are invoked and killed/terminated along the way so there is no way this output can ever be constant. The point is, regexp arent of much use here. Regexp will serve you best, when the given input is itself constant or static. Still confused ? Dont be, lets try to solve this issue on the paper.

 

The requirement is to collect first 5 top processes.

 

1) Run "show process cpu sorted"

2) Parse the output. First line starting with "CPU utilization for five ..." is not important, since it doesnt contains information of processes.

3) Second line is the start of table with headings PID, Runtime(ms) etc, this is also not important.

4) Fourth line contains the first process PID and last column of this fourth line contains the process name. So we have found our top first process.

5) Fifth line contains the second process.

6) Sixth line contains the third process.

so on

 

Now remember, if you figure out a way to solve this problem through regexp alone, then thats wonderful. When you are writing scripts, it depents completely on you as to how you solve it. Proper established programmers may know a lot more decent and recommended ways of solving these issues but since we are beginning this journey, there is only 1 goal in front of us. Write a script to get a task done. SIMPLE !!!

 

So in order to solve this issue we will use two techniques.

 

1) Splitting the string

2) Indexing the splitted string.

 

Now lets see what do we mean by doing some practical. I want to split the "sh processes cpu sorted" output in individual lines.

 

Q) WHY ??

A) Show some patience and you will see ...

 

Q) I tried this command but it said, invalid input detected !

A) Yeah right

 

 

Ok, first store the output in a variable like this

 

R1(tcl)#set process_output [exec show process cpu sorted]

CPU utilization for five seconds: 2%/100%; one minute: 0%; five minutes: 0%

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

166 140 20 7000 2.04% 0.19% 0.04% 0 Tcl Serv - tty0

76 92 74605 1 0.16% 0.09% 0.08% 0 IP ARP Retry Age

84 252 251 1003 0.16% 0.19% 0.06% 0 Exec

42 452 2415 187 0.08% 0.03% 0.00% 0 Per-Second Jobs

115 24 4780 5 0.08% 0.06% 0.08% 0 DHCPD Receive

88 24 9338 2 0.08% 0.02% 0.00% 0 SSS Feature Time

48 20 480 41 0.08% 0.01% 0.00% 0 Compute load avg

70 136 74606 1 0.08% 0.09% 0.08% 0 ACCT Periodic Pr

33 4 2391 1 0.08% 0.00% 0.00% 0 GraphIt

108 16 4668 3 0.08% 0.00% 0.00% 0 Inspect process

10 0 40 0 0.00% 0.00% 0.00% 0 IPC Dynamic Cach

......

R1(tcl)#

 

Now just for the sake of practice, verify if process_output contains the result.

 

R1(tcl)# puts $process_output

CPU utilization for five seconds: 2%/100%; one minute: 0%; five minutes: 0%

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

166 140 20 7000 2.04% 0.19% 0.04% 0 Tcl Serv - tty0

76 92 74605 1 0.16% 0.09% 0.08% 0 IP ARP Retry Age

84 252 251 1003 0.16% 0.19% 0.06% 0 Exec

42 452 2415 187 0.08% 0.03% 0.00% 0 Per-Second Jobs

115 24 4780 5 0.08% 0.06% 0.08% 0 DHCPD Receive

88 24 9338 2 0.08% 0.02% 0.00% 0 SSS Feature Time

48 20 480 41 0.08% 0.01% 0.00% 0 Compute load avg

70 136 74606 1 0.08% 0.09% 0.08% 0 ACCT Periodic Pr

33 4 2391 1 0.08% 0.00% 0.00% 0 GraphIt

108 16 4668 3 0.08% 0.00% 0.00% 0 Inspect process

10 0 40 0 0.00% 0.00% 0.00% 0 IPC Dynamic Cach

......

R1(tcl)#

 

Note: In all Tcl tutorials, remember that you are free to choose any name for your variables. I choose them as i like so the variable process_output can have any different name as per you liking.

 

Now to split an output, you have to first decide, what "character" do you need the string to be split at. Now before going any further, lets clarify this point.

 

Suppose i give the following line.

 

Hi. My name is blah blah. I study in blah blah. My favourite hobbies are blah blah. My best friend is blah blah. I hope you like this blah blah.

 

Now i want to split this entire string on character "period" (.). Lets see

 

R1(tcl)# set sample "Hi. My name is blah blah. I study in blah blah. My favourite hobbies are blah blah. My best friend is blah blah. I hope you like this blah blah."

Hi. My name is blah blah. I study in blah blah. My favourite hobbies are blah bl

ah. My best friend is blah blah. I hope you like this blah blah.

R1(tcl)#puts $sample

Hi. My name is blah blah. I study in blah blah. My favourite hobbies are blah bl

ah. My best friend is blah blah. I hope you like this blah blah.

 

R1(tcl)#

 

This is one whole string in a single line. I want to divide(split) it, whenever a period (.) comes. The syntax is as follows

 

split $<variable-name> "<splitting character in inverted commas>"

 

R1(tcl)#split $sample "."

Hi { My name is blah blah} { I study in blah blah} { My favourite hobbies are bl

ah blah} { My best friend is blah blah} { I hope you like this blah blah} {}

R1(tcl)#

 

Over here, { } denotes the splitted parts. As you can see, there are no periods(.) anywhere in the string anymore. They are used to split the entire string. This splitting has one advantage, which infact is the cause we are splitting this string. And that is indexing. And this is how its done

 

lindex [split $<variable-name> "splitting character"] <index-number>

 

R1(tcl)#lindex [split $sample "."] 0

Hi

R1(tcl)#lindex [split $sample "."] 1

My name is blah blah

R1(tcl)#lindex [split $sample "."] 2

I study in blah blah

R1(tcl)#lindex [split $sample "."] 3

My favourite hobbies are blah blah

R1(tcl)#lindex [split $sample "."] 4

My best friend is blah blah

R1(tcl)#lindex [split $sample "."] 5

I hope you like this blah blah

R1(tcl)#

 

Q) Ok, i see what is happening, but i still didnt get the purpose. Why are you wasting my TIME !!!!!

A) I asked to show some patience and you tried that on your router console. Be patient and see how we will use split-index technique to solve our original problem

 

Q) What original problem ?

A) The get the top 5 processes !!

 

Q) When did you give this problem ? where was i ?

A) Never mind.

 

Now just review the solution on paper i gave regarding the original problem. The first process will always be on 3rd line. 4th process will always be on 5th line. This is what we have observed after seeing the output. IOS is very rigid in producing its output. Most of the time, you will easily get such patterns that will help you to easily parse and find your required object. Just for a brief review, lets do it again

 

 

R1#sh processes cpu sorted

CPU utilization for five seconds: 1%/100%; one minute: 0%; five minutes: 0%

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

5 2072 399 5192 0.40% 0.06% 0.05% 0 Check heaps

84 420 587 715 0.08% 0.00% 0.00% 0 Exec

70 168 110823 1 0.08% 0.08% 0.08% 0 ACCT Periodic Pr

215 72 35488 2 0.08% 0.04% 0.06% 0 CCPROXY_CT

115 24 7098 3 0.08% 0.05% 0.08% 0 DHCPD Receive

76 128 110822 1 0.08% 0.08% 0.08% 0 IP ARP Retry Age

88 28 13867 2 0.08% 0.01% 0.00% 0 SSS Feature Time

65 4 3468 1 0.08% 0.00% 0.00% 0 Ethernet Timer C

8 4 2 2000 0.00% 0.00% 0.00% 0 ATM AutoVC Perio

7 0 2 0 0.00% 0.00% 0.00% 0 Timers

9 4 2 2000 0.00% 0.00% 0.00% 0 ATM VC Auto Crea

6 0 1 0 0.00% 0.00% 0.00% 0 Pool Manager

13 20 3552 5 0.00% 0.00% 0.00% 0 IPC Deferred Por

10 0 60 0 0.00% 0.00% 0.00% 0 IPC Dynamic Cach

2 8 711 11 0.00% 0.00% 0.00% 0 Load Meter

16 28 3551 7 0.00% 0.00% 0.00% 0 EnvMon

4 4 1 4000 0.00% 0.00% 0.00% 0 EDDRI_MAIN

11 0 1 0 0.00% 0.00% 0.00% 0 IPC Zone Manager

3 0 1 0 0.00% 0.00% 0.00% 0 chkpt message ha

20 4 3708 1 0.00% 0.00% 0.00% 0 ARP Background

12 8 3552 2 0.00% 0.00% 0.00% 0 IPC Periodic Tim

--More--

 

R1#

 

Now remember, indexing in tcl and other languages usually start from 0 and not 1. So the first line will be at index 0, second line at index 1 and so on.

 

Lets store the output and split it.

 

R1(tcl)#set process_output [exec show process cpu sorted]

CPU utilization for five seconds: 0%/84%; one minute: 0%; five minutes: 0%

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

70 172 115081 1 0.16% 0.09% 0.08% 0 ACCT Periodic Pr

76 132 115080 1 0.08% 0.08% 0.08% 0 IP ARP Retry Age

215 72 36852 1 0.08% 0.04% 0.06% 0 CCPROXY_CT

115 28 7370 3 0.08% 0.06% 0.08% 0 DHCPD Receive

84 528 680 776 0.08% 0.10% 0.03% 0 Exec

5 2160 414 5217 0.00% 0.07% 0.05% 0 Check heaps

6 0 1 0 0.00% 0.00% 0.00% 0 Pool Manager

8 4 2 2000 0.00% 0.00% 0.00% 0 ATM AutoVC Perio

7 0 2 0 0.00% 0.00% 0.00% 0 Timers

2 8 739 10 0.00% 0.00% 0.00% 0 Load Meter

9 4 2 2000 0.00% 0.00% 0.00% 0 ATM VC Auto Crea

12 8 3688 2 0.00% 0.00% 0.00% 0 IPC Periodic Tim

13 20 3688 5 0.00% 0.00% 0.00% 0 IPC Deferred Por

10 0 62 0 0.00% 0.00% 0.00% 0 IPC Dynamic Cach

4 4 1 4000 0.00% 0.00% 0.00% 0 EDDRI_MAIN

--More--

 

R1(tcl)#

 

Now, over here, i want to split the string whenever a new line starts. So that i can get the whole line. If you want someother criteria feel free to experiment with it, just remember, the main goal for now is to get the task done. I decided to use "newline character" denoted by this special form "\n" Those who are familiar with programming should be knowing this character. Those who dont, just understand that "\n" means a newline character.

 

So lets first split the output with newline

 

R1(tcl)# split $process_output "\n"

 

...... (you will see lots of lines again)

 

Now to get the required lines, we will use indexing.

 

R1(tcl)#lindex [split $process_output "\n"] 0

CPU utilization for five seconds: 0%/84%; one minute: 0%; five minutes: 0%

R1(tcl)#lindex [split $process_output "\n"] 1

PID Runtime(ms) Invoked uSecs 5Sec 1Min 5Min TTY Process

R1(tcl)#lindex [split $process_output "\n"] 2

70 172 115081 1 0.16% 0.09% 0.08% 0 ACCT Periodic Pr

R1(tcl)#lindex [split $process_output "\n"] 3

76 132 115080 1 0.08% 0.08% 0.08% 0 IP ARP Retry Age

R1(tcl)#lindex [split $process_output "\n"] 4

215 72 36852 1 0.08% 0.04% 0.06% 0 CCPROXY_CT

R1(tcl)#lindex [split $process_output "\n"] 5

115 28 7370 3 0.08% 0.06% 0.08% 0 DHCPD Receive

R1(tcl)#lindex [split $process_output "\n"] 6

84 528 680 776 0.08% 0.10% 0.03% 0 Exec

R1(tcl)#

 

 

AS you can see, we are able to extract 5 top processes using splitting and indexing. It wasnt too difficult right ?

 

Q) What ?

A) Splitting and indexing..

 

Q) YEAH, NOT AT ALL DIFFICULT, I THINK I WAS BORN WITH TCL IMPLANTED IN MY BRAIN. ARE YOU CRAZY, I AM DOING THIS FOR THE FIRST TIME AND GETTING THE WORST HEADACHE AND YOU ARE SAYING ITS NOT DIFFICULT !!

A) Well, there are something you ought to learn, whether the easy way or the hardway.

 

Those who have made this far will be questioning themselves, do we really need to do it ? may be i (pappyaar) have been a programming guru or have friends/teacher to help me out. But this is not the case. Even in my BS days, i didnt have anyone to help me out. I just learned programming by doing assignments that were given to us. I was able to write the pseudo-code (algorithm) which is 50% of programming i think. If you are able to solve the problem on paper, you just need to debug yourself and look cloesly how did you do it. What were the steps you have taken to complete this task. Your remaining job left now is to tell the computer in programming language to carry out the same steps in the same order. Thats it. Trust me programming is more fun then you could imagine.

 

Moreover, programming gives a self satisfaction that you have done it something completely by yourself. The more you get in programming, the more understanding you will get of underlying concepts.

 

Till next part, i want you to practice regexp and splitting-indexing, so that your parsing and searching skills become strong. If you guys are comfortable till this part, let me know with your feedback, so that i will start with TCL based EEM scripts.

1

Share this post


Link to post
Share on other sites

You completely nailed this damn TCL .I am reading this and found handy as compared to CNAP or other books stuff. Definitely it must be a "post of the month" but hey you got this title before :).

0

Share this post


Link to post
Share on other sites

You completely nailed this damn TCL .I am reading this and found handy as compared to CNAP or other books stuff. Definitely it must be a "post of the month" but hey you got this title before :).

 

Dear Faisal, its good to hear that its helping you guys getting a grip of it. I am currently writing more on this topic and would be doing so in the coming week i hope. But for a little disappointment, i wont be starting tcl based eem scripts yet. I want to make sure that readers are well versed in searching and identifying objects from the given input which requires little skillset to be developed. After 1 or 2 parts i will be starting the main event :-)

 

So stay tuned ;-)

0

Share this post


Link to post
Share on other sites

Hi all. In previous tutorials we covered the following topics

 

1) Introduction to TCL scripting in IOS.

2) How to run IOS commands from within TCL shell using exec and ios_config keyword

3) Basics of tcl like variables, displaying on screen, expr keyword for mathematical operations.

4) Use of regexp to play with regular expressions

5) Use of split and lindex keyword to split and index the splitted string.

 

In this part, we will learn how to do configuration by parsing some input. This will be a bit long example so make sure you are grasping all the stuff.

 

Script 1)

 

Write a script to check if your LAN interface is made passive under router ospf <process-id> or not. If its not, then make it a passive interface.

Now the question arises, how would you determine your lan interface ? Are you using same model throughout and are sure that a ---- interface is always your LAN interface ? or are you following a particular subnet scheme for your private network that might help us identify your lan interface ?

Now being a network administrator, you already know what format does your private ip address follows. In my case, i can say that my LAN IP has 10 in first octet and 1 in last octet.

 

10.x.x.1

 

Now looking at this assumption carefully, i can say that although its correct but somewhere in 160+ branches, i may have a tunnel ip or WAN ip of this sort

 

as well. Its less likely but the possibility is still there. So what else i can do to make sure that the interface selected is indeed my LAN interface.

 

Thinking ..........

.

.

.

 

Thinking ..........

 

Q) How much will you think ?

A) Ok dont worry i figured it out.

 

All of my LAN interface contains word "LAN" in their description. So my first check would be

 

1) Check all the interfaces and their IP address to see which contains 10.x.x.1

2) Identify the interface from step 1 and make sure its description contains word "LAN"

 

Ok lets first solve it on paper

 

1) Run show ip int brief.

2) Parse the output to see which "LINE" contains the ip address of format 10.x.x.1

3) When found, note down the interface name

4) Run show run interface <interface-name>

5) Parse the output and pick the "LINE" containing the word description.

6) Parse the picked line to see if it contains word "LAN".

7) If yes, then make this interface passive under router ospf <id>

 

Now this is a simple overview of solving it. Consider the following output.

 

R1#sh ip int brief

Interface IP-Address OK? Method Status Prot

ocol

Loopback0 10.1.1.1 YES manual up up

 

Loopback1 192.168.0.1 YES manual up up

 

Loopback2 192.167.0.1 YES manual up up

 

Loopback4 192.147.0.1 YES manual up up

 

Loopback5 192.145.0.1 YES manual up up

 

Loopback78 10.45.0.1 YES manual up up

 

R1#

 

As you can see that loopback 0 and 78 contains the ip address of lan format (10.x.x.1). You have to parse each and every line of "show ip int brief" in order to make sure you have checked all the ip addresses. So what will you do when you have to do a task repeatedly ?

 

This is called LOOPING in programming.

 

Looping means to perform a task more than 1 times. It means that, either that task will be done indefinetly (infinite loop) or will end when the ending criteria is met.

 

So lets see how looping is done in TCL. The most basic loops that you will encounter are For loops, While loops, and Foreach loops. Each of them serve the same purpose i.e. looping but in a different manner. Mostly you will be using For and while loops. Now i am not a programming guru but as far as i know, we didnt had foreach loops back in C language. But they are extremely useful in traversing the lists.

 

Q) What are lists ?

A) Lists are simply collection of data. For example, if you want to store a 10 ip addresses to later use them, what will you do ?

 

Q) Well, i will use 10 variables to store them

A) Exactly, that is 100% correct. But tcl and other languages provide another feasible way of storing such values in a single variable. This variable is of type list. It means that all the values are kept inside a single name but with increasing index.

 

Q) It all went over my head, AGAINNNNNNN !!

A) Ok ok, consider this

 

We want to store 10 ip address, using variable approach it will become

 

set ip_addr1 10.1.1.1

set ip_addr2 10.2.1.1

set ip_addr3 10.3.1.1

..

 

using list approach, it will become

 

R1(tcl)#set ip_addr {10.1.1.1 10.2.1.1 10.3.1.1 10.4.1.1 10.5.1.1}

10.1.1.1 10.2.1.1 10.3.1.1 10.4.1.1 10.5.1.1

R1(tcl)#

 

To refer individual elements inside this list, we will use well-known "lindex" keyword ;-)

 

R1(tcl)#lindex $ip_addr 0

10.1.1.1

R1(tcl)#lindex $ip_addr 1

10.2.1.1

R1(tcl)#lindex $ip_addr 2

10.3.1.1

R1(tcl)#lindex $ip_addr 3

10.4.1.1

R1(tcl)#lindex $ip_addr 4

10.5.1.1

R1(tcl)#

 

Q) There is something fishy going on !!

A) What ?

 

Q) You think i am stupid ?

A) Yes....

 

Q) No i am not. You are teaching me programming and this is where we are going. You are no way near IOS, you will divert your path and take me somewhere else, i need my money back !!!

A) I dont remember you paying anything !

 

Q) Doesnt matter, i still want it back !

A) Better stay calm. Scripting, whether done generally or in IOS requires some fundamentals to know

 

Q) How much more FUNDAMENTALS do we need now ?

A) A few more...

 

Ok now lets see how looping actually works. Suppose you want to practice OSPF, to view its database, or to practice NAT or access-list. For that you decided to create 60 loopbacks each with different subnet or same subnet with different IPs. Normally it would require sometime if you start configuring loopback directly in IOS, we since we need to create 60 loopbacks i.e. a repeated task, therefore we can use TCL loops to accomplish this.

 

For this script, we will use a while loop.

 

"While" loop works in this way

 

while { $<variable-name> <test-condition> } {

body of the loop

..

..

}

 

Now to create 60 loopbacks, from 0 - 59, i shall have a variable which value starts from 0 and increases up to 59. For simplicity, the network of each loopback will be incremented in same fashion. like this

 

int loopback 0

ip add 10.0.1.1 255.255.0.0

 

int loopback 1

ip add 10.1.1.1 255.255.0.0

 

As you can see that loopback number and second octet are of same value, this is just for simplicity so we shall move on.

 

In while loops first we need to initialize the variable that will be incremented from 0 to 59.

 

R1(tcl)# set var 0

 

<test-condition> means to compare the variable with some test value and see if the critera meets. For example

 

While { $var1 < 60 } {

body

}

 

This means that, as long as the value of var1 is below 60, the body in the while loop will execute, as soon as the value reaches 60 or above, it will terminate.

 

While { $var1 == 60 } {

body

}

 

This means that, as long as the value of var1 is equal to 60, the body will execute, as soon as the value changes to other then 60, it will terminate.

 

Same is true for other conditions like ">" (greater than), "!=" (not equal to) etc

 

So lets create 60 loopbacks in a matter of seconds ;-)

 

R1(tcl)#while {$i <60} {

+>(tcl)#ios_config "int loopback $i" "ip address 10.$i.1.1 255.255.0.0"

+>(tcl)#incr i }

 

Note: incr i, "incr" is the special keyword that will increment the value of the variable by whatever value is given after the name of variable. If no value is given like in our case than the value is incremented by "1". We could have used expr keyword, it would have been 100% correct also.

 

now after pressing enter, this what comes up

 

R1(tcl)#

*Sep 28 20:34:03.279: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback0,

changed state to up

*Sep 28 20:34:03.283: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback1,

changed state to up

*Sep 28 20:34:03.287: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback2,

changed state to up

*Sep 28 20:34:03.291: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback3,

changed state to up

*Sep 28 20:34:03.295: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback4,

changed state to up

*Sep 28 20:34:03.299: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback5,

changed state to up

*Sep 28 20:34:03.303: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback6,

changed state to up

*Sep 28 20:34:03.307: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback7,

changed state to up

*Sep 28 20:34:03.311: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback8,

changed state to up

*Sep 28 20:34:03.315: %LINEPROTO-5-UPDOWN: Line protocol on Interface Loopback9,

 

 

R1(tcl)# show ip int brief

Note: i am not using exec keyword here, so remember, when you simply want to perform IOS command, just do it, but if you want to use that result in your scripts, use the exec keyword, SIMPLE !!

 

Interface IP-Address OK? Method Status Prot

ocol

FastEthernet0/0 unassigned YES unset administratively down down

 

Loopback0 10.0.1.1 YES unset up up

 

Loopback1 10.1.1.1 YES unset up up

 

Loopback2 10.2.1.1 YES unset up up

 

Loopback3 10.3.1.1 YES unset up up

 

Loopback4 10.4.1.1 YES unset up up

 

Loopback5 10.5.1.1 YES unset up up

 

Loopback6 10.6.1.1 YES unset up up

 

Loopback7 10.7.1.1 YES unset up up

 

Loopback8 10.8.1.1 YES unset up up

 

Loopback9 10.9.1.1 YES unset up up

 

--More--

..

.

.

Loopback48 10.48.1.1 YES unset up up

 

Loopback49 10.49.1.1 YES unset up up

 

Loopback50 10.50.1.1 YES unset up up

 

Loopback51 10.51.1.1 YES unset up up

 

Loopback52 10.52.1.1 YES unset up up

 

Loopback53 10.53.1.1 YES unset up up

 

Loopback54 10.54.1.1 YES unset up up

 

Loopback55 10.55.1.1 YES unset up up

 

Loopback56 10.56.1.1 YES unset up up

 

Loopback57 10.57.1.1 YES unset up up

 

Loopback58 10.58.1.1 YES unset up up

 

Loopback59 10.59.1.1 YES unset up up

 

R1(tcl)#

 

It just took a couple of seconds to configure this. Practice the same with For loop. This is your assignment.

 

Lets take a look at Foreach loop...

 

Q) Why ? why you skipped For loop and picked Foreach ?

A) Well, For is very similar to while, foreach is a bit different..

 

Q) How ?

A) That's exactly i was going to show if you could be a little patient.

 

Q) Ok, Fine, carry on

A) Where are you going ??

 

Q) Need a little break, but you please continue, i am sure i wont be missing anything !!

A) Yeah right

 

Ok now, those of you who have ever touched a CCIE blog, they must have seen one thing common, The final reachability testing done via tcl scripts. Thats a very small script but usually complicated with use of procedures and conditional statements. We will use foreach for exactly same purpose here so you can see how much simple it is. Following is the syntax

 

Foreach <variable-name> <list> {

body

..

..

}

 

Like, for example i have a list containing numbers 0 - 9, and i want to print them

 

R1(tcl)#foreach var1 {0 1 2 3 4 5 6 7 8 9 } {

+>(tcl)#puts $var1 }

0

1

2

3

4

5

6

7

8

9

 

R1(tcl)#

 

Now lets ping some of the IPs we configured in last step

 

R1(tcl)#foreach var1 {

+>(tcl)#10.0.1.1

+>(tcl)#10.1.1.1

+>(tcl)#10.2.1.1

+>(tcl)#10.3.1.1

+>(tcl)#} { exec [ping $var1] }

 

Type escape sequence to abort.

Sending 5, 100-byte ICMP Echos to 10.0.1.1, timeout is 2 seconds:

!!!!!

Success rate is 100 percent (5/5), round-trip min/avg/max = 1/3/8 ms

Type escape sequence to abort.

Sending 5, 100-byte ICMP Echos to 10.1.1.1, timeout is 2 seconds:

!!!!!

Success rate is 100 percent (5/5), round-trip min/avg/max = 4/4/8 ms

Type escape sequence to abort.

Sending 5, 100-byte ICMP Echos to 10.2.1.1, timeout is 2 seconds:

!!!!!

Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/1 ms

Type escape sequence to abort.

Sending 5, 100-byte ICMP Echos to 10.3.1.1, timeout is 2 seconds:

!!!!!

Success rate is 100 percent (5/5), round-trip min/avg/max = 1/1/4 ms

R1(tcl)#

 

Lets look at the last fundamental of this tutorial. The famous IF-ELSE control structure.

 

IF-ELSE represent the action to be taken if a condition mets.

 

 

R1(tcl)#set var1 0

0

R1(tcl)#if {$var1 == 0} {

+>(tcl)#puts "yes the value is zero"

+>(tcl)#} else { puts " no the value is not zero" }

yes the value is zero

 

R1(tcl)#

 

Ok, now, just practice a little bit and you will get comfortable with it in no time.

Lets get back to our original problem, to identify LAN subnets and making sure these interfaces are passive under ospf.

 

 

R1(tcl)#sh ip int brief

Interface IP-Address OK? Method Status Prot

ocol

FastEthernet0/0 unassigned YES unset administratively down down

 

Loopback0 10.1.1.1 YES manual up up

 

Loopback1 192.168.0.1 YES manual up up

 

Loopback2 192.167.0.1 YES manual up up

 

Loopback4 192.147.0.1 YES manual up up

 

Loopback5 192.145.0.1 YES manual up up

 

Loopback78 10.45.0.1 YES manual up up

 

R1(tcl)#

 

 

Ok now, lets see how i solve this issue. You can surely try to come up with your own solution. Right now, i dont care how much line my script takes, as long as i am able to do what i intend to do, that is fine with me.

 

To ease the solution, we will use the builtin regexp engine to select only those interfaces that have IPs of this format

 

10.x.x.1

 

R1(tcl)#set show_int [exec show ip int brief | in 10\..*\.1]

Loopback0 10.1.1.1 YES manual up up

 

Loopback78 10.45.0.1 YES manual up up

 

R1(tcl)#puts $show_int

Loopback0 10.1.1.1 YES manual up up

 

Loopback78 10.45.0.1 YES manual up up

 

 

R1(tcl)#

 

Q) What ?? what kind of a regexp is this ?

A) I told you to practice it

 

Q) I did, but still i dont get it

A) Then practice a little more.

 

Q) Thanks for HELPING ME, I DONT KNOW HOW CAN I EVER REPAY YOU :-S

A) Nevermind

 

So, we get our needed interfaces. So lets extract the interfaces names first

 

First i will split them to 2 different lines

 

R1(tcl)#set int_name [split $show_int "\n"]

{Loopback0 10.1.1.1 YES manual up up

 

} {Loopback78 10.45.0.1 YES manual up u

p }

R1(tcl)#puts $int_name

{Loopback0 10.1.1.1 YES manual up up

 

} {Loopback78 10.45.0.1 YES manual up u

p }

 

R1(tcl)#

 

To verify, that we have splitted it, try using the lindex keyword

 

R1(tcl)#lindex $int_name 0

Loopback0 10.1.1.1 YES manual up up

 

R1(tcl)#lindex $int_name 1

Loopback78 10.45.0.1 YES manual up up

 

R1(tcl)#

 

Now to extract the names, we will use regexp

 

 

R1(tcl)#regexp {(Loopback[0-9]+).*} [lindex $int_name 0] complete_string loop_name

1

R1(tcl)#puts $loop_name

Loopback0

 

R1(tcl)#ios_config "router ospf 10" "passive-interface $loop_name"

 

R1(tcl)#regexp {(Loopback[0-9]+).*} [lindex $int_name 1] complete_string loop_$

1

R1(tcl)#puts $loop_name

Loopback78

 

R1(tcl)#ios_config "router ospf 10" "passive-interface $loop_name"

 

 

Mission Accomplished. See, it wasnt that difficult

 

Q) You have been doing this for ages, ofcourse its not difficult for you, you are being a show off !!!

A) Yeah right

 

Few months back, we were having off for like 3-4 days. May be they were EID holidays i think. I didnt had good internet at home and i was expecting to access the routers just in case any problem arises. The issue was with the access-list applied on vty lines. The pool that vpn client was getting was different and surely not allowed in that list. I needed to write a script, that would recognize me when i connect via vpn, and grant my IP in the access-list. The ip will be removed as soon as i logout. I started in afternoon and completed this small and easy task after 5-6 hours. My head went spinning for 2 days but trust me, it was fun :-)

 

For now, dont be scared for what you have seen so far. Scripting is a lot easier if you do regular practice.

 

Let me know if there is any part that confuses you. Anything at all...

 

Q) Hey, i just reviewd the question, you have not completed it the way you should have, where is the interface description check ?

A) Well, i skipped it to see if you were sleeping or not..

 

Q) Well i wasnt ?

A) Good, so this is your assignment, perform this check and let me know how you did it

 

Q) WHAT ?????????

A) See you in the next part...

0

Share this post


Link to post
Share on other sites

Dear Darkfiber, thanks for appreciating, i hope it helps everyone out here :-). Yes i knew about this book and i am expecting it to fill the gaps between how to actually use it with EEM. Currently i am using some predefined code snippet (mainly to run ios commands using cli_open, cli_close etc calls). So lets see if this book provides more information on the background of these codes. I wasnt able to understand them fully from cisco site itself. But still, considering them static piece of code, the rest of the script is really fun to write :-)

0

Share this post


Link to post
Share on other sites

Hi Pappyaar,

 

Very Nice Topic,But ia have a doubt in this like why u didn't specify the literal symbol in the given given exp below as you have specified in the first example.

R1(tcl)#regexp {.*with ([0-9]+)K/([0-9]+)K bytes of memory.} $version complete_string first_val second_val

 

Let me know waht is that period and literal means.Thanks in advance for your reply.Awaiting your response.

0

Share this post


Link to post
Share on other sites

Dear jalakampradeep, kindly elaborate your question since i didnt get what you mean :-). Highlight the first example and the expression you have given, and also highlight the point of confusion so i may clear it.

 

Waiting....

0

Share this post


Link to post
Share on other sites

thank you pappyaar for posting this wonderful topic..i have studied this and practiced simultaneously in gns3..Can you post more information?

0

Share this post


Link to post
Share on other sites

Wonderfully explained !!

It would be great if you can show us regex uses with multiple lines lik return the linecard number if a port belongs to vlan 10 and is up from show output

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0