Tuesday, October 15, 2013

How to test/simulate an event to trigger an event script



instead of waiting for an event to happen you can generate an event using the logger command from the cli.

First you need to get the attribute of the event if you want to pass an argument to the script. Use "help syslog <command>" 
jnpr@router> help syslog UI_CHILD_EXITED    
Name:          UI_CHILD_EXITED
Message:       Child exited: PID <pid>, status <return-value><core-dump-status>, command '<command>'
Help:          Child process of mgd exited

In help syslog the attribute will be displayed inside the <> bracket.
pid, return-value, core-dump-status, and command are the attributes



jnpr@router# show event-options
policy test {
    events ui_child_exited;
    then {
        event-script test.slax {
            arguments {
                mib "{$UI_CHILD_EXITED.pid}";
            }
            output-filename ARG;
            destination local;
        }
    }
}
destinations {
    local {
        archive-sites {
            "ftp://user:password@192.168.1.1";
        }
    }
}


go into shell as root and then issue the logger command

logger [-e event-id/tag] [-p priority] [-d daemon] [-a attr=value]
       [message]

root@router% logger -e UI_CHILD_EXITED -a "pid=111" test-syslog-message


jnpr@router# run show log messages
Jun 30 23:57:45 router clear-log[6242]: logfile cleared
Jun 30 23:58:01  router logger: UI_CHILD_EXITED: test-syslog-message
Jun 30 23:58:02  router root: invoke-commands: Executed /tmp/evt_cmd_k0dUOC, output to /tmp/evt_op_YRuPs6 in text format
Jun 30 23:58:02  router ftpd[6259]: connection from 192.168.1.1 (192.168.1.1)
Jun 30 23:58:02  router ftpd[6259]: FTP LOGIN FROM 192.168.1.1 as user
Jun 30 23:58:02  router root: transfer-file: Transferred /tmp/evt_op_YRuPs6


[edit]
jnpr@router# run file show router_ARG_20090701_065802


root@router> op test.slax mib "111"

111


------------------
script
------------------

root@router% more test.slax
version 1.0;

ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";

import "../import/junos.xsl";
var $arguments = <argument> {
    <name> "mib";

}
param $mib;

