Sunday, June 10, 2018

Checking Advertised BGP Routes To Peers - With PYEZ’S TABLE/VIEW


BGP doesn’t need any introduction because whenever we talk out highly scalable networks or Internet, we talk about BGP only. This is the best protocol to transport any number of routes. Whenever service provider or any customer runs BGP with its internal or external neighbors, they want to see what the BGP advertised routes to the neighbors are.

Every service provider or end customer wants to know what are the advertised routes towards the upstream peering so that during time of outages routes manipulation can be taken care. In this post, I have written a script by using the BGP Table View which can be used to dynamically create a view what is being advertised to peers by using different attributes mentioned in XML table.

Previous post “Display Static Routes With PyEZ Table and View” helps to understand how PYeZ framework can be used to display the static routes. I am using the same framework with different RPCs to show how dynamically we can display per peer neighbor advertised routes.

To achieve this, we need to know how many BGP neighbors we have and how many prefixes are advertised to each BGP neighbor.
Below is the python code which has been written to get the desired output of advertised route per neighbor.
       

from jnpr.junos import Device
from jnpr.junos.factory.factory_loader import FactoryLoader
import yaml
from jnpr.junos.op.xcvr import XcvrTable

yml = """
---
bgpAdvertiseRoutes:
 rpc: get-route-information
 args:
  advertising-protocol-name: bgp
  extensive: True
 item: route-table/rt 
 key:  rt-destination
 view: bgpAdvertiseView

bgpAdvertiseView:
 fields:
  rt_destination: rt-destination
  rt_prefix_length: rt-prefix-length
  rt_protocol_name: rt-entry/protocol-name
  bgp_group_name: rt-entry/bgp-group-name
  bgp_nh: rt-entry/nh/to
  rt_med: rt-entry/med
  rt_local_preference: rt-entry/local-preference
  rt_as_path: rt-entry/as-path
  rt_communities: rt-entry/communities/community
  
bgpSummary:
 rpc: get-bgp-summary-information
 
 
  """
globals().update(FactoryLoader().load(yaml.load(yml)))

with Device('your device ip address', port='7020', user='useryourname',passwd='yourpassword') as dev:
 op = dev.rpc.get_bgp_summary_information()
 for i in op.xpath('bgp-peer/peer-address'):
  #print(i.text)
  load_bgp = bgpAdvertiseRoutes(dev).get(neighbor=i.text)
  print("\n-----------------BGP Advertising Routes For:", i.text, "-----------------")
  for item in load_bgp:
   print('----------------------------------------------')
   print("Advertising_Route:",item.rt_destination,"Prefix_Lengh:",item.rt_prefix_length,"MED:",item.rt_med,"LP:",item.rt_local_preference,"AS_Path:",item.rt_as_path, "Communities:",item.rt_communities)



After running the above code, below is the output which can be visible on your python screen. Do ignore the public ip addresses, this is the lab network and only reachable in lab and has nothing to do with internet routes. In my lab, I have two peers and I am advertising the same routes to both the peers with communities.
       
C:\Python34>python c:\Lab\PyEZ\vmx_facts.py

-----------------BGP Advertising Routes For: 22.22.22.22 -----------------
----------------------------------------------
Advertising_Route: 2.2.2.8 Prefix_Lengh: 30 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.12 Prefix_Lengh: 30 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.16 Prefix_Lengh: 30 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.20 Prefix_Lengh: 30 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 22.22.22.22 Prefix_Lengh: 32 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 33.33.33.33 Prefix_Lengh: 32 MED: 1 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 44.44.44.44 Prefix_Lengh: 32 MED: 1 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 55.55.55.55 Prefix_Lengh: 32 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 66.66.66.66 Prefix_Lengh: 32 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']

-----------------BGP Advertising Routes For: 33.33.33.33 -----------------
----------------------------------------------
Advertising_Route: 2.2.2.8 Prefix_Lengh: 30 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.12 Prefix_Lengh: 30 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.16 Prefix_Lengh: 30 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 2.2.2.20 Prefix_Lengh: 30 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 22.22.22.22 Prefix_Lengh: 32 MED: 3 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 33.33.33.33 Prefix_Lengh: 32 MED: 1 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 44.44.44.44 Prefix_Lengh: 32 MED: 1 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 55.55.55.55 Prefix_Lengh: 32 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']
----------------------------------------------
Advertising_Route: 66.66.66.66 Prefix_Lengh: 32 MED: 2 LP: 100 AS_Path: AS path: [100] I Communities: ['65001:11', '65001:33', '65001:172']

References: STEPHAN BEHRENS has written great post on "CHECKING BGP WITH PYEZ’S TABLE/VIEW".
Click Here To Read Rest Of The Post...

Monday, May 28, 2018

Junos Automation: Display Static Routes With PyEZ Table and View


All about Juniper JET Automation Framework consists lot of APIs which helps network engineer to automate their day to day operation. The framework leverages Junos PyEZ framework which is nothing but library developed for Juniper routers. In my earlier post, I have already explained how the PyEZ can be installed in your laptop and use the library to connect your first router.