match / {
    <op-script-results> {

        <output method = "text"> {

                    expr $mib;
            <xsl:document href = "/var/home/jnpr/text.txt"> {
                copy-of $mib;
            }
        }
    }


Monday, October 14, 2013

How to map a specific VRF to a specific LSP


s there a way to bind a particular VRF to an MPLS LSP? I have 5 VRFs and 5 LSPs to the same destination (Egress-PE2). I want each VRF to take a specific LSP.
By default the VRFs choose the LSPs randomly: 
jnpr@router# run show route table VRF1 
VRF1.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both
20.0.1.0/24        *[Static/5] 00:05:37
                    > to 192.2.1.2 via xe-1/0/0.2
10.0.1.0/24        *[BGP/170] 00:00:07, localpref 100, from 6.6.6.6
                      AS path: I
                      to 192.168.36.3 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-1
                    > to 192.168.36.3 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-2 <<<<<< Chosen LSP
                      to 192.168.36.3 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-3
                      to 192.168.36.3 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-4
                      to 192.168.36.3 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-5
Can I bind it say VRF1 chooses only lsp to-EGRESS-PE2-1?
Currently, VRF2 chooses only lsp to-EGRESS-PE2-2, etc...
Yes.

Config:
interfaces { 
    xe-0/0/0 { 
        unit 0 { 
            family inet { 
                address 192.168.15.5/24; 
            } 
            family mpls; 
        } 
    } 
    xe-0/1/0 { 
        description to-AGT-1601/1; 
        flexible-vlan-tagging; 
        encapsulation flexible-ethernet-services; 
        unit 2 { 
            vlan-id 2; 
            family inet { 
                address 192.2.1.1/24; 
            } 
        } 
        unit 3 { 
            vlan-id 3; 
            family inet { 
                address 192.2.2.1/24; 
            } 
        } 
    } 
    lo0 { 
        unit 0 { 
            family inet { 
                address 5.5.5.5/32; 
            } 
        } 
    } 
} 
routing-options { 
    autonomous-system 100; 
    forwarding-table { 
        export lspmap; 
    } 
} 
protocols { 
    rsvp { 
        interface all { 
            link-protection; 
        } 
        interface fxp0.0 { 
            disable; 
        } 
    } 
    mpls { 
        label-switched-path to-EGRESS-PE2-1 { 
            to 6.6.6.6; 
            bandwidth 1m; 
            node-link-protection; 
        } 
        label-switched-path to-EGRESS-PE2-2 { 
            to 6.6.6.6; 
            bandwidth 1m; 
            node-link-protection; 
        } 
        interface all; 
        interface fxp0.0 { 
            disable; 
        } 
    } 
    bgp { 
        group iBGP { 
            type internal; 
            local-address 5.5.5.5; 
            family inet { 
                any; 
            } 
            family inet-vpn { 
                any; 
            } 
            neighbor 6.6.6.6; 
        } 
    } 
    ospf { 
        traffic-engineering; 
        area 0.0.0.0 { 
            interface all; 
            interface fxp0.0 { 
                disable; 
            } 
        } 
    } 
} 
policy-options { 
    policy-statement lspmap { 
        term VRF1 { 
            from { 
                rib bgp.l3vpn.0; 
                community VRF1-COM; 
            } 
            then { 
                install-nexthop strict lsp to-EGRESS-PE2-1; 
                accept; 
            } 
        } 
        term VRF2 { 
            from { 
                rib bgp.l3vpn.0; 
                community VRF2-COM; 
            } 
            then { 
                install-nexthop strict lsp to-EGRESS-PE2-2; 
            } 
        } 
    } 
    community VRF1-COM members target:200:1; 
    community VRF2-COM members target:200:2; 
} 
routing-instances { 
    VRF1 { 
        instance-type vrf; 
        interface xe-0/1/0.2; 
        route-distinguisher 100:1; 
        vrf-target target:200:1; 
        vrf-table-label; 
        routing-options { 
            static { 
                route 20.0.1.0/24 next-hop 192.2.1.2; 
            } 
        } 
    } 
    VRF2 { 
        instance-type vrf; 
        interface xe-0/1/0.3; 
        route-distinguisher 100:2; 
        vrf-target target:200:2; 
        vrf-table-label; 
        routing-options { 
            static { 
                route 20.0.2.0/24 next-hop 192.2.2.2; 
            } 
        } 
    } 
} 


BEFORE
jnpr@router# run show route 10.0.1.0/24 

VRF1.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.0.1.0/24        *[BGP/170] 00:50:03, localpref 100, from 6.6.6.6
                      AS path: I
                      to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-1
                     > to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-2

bgp.l3vpn.0: 20 destinations, 20 routes (20 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

101:1:10.0.1.0/24                
                   *[BGP/170] 00:50:03, localpref 100, from 6.6.6.6
                      AS path: I
                      to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-1
                     > to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-2



AFTER

jnpr@router# run show route 10.0.1.0/24    

VRF1.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.0.1.0/24        *[BGP/170] 00:00:06, localpref 100, from 6.6.6.6
                      AS path: I
                    > to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-1

bgp.l3vpn.0: 20 destinations, 20 routes (20 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

101:1:10.0.1.0/24                
                   *[BGP/170] 00:50:29, localpref 100, from 6.6.6.6
                      AS path: I
                    > to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-1


[edit]
jnpr@router# run show route 10.0.2.0/24    

VRF2.inet.0: 5 destinations, 5 routes (5 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

10.0.2.0/24        *[BGP/170] 00:00:18, localpref 100, from 6.6.6.6
                      AS path: I
                      to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-2

bgp.l3vpn.0: 20 destinations, 20 routes (20 active, 0 holddown, 0 hidden)
+ = Active Route, - = Last Active, * = Both

101:2:10.0.2.0/24                
                   *[BGP/170] 00:50:41, localpref 100, from 6.6.6.6
                      AS path: I
                      to 192.168.15.1 via xe-0/0/0.0, label-switched-path to-EGRESS-PE2-2

Caveats:
There is a limitation if you have multiple LSPs to the same destinations. By Default the number of LSP next-hops are 16. You can expand it to 32-64 with this command.

user@router# set chassis maximum-ecmp ?
Possible completions:
  16                   Maximum 16 ECMP routes
  32                   Maximum 32 ECMP routes
  64                   Maximum 64 ECMP routes

So you can theoretically only map a maximum of 64 VRFs to 64 unique LSPs.




Sunday, October 13, 2013

Juniper Op script to convert Hex to Decimal


Created an op script that would take a string of hex pairs and convert them into decimal. Actually I took some xslt script I found on the internet and made the conversion to slax.

user@router> op hex 
07 d9 08 1c 04 32 13 00 2d 07 00
7
217
8
28
4
50
19
0
45
7
0

Could be useful in other scripts if you need to make a conversion.

Code:
---------------

version 1.0;

ns junos = http://xml.juniper.net/junos/*/junos;
ns xnm = http://xml.juniper.net/xnm/1.1/xnm;
ns jcs = http://xml.juniper.net/junos/commit-scripts/1.0;

import ../import/junos.xsl;

match / {
    <op-script-results> {
     var $string = 07 d9 08 1c 04 32 13 00 2d 07 00;
     var $hexval = translate($string,' ','');
     <output> $string;
     var $len = string-length($hexval);
     var $loopCounter := { call create-loop-counter( $counter = 11); }
     for-each( $loopCounter/counter ) {
       call hexpairs-to-dec($pair = position(), $hexval);
     }

    }
   
}
template create-loop-counter( $counter ) {
if( $counter > 0 ) {
<counter>;
call create-loop-counter( $counter = $counter -1 );
}
}

template hexpairs-to-dec ($pair = 1, $hexval) {
    var $hexpair = substring($hexval, $pair * 2 - 1, 2);
   
    if ($hexpair) {
        var $hex = 0123456789abcdef;

        <output> (string-length(substring-before($hex, substring($hexpair, 1, 1)))) * 16 + string-length(substring-before($hex, subs
tring($hexpair, 2, 1)));
    }
}

Wednesday, October 9, 2013

Multi-homed VPL configuration

I consulted on the configuration for multi-homed VPLS for a Data Center Interconnetion. Here's a working version.
------------------


Primary PE Router

interfaces {
    xe-0/0/0 {
        description "to EX4500";
        flexible-vlan-tagging;
        mtu 9100;
        encapsulation flexible-ethernet-services;
        unit 900 {
            encapsulation vlan-vpls;
            vlan-id-list [ 1-900 ];
        }
    }
}


routing-instances {
    VPLS-BGP-900 {
        instance-type vpls;
        interface xe-0/0/0.900;
        route-distinguisher 192.168.0.1:900;
        vrf-target target:100:900;
        protocols {
            vpls {
                site-range 1024;
                no-tunnel-services;
                site mx960-1-900 {
                    site-identifier 1;
                    multi-homing;
                    site-preference primary;
                    interface xe-0/0/0.900;
                }
            }
        }
    }



Backup PE Router

interfaces {
    xe-0/0/0 {
        description "to EX4500";
        flexible-vlan-tagging;
        mtu 9100;
        encapsulation flexible-ethernet-services;
        unit 900 {
            encapsulation vlan-vpls;
            vlan-id-list [ 1-900 ];
        }
    }
}

    VPLS-BGP-900 {
        instance-type vpls;
        interface xe-0/0/0.900;
        route-distinguisher 192.168.0.2:900;
        vrf-target target:100:900;
        protocols {
            vpls {
                site-range 1024;
                no-tunnel-services;
                site mx960-2-900 {
                    site-identifier 1;
                    multi-homing;
                    site-preference backup;
                    interface xe-0/0/0.900;
                }
            }
        }
    }

Tuesday, October 8, 2013

parsing xml data with perl

So a coworker wanted to parse an xml file. This xml file was retrieved using netconf and was equivalent to issuing a show bgp summary on a juniper router.


> show bgp summary                
Groups: 1 Peers: 2 Down peers: 0
Table          Tot Paths  Act Paths Suppressed    History Damp State    Pending
inet.0              
                      14          8          0          0          0          0
bgp.l3vpn.0        
                       0          0          0          0          0          0
bgp.l2vpn.0        
                       0          0          0          0          0          0
Peer                     AS      InPkt     OutPkt    OutQ   Flaps Last Up/Dwn State|#Active/Received/Accepted/Damped...
1.1.1.3               65000       4067        684       0       3     3:21:14 Establ
  inet.0: 4/7/7/0
  bgp.l3vpn.0: 0/0/0/0
  bgp.l2vpn.0: 0/0/0/0
1.1.1.4               65000       3653        865       0       2     4:10:55 Establ
  inet.0: 4/7/7/0
  bgp.l3vpn.0: 0/0/0/0
  bgp.l2vpn.0: 0/0/0/0


The xml file (bgp_summary.xml) looks like this:


0> show bgp summary | display xml
<rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.3R1/junos">
    <bgp-information xmlns="http://xml.juniper.net/junos/12.3R1/junos-routing">
        <group-count>1</group-count>
        <peer-count>2</peer-count>
        <down-peer-count>0</down-peer-count>
        <bgp-rib junos:style="brief">
            <name>inet.0</name>
            <total-prefix-count>14</total-prefix-count>
            <received-prefix-count>14</received-prefix-count>
            <accepted-prefix-count>14</accepted-prefix-count>
            <active-prefix-count>8</active-prefix-count>
            <suppressed-prefix-count>0</suppressed-prefix-count>
.......
truncated.

so using the library XML::XPATH you can parse this file and retrieve the information.

-----------------
output:


% perl bgp.pl bgp_summary.xml

========> Peer = 1.1.1.3

rib-name = inet.0
active = 4
received = 7
accepted = 7
suppressed = 0

rib-name = bgp.l3vpn.0
active = 0
received = 0
accepted = 0
suppressed = 0

rib-name = bgp.l2vpn.0
active = 0
received = 0
accepted = 0
suppressed = 0


========> Peer = 1.1.1.4

rib-name = inet.0
active = 4
received = 7
accepted = 7
suppressed = 0

rib-name = bgp.l3vpn.0
active = 0
received = 0
accepted = 0
suppressed = 0

rib-name = bgp.l2vpn.0
active = 0
received = 0
accepted = 0
suppressed = 0


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

I didn't write the script. In fact I was in the middle of making my own version when another coworker beat me to it. My wasn't a nice:

% perl bgp_old.pl bgp_summary.xml
peer-address = 1.1.1.3 
------------------
name inet.0
total-prefix-count 14
total-prefix-count 14
received-prefix-count 14
accepted-prefix-count 8
accepted-prefix-count 0
------------------
name bgp.l3vpn.0
total-prefix-count 0
total-prefix-count 0
received-prefix-count 0
accepted-prefix-count 0
accepted-prefix-count 0
------------------
name bgp.l2vpn.0
total-prefix-count 0
total-prefix-count 0
received-prefix-count 0
accepted-prefix-count 0
accepted-prefix-count 0

His was way better and simple.

-------------
source code:

#!/usr/bin/perl

#use strict;
#use warnings;

use XML::XPath;

my $xmlfile = $ARGV[0];

my $lxp1 = XML::XPath->new(filename => $xmlfile);

foreach my $bgpPeer ($lxp1->find('//bgp-information/bgp-peer[peer-state="Established"]')->get_nodelist) {
        printf ("\n========> Peer = %s\n\n", $bgpPeer->find('peer-address')->string_value);
        foreach my $ribs ($bgpPeer->find('bgp-rib')->get_nodelist()) {
                printf ("\t\trib-name = %s\n", $ribs->find('name')->string_value);
                printf ("\t\tactive = %d\n", $ribs->find('active-prefix-count'));
                printf ("\t\treceived = %d\n", $ribs->find('received-prefix-count'));
                printf ("\t\taccepted = %d\n", $ribs->find('accepted-prefix-count'));
                printf ("\t\tsuppressed = %d\n\n", $ribs->find('suppressed-prefix-count'));
        }
}





Sunday, October 6, 2013

Junos OP script ping a range of IP addresses


I wanted to ping some devices in my lab to see which ones were reachable, but there wasn't a range command in Junos. So I decided to build one myself. I took a similar ping-sweep script and modified it for my purposes.

{master:0}
user@router# set system scripts op file ping.slax

{master:0}
user@router> op ping ?
Possible completions:
  <[Enter]>            Execute this command
  <name>               Argument name
  detail               Display detailed output
  first                starting ip of last octet - default 1
  last                 last ip of last octet - default 20
  remote-host          first 3 octests of an ip-address to ping eg 10.1.1.
  step                 step size - default 1
  |                    Pipe through a command
{master:0}
user@router> op ping remote-host 192.168.32. first 20 last 30        
Pinging 192.168.32.20
Ping Success!!!
Pinging 192.168.32.21
Ping Failed!!!
Pinging 192.168.32.22
Ping Success!!!
Pinging 192.168.32.23
Ping Success!!!
Pinging 192.168.32.24
Ping Success!!!
Pinging 192.168.32.25
Ping Success!!!
Pinging 192.168.32.26
Ping Success!!!
Pinging 192.168.32.27
Ping Failed!!!
Pinging 192.168.32.28
Ping Failed!!!
Pinging 192.168.32.29
Ping Failed!!!
Pinging 192.168.32.30
Ping Failed!!!

{master:0}
user@router> show arp no-resolve
MAC Address       Address         Interface     Flags
00:a0:a5:7b:ba:1a 192.168.32.20    ge-0/0/0.0                none
40:b4:f0:7a:bc:3d 192.168.32.22    ge-0/0/0.0                none
40:b4:f0:79:50:fd 192.168.32.23    ge-0/0/0.0                none
40:b4:f0:79:59:3d 192.168.32.24    ge-0/0/0.0                none
40:b4:f0:79:46:bd 192.168.32.25    ge-0/0/0.0                none
84:18:88:d1:9d:7d 192.168.32.26    ge-0/0/0.0                none
Total entries: 6

Here's the source code:
------------------

version 1.0;

/*  This OP script will ping a range of ips up to a class C subnet
*/


ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns ext = "http://xmlsoft.org/XSLT/namespace";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";

import "../import/junos.xsl";


var $arguments = {
    <argument> {
        <name> "remote-host";
        <description> "first 3 octests of an ip-address to ping eg 10.1.1.";
    }
    <argument> {
        <name> "first";
        <description> "starting ip of last octet - default 1";
    }
    <argument> {
        <name> "last";
        <description> "last ip of last octet - default 20";
    }
    <argument> {
        <name> "step";
        <description> "step size - default 1";
    }
}


param $remote-host = "192.168.32.";
param $first = '1';
param $last = '20';
param $step = '1';

match / {

    call ping($remote-host, $cur-size = $first, $last, $step);

}

/*
 * Ping the remote-host with different packet size and display the result
 */
template ping ($remote-host, $cur-size, $last, $step) {

        var $ip = $remote-host _ $cur-size;

    if ($cur-size <= $last) {
        var $ping-rpc = {
            <ping> {
                <host> $ip;
                <count> 1;
                <rapid>;
            }
        }

        expr jcs:output("Pinging ", $ip);

        /*
         * Invoking ping RPC and getting the result into $ping-out
         */
        var $ping-out = jcs:invoke($ping-rpc);

        if ($ping-out/ping-success) {
            expr jcs:output("Ping Success!!!");
        } else {
            expr jcs:output("Ping Failed!!!");
        }

        call ping($remote-host, $cur-size = $cur-size + $step, $last,
                  $step);
    }
}


Saturday, October 5, 2013

Junos commit script

Someone asked if there was a Juniper commit script that could check if a user configures an interface that uses unit 1000. If the interface does not appear in a VRF named VRF1000 it then will then make sure it is configured in there. I didn't write most of the script, but I did fix the original that had some errors. Here's the result.

Interface ge-0/0/0 was already configured and placed in the VRF, but not ge-0/0/10

user@router# show interfaces 
ge-0/0/0 {
    vlan-tagging;
    unit 1000 {
        vlan-id 1000;
        family inet {
            address 100.1.1.1/24;
        }
    }
}
ge-0/0/10 {
    vlan-tagging;
    unit 1000 {
        vlan-id 1000;
        family inet {
            address 200.1.1.1/24;
        }
    }
}
lo0 {
    unit 0 {
        family inet {
            address 1.1.1.1/32;
        }
    }
}


{master:0}[edit]
user@router# show routing-instances VRF1000 
instance-type vrf;
interface ge-0/0/0.1000;
route-distinguisher 100:100;
vrf-target target:1001:100;
vrf-table-label;

Now if a user commits it, the script will automatically correct config by adding the missing interface

{master:0}[edit]
user@router# commit 
warning: warning message - found int in vrf VRF1000 ge-0/0/0.1000
warning: warning message - adding to vrf VRF1000 missing int ge-0/0/10.1000
configuration check succeeds
commit complete


{master:0}[edit]
user@router# show routing-instances VRF1000 
instance-type vrf;
interface ge-0/0/0.1000;
interface ge-0/0/10.1000;
route-distinguisher 100:100;
vrf-target target:1001:100;
vrf-table-label;

{master:0}[edit]
user@router## show system
scripts {
    commit {
        file vrf.slax;
    }
}


Here's the code:

------------------------
{master:0}[edit]
user@router> file show /var/db/scripts/commit/vrf.slax

version 1.0;

ns junos = "http://xml.juniper.net/junos/*/junos";
ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
import "../import/junos.xsl";

match configuration {
   var $top = .;
   var $interfaces = interfaces/interface;
   var $vrf = "VRF1000";

   for-each ($interfaces/unit[name == 1000]) {
       var $ifname = ../name _ "." _ name;

       if ($top/routing-instances/instance[name == $vrf]/interface[name == $ifname]) {
          <xnm:warning> {
            <message> "warning message - found int in vrf VRF1000 " _ $ifname;
          }
       }
       else {
           <xnm:warning> {
             <message> "warning message - adding to vrf VRF1000 missing int " _ $ifname;
           }
           var $dot = $top/routing-instances/instance[name == $vrf];
           var $content = <interface> {
               <name> $ifname;
           }
      call jcs:emit-change($dot, $content);
       }
   }
}