In this post, I will be covering more about Junos PyEZ tables and views. Tables and Views enable you to extract operational information and configuration data from devices running Junos OS as well as configure devices running Junos OS. When you add the Table to the Junos PyEZ framework, Junos PyEZ dynamically creates a configuration class for the resource, which you can use to programmatically configure the resource on a device. Tables and Views are defined using YAML, so no complex coding is required to create your own custom Tables and Views. Tables and Views provide a simple and efficient way to extract information from complex operational command output or configuration data and map it to a Python data structure. Operational (op) Tables select items from the RPC reply of an operational command, and configuration Tables select data from specific hierarchies in the selected configuration database. Each Table item represents a record of data and has a unique key. A Table also references a Table View, which is used to map the tag names in the data to the variable property names used within the Python module.

The below OP table retrieves output of get-route-information which corresponds to the show route protocol static extensive | display xml. The table extracts the information from the output and corresponding staticView selects two fields from each get-route-information output. The OP table has item and key, item is the xpath top level hierarchy and key is the unique value under the xpath hierarchy.
       

staticRoutes:
 rpc: get-route-information
 args:
  protocol: static
  extensive: True
 item: route-table/rt
 key:  rt-destination
 view: staticView

staticView:
 fields:
  rt_destination: rt-destination
  protocol_name: rt-entry/protocol-name



Now the same code has to be saved in YAML file or we can directly call the same code in python. Below is the code what need to be run on your machine. I am using Junos PyEZ docker on my laptop to test all the functionality.
       
PS C:\lab> docker images
REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
juniper/pyez               latest              122dff90c4db        6 days ago          279MB
PS C:\lab>

       
PS C:\lab> docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
628e5c01da14        juniper/pyez        "sh"                37 hours ago        Up 37 hours                             pyez
PS C:\lab>


Below is the code with YAML model called under the same python file.
       

/scripts # cat srx_facts.py
from jnpr.junos import Device
import sys
import pprint
from jnpr.junos.factory.factory_loader import FactoryLoader
import yaml
dev = Device('add your ip address of the router',user='user',passwd='passwd')
dev.open()
hhost_name = dev.facts['hostname']

#Defining YAML Model
yml = """
---
staticRoutes:
 rpc: get-route-information
 args:
  protocol: static
  extensive: True
 item: route-table/rt
 key:  rt-destination
 view: staticView

staticView:
 fields:
  rt_destination: rt-destination
  protocol_name: rt-entry/protocol-name
"""

####YAML Ends Here #####


#### Load Table and View definitions via YAML into namespace  ####
globals().update(FactoryLoader().load(yaml.load(yml)))
st = staticRoutes(dev).get()

# Load for interfaces
interface_var = interfaceStatus(dev).get()
#print(interface_var)

#print(st)
# Print all the information received from device
print("-----------------Static Routes------------------")
print("---------------------------------------------")
for item in st:
        print('*')
        print(hhost_name, "is having", item.rt_destination,"as", item.protocol_name, "route.")
        print("*")
        print("---------------------------------------------")
dev.close()/scripts #


Below is the output after running the above code. The below output is the lab output and all the public IP are used only for LAB purpose and are not connected, advertise and reachable in the public cloud.

       
Model Number is: SRX1400
Hostname is: vSRX120
-----------------Static Routes------------------
---------------------------------------------
*
vSRX120 is having 0.0.0.0 as Static route.
*
---------------------------------------------
*
vSRX120 is having 192.1.1.1 as Static route.
*
---------------------------------------------
*
vSRX120 is having 193.2.2.2 as Static route.
*
---------------------------------------------
*
vSRX120 is having 172.11.11.11 as Static route.
*
---------------------------------------------
*
vSRX120 is having 173.22.22.22 as Static route.
*
---------------------------------------------
*


The view property associates the Table definition with a particular View. A View maps your user-defined field names to elements in the selected Table items using XPath expressions. You can customize the View to only select the necessary elements from the Table items.
References: Juniper Documentation

Click Here To Read Rest Of The Post...

Tuesday, May 15, 2018

Understanding Layered Architecture of Docker Container Images


Building Docker Image From Scratch” is easy way to build any kind of containerization image. Let’s get bit more deep into it and understand what it is doing at the low level. Everyone knows in Linux everything is considered as file only. The whole operating system is nothing but a collection of files and folders.

In the previous post, we have seen there are 2 steps required as per “Dockerfile” and same has been embedded in the container layer file system. As a result we have got a container image which is nothing but a collection of layered filesystem.

Container images are templates from which containers are created. These images are not just one monolithic block, but are composed of many layers. The first layer in the image is also called the base layer:



Each layer is mapping with one command and this command is nothing but a file which will be stacked in this image. The all layers of container images are immutable or read only which means once created can’t be changed but we can delete it. In case we want to use the content of one layer in another layer, in that case we have to copy it from layer and use it in new layer. Each layer only contains the delta of changes in regard to the previous set of layers. The content of each layer is mapped to a special folder on the host system, which is usually a subfolder of "/var/lib/docker/."

When the docker engine creates a container from these images, it adds writable layer on the top of immutable or read only layers like as shown in below image:



By doing this, same immutable image can be used across various applications just by adding single writable docker layer.

As I have already mentioned, the image layers are immutable and to reuse the existing files and folders docker uses the copy-on-write strategy. With this strategy, If a layer uses a file or folder that is available in one of the low-lying layers, then it just uses it. If, on the other hand, a layer wants to modify, say, a file from a low-lying layer, then it first copies this file up to the target layer and then modifies it. Below is the snapshot of copy-on-write strategy:



As per above image, second layer want to modify file 1 which is present in base layer. Second layer will copy file 1 from base layer and then modified it. So top layer will use file 1 will be copied from layer 1 and file 2 will be copied from base layer.

Click Here To Read Rest Of The Post...