aboutsummaryrefslogtreecommitdiffstats
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/libraries/python/honeycomb/BGP.py107
-rw-r--r--resources/libraries/python/honeycomb/HoneycombSetup.py32
-rw-r--r--resources/libraries/robot/honeycomb/bgp.robot86
-rw-r--r--resources/test_data/honeycomb/bgp.py175
-rwxr-xr-xresources/traffic_scripts/honeycomb/bgp_open.py85
5 files changed, 466 insertions, 19 deletions
diff --git a/resources/libraries/python/honeycomb/BGP.py b/resources/libraries/python/honeycomb/BGP.py
index ca50cc3120..75dce762ff 100644
--- a/resources/libraries/python/honeycomb/BGP.py
+++ b/resources/libraries/python/honeycomb/BGP.py
@@ -13,6 +13,7 @@
"""Keywords to manipulate BGP configuration using Honeycomb REST API."""
+from resources.libraries.python.constants import Constants as Const
from resources.libraries.python.HTTPRequest import HTTPCodes
from resources.libraries.python.honeycomb.HoneycombSetup import HoneycombError
from resources.libraries.python.honeycomb.HoneycombUtil \
@@ -27,6 +28,7 @@ class BGPKeywords(object):
"""
def __init__(self):
+ """Initializer."""
pass
@staticmethod
@@ -41,7 +43,7 @@ class BGPKeywords(object):
:type data: dict
:returns: Content of response.
:rtype: bytearray
- :raises HoneycombError: If the status code in response on PUT is not
+ :raises HoneycombError: If the status code in response to PUT is not
200 = OK or 201 = ACCEPTED.
"""
@@ -69,7 +71,7 @@ class BGPKeywords(object):
:type data: dict
:returns: Content of response.
:rtype: bytearray
- :raises HoneycombError: If the status code in response on PUT is not
+ :raises HoneycombError: If the status code in response to PUT is not
200 = OK or 201 = ACCEPTED.
"""
@@ -93,6 +95,7 @@ class BGPKeywords(object):
:type node: dict
:returns: BGP configuration data.
:rtype: dict
+ :raises HoneycombError: If the status code in response is not 200 = OK.
"""
status_code, resp = HcUtil. \
@@ -104,21 +107,29 @@ class BGPKeywords(object):
return resp
@staticmethod
- def get_bgp_peer(node, address):
+ def get_bgp_peer(node, address, datastore='config'):
"""Get BGP configuration of the specified peer from the node.
:param node: Honeycomb node.
:param address: IP address of the peer.
+ :param datastore: Get data from config or operational datastore.
:type node: dict
:type address: str
+ :type datastore; str
:returns: BGP peer configuration data.
:rtype: dict
+ :raises HoneycombError: If the status code in response is not 200 = OK.
"""
path = "bgp-openconfig-extensions:neighbors/" \
"neighbor/{0}".format(address)
+ if datastore != "operational":
+ url = "config_bgp_peer"
+ else:
+ url = "oper_bgp"
+ path = "peer/bgp:%2F%2F{0}".format(address)
status_code, resp = HcUtil. \
- get_honeycomb_data(node, "config_bgp_peer", path)
+ get_honeycomb_data(node, url, path)
if status_code != HTTPCodes.OK:
raise HoneycombError(
"Not possible to get configuration information about the BGP"
@@ -211,7 +222,7 @@ class BGPKeywords(object):
:type ip_version: str
:returns: Content of response.
:rtype: bytearray
- :raises HoneycombError: If the operation fails.
+ :raises HoneycombError: If the status code in response is not 200 = OK.
"""
route_address = route_address.replace("/", "%2F")
@@ -239,7 +250,7 @@ class BGPKeywords(object):
def get_all_peer_routes(node, peer_address, ip_version):
"""Get all configured routes for the given BGP peer.
- :param node: HOneycomb node.
+ :param node: Honeycomb node.
:param peer_address: IP address of the peer.
:param ip_version: IP protocol version. ipv4 or ipv6
:type node: dict
@@ -247,7 +258,7 @@ class BGPKeywords(object):
:type ip_version: str
:returns: Content of response.
:rtype: bytearray
- :raises HoneycombError: If the operation fails.
+ :raises HoneycombError: If the status code in response is not 200 = OK.
"""
if ip_version.lower() == "ipv4":
@@ -299,3 +310,85 @@ class BGPKeywords(object):
.format(peer_address, route_address, index)
return BGPKeywords._configure_bgp_route(node, path)
+
+ @staticmethod
+ def get_bgp_local_rib(node):
+ """Get local RIB table from the Honeycomb node.
+
+ :param node: Honeycomb node.
+ :type node: dict
+ :returns: RIB operational data.
+ :rtype: dict
+ :raises HoneycombError: If the status code in response is not 200 = OK.
+ """
+
+ path = "loc-rib"
+
+ status_code, resp = HcUtil. \
+ get_honeycomb_data(node, "oper_bgp", path)
+
+ if status_code != HTTPCodes.OK:
+ raise HoneycombError(
+ "Not possible to get operational data from BGP local RIB."
+ " Status code: {0}.".format(status_code))
+
+ return resp
+
+ @staticmethod
+ def configure_bgp_base(node, ip_address, port, as_number):
+ """Modify BGP config file. Requires a restart of Honeycomb to take
+ effect.
+
+ :param node: Honeycomb node.
+ :param ip_address: BGP peer identifier/binding address.
+ :param port: BGP binding port.
+ :param as_number: Autonomous System ID number.
+ :type node: dict
+ :type ip_address: str
+ :type port: int
+ :type as_number: int
+ :raises HoneycombError: If modifying the configuration fails.
+ """
+
+ from resources.libraries.python.ssh import SSH
+
+ config = {
+ '\\"bgp-binding-address\\"': '\\"{0}\\"'.format(ip_address),
+ '\\"bgp-port\\"': port,
+ '\\"bgp-as-number\\"': as_number}
+
+ path = "{0}/config/bgp.json".format(Const.REMOTE_HC_DIR)
+
+ for key, value in config.items():
+ find = key
+ replace = '"{0}": "{1}",'.format(key, value)
+
+ argument = '"/{0}/c\\ {1}"'.format(find, replace)
+ command = "sed -i {0} {1}".format(argument, path)
+
+ ssh = SSH()
+ ssh.connect(node)
+ (ret_code, _, stderr) = ssh.exec_command_sudo(command)
+ if ret_code != 0:
+ raise HoneycombError("Failed to modify configuration on "
+ "node {0}, {1}".format(node, stderr))
+
+ @staticmethod
+ def compare_rib_tables(data, ref):
+ """Compare provided RIB table with reference. All reference entries must
+ be present in data. Data entries not present in reference are ignored.
+
+ :param data: Data from Honeycomb node.
+ :param ref: Reference data to compare against.
+ :type data: dict
+ :type ref: dict
+ :raises HoneycombError: If the tables do not match."""
+
+ # Remove runtime attributes from data
+ for item in data:
+ item.pop("attributes", "")
+
+ for item in ref:
+ if item not in data:
+ raise HoneycombError(
+ "RIB entry {0} not found in operational data.")
diff --git a/resources/libraries/python/honeycomb/HoneycombSetup.py b/resources/libraries/python/honeycomb/HoneycombSetup.py
index 7c3831ca04..d4175b13e4 100644
--- a/resources/libraries/python/honeycomb/HoneycombSetup.py
+++ b/resources/libraries/python/honeycomb/HoneycombSetup.py
@@ -61,12 +61,13 @@ class HoneycombSetup(object):
HoneycombSetup.print_environment(nodes)
- logger.console("\n(re)Starting Honeycomb service ...")
-
cmd = "sudo service honeycomb start"
for node in nodes:
if node['type'] == NodeType.DUT:
+ logger.console(
+ "\n(re)Starting Honeycomb service on node {0}".format(
+ node["host"]))
ssh = SSH()
ssh.connect(node)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
@@ -89,13 +90,15 @@ class HoneycombSetup(object):
:type nodes: list
:raises HoneycombError: If Honeycomb failed to stop.
"""
- logger.console("\nShutting down Honeycomb service ...")
cmd = "sudo service honeycomb stop"
errors = []
for node in nodes:
if node['type'] == NodeType.DUT:
+ logger.console(
+ "\nShutting down Honeycomb service on node {0}".format(
+ node["host"]))
ssh = SSH()
ssh.connect(node)
(ret_code, _, _) = ssh.exec_command_sudo(cmd)
@@ -121,7 +124,8 @@ class HoneycombSetup(object):
:raises HoneycombError: If Honeycomb fails to start.
"""
- logger.console("\n(re)Starting Honeycomb service ...")
+ logger.console(
+ "\n(re)Starting Honeycomb service on node {0}".format(node["host"]))
cmd = "sudo service honeycomb restart"
@@ -650,6 +654,26 @@ class HoneycombSetup(object):
logger.info("ODL client service stopped.")
+ @staticmethod
+ def set_static_arp(node, ip_address, mac_address):
+ """Configure a static ARP entry using arp.
+
+ :param node: Node in topology.
+ :param ip_address: IP address for the entry.
+ :param mac_address: MAC adddress for the entry.
+ :type node: dict
+ :type ip_address: str
+ :type mac_address: str
+ :raises RuntimeError: If the operation fails.
+ """
+
+ ssh = SSH()
+ ssh.connect(node)
+ ret_code, _, _ = ssh.exec_command_sudo("arp -s {0} {1}".format(
+ ip_address, mac_address))
+
+ if ret_code != 0:
+ raise RuntimeError("Failed to configure static ARP adddress.")
class HoneycombStartupConfig(object):
diff --git a/resources/libraries/robot/honeycomb/bgp.robot b/resources/libraries/robot/honeycomb/bgp.robot
index d4c2d6b0a2..aa96cc6538 100644
--- a/resources/libraries/robot/honeycomb/bgp.robot
+++ b/resources/libraries/robot/honeycomb/bgp.robot
@@ -16,6 +16,24 @@
| Library | resources.libraries.python.honeycomb.HcAPIKwInterfaces.InterfaceKeywords
*** Keywords ***
+| Configure BGP module
+| | [Documentation] | Edit Honeycomb's configuration file for the BGP feature.\
+| | ... | Honeycomb needs to be restarted for the changes to take effect.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - information about a DUT node. Type: dictionary
+| | ... | - ip_address - IP address to bind BGP listener to. Type: string
+| | ... | - port - Port number to bind BGP listener to. Type: integer
+| | ... | - as_number - Autonomous System (AS) ID number. Type: integer
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| Configure BGP module \| ${nodes['DUT1']} \| 192.168.0.1 \| ${179} \
+| | ... | \| ${65000} \|
+| | ...
+| | [Arguments] | ${node} | ${ip_address} | ${port} | ${as_number}
+| | Configure BGP base | ${node} | ${ip_address} | ${port} | ${as_number}
+
| No BGP peers should be configured
| | [Documentation] | Uses Honeycomb API to read BGP configuration and checks
| | ... | if there ary BGP peers conffigured.
@@ -50,7 +68,7 @@
| | Add BGP Peer | ${node} | ${address} | ${data}
| BGP Peer From Honeycomb Should be
-| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data.
+| | [Documentation] | Uses Honeycomb API to verify BGP peer config data.
| | ...
| | ... | *Arguments:*
| | ... | - node - Information about a DUT node. Type: dictionary
@@ -67,6 +85,24 @@
| | ${oper_data}= | Get BGP Peer | ${node} | ${address}
| | Compare Data Structures | ${oper_data} | ${data}
+| Peer Operational Data From Honeycomb Should be
+| | [Documentation] | Uses Honeycomb API to verify BGP peer operational data.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - Information about a DUT node. Type: dictionary
+| | ... | - address - IP address of the peer. Type: string
+| | ... | - data - Peer configuration data. Type: dictionary
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| BGP Peer From Honeycomb Should be \
+| | ... | \| ${nodes['DUT1']} \| 192.168.0.1 \| ${data} \|
+| | ...
+| | [Arguments] | ${node} | ${address}
+| | ...
+| | ${oper_data}= | Get BGP Peer | ${node} | ${address} | operational
+| | Should be Equal | ${oper_data['peer'][0]['peer-id']} | bgp://${address}
+
| Honeycomb removes BGP peer
| | [Documentation] | Uses Honeycomb API to add a BGP peer.
| | ...
@@ -171,3 +207,51 @@
| | ${oper_data}= | Get All Peer Routes
| | ... | ${node} | ${peer_address} | ${ip_version}
| | Should be Empty | ${oper_data['bgp-inet:${ip_version}-routes']}
+
+| BGP Loc-RIB table should include
+| | [Documentation] | Uses Honeycomb API to retrieve local BGP RIB table\
+| | ... | And verifies that it contains the specified entry.
+| | ...
+| | ... | *Arguments:*
+| | ... | - node - Information about a DUT node. Type: dictionary
+| | ... | - data - RIB that should be present in operational data.\
+| | ... | Type: dictionary
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| BGP Loc-RIB table should include \| ${nodes['DUT1']} \| ${data} \|
+| | ...
+| | [Arguments] | ${node} | ${data}
+| | ...
+| | ${oper_data}= | Get BGP Local RIB | ${node}
+| | ${oper_data}= | Set Variable | ${oper_data['loc-rib']['tables']}
+| | ${data}= | Set Variable | ${data['loc-rib']['tables']}
+| | Compare RIB Tables | ${oper_data} | ${data}
+
+| Receive BGP OPEN message
+| | [Documentation] | Open a TCP listener on BGP port(179) and listen\
+| | ... | for BGP OPEN message. Verify ID and holdtime fields.
+| | ...
+| | ... | *Arguments:*
+| | ... | - tg_node - Information about the TG node. Type: dictionary
+| | ... | - rx_ip - IP address to listen on. Type: string
+| | ... | - src_ip - IP address of the BGP speaker. Also acts as BGP peer ID.\
+| | ... | Type: string
+| | ... | - holdtime - Expected value of HOLD_TIME field in received message.\
+| | ... | Type: integer
+| | ...
+| | ... | *Example:*
+| | ...
+| | ... | \| Receive BGP OPEN message \| ${node['TG']} \
+| | ... | \| 192.168.0.1 \| 192.168.0.2 \| ${0}
+| | ...
+| | [Arguments] | ${tg_node} | ${rx_ip} | ${src_ip} | ${port} | ${as_number}
+| | ... | ${holdtime}
+| | ...
+| | ${args}= | Catenate | --rx_ip | ${rx_ip}
+| | ... | --src_ip | ${src_ip}
+| | ... | --rx_port | ${port}
+| | ... | --as_number | ${as_number}
+| | ... | --holdtime | ${holdtime}
+| | Run Traffic Script On Node | honeycomb/bgp_open.py
+| | ... | ${tg_node} | ${args}
diff --git a/resources/test_data/honeycomb/bgp.py b/resources/test_data/honeycomb/bgp.py
index f9dc4ab233..84c9431e6b 100644
--- a/resources/test_data/honeycomb/bgp.py
+++ b/resources/test_data/honeycomb/bgp.py
@@ -18,6 +18,7 @@ from copy import deepcopy
# Internal BGP peers for CRUD tests
address_internal = "192.168.0.2"
address_internal2 = "192.168.0.3"
+holdtime_internal = 60
peer_internal = {
"bgp-openconfig-extensions:neighbor": [{
"neighbor-address": address_internal,
@@ -26,13 +27,13 @@ peer_internal = {
},
"timers": {
"config": {
- "connect-retry": 10,
- "hold-time": 60
+ "connect-retry": 3,
+ "hold-time": holdtime_internal
}
},
"transport": {
"config": {
- "remote-port": 17900,
+ "remote-port": 179,
"passive-mode": False
}
},
@@ -55,12 +56,12 @@ peer_internal_update = {
"timers": {
"config": {
"connect-retry": 5,
- "hold-time": 120
+ "hold-time": holdtime_internal*2
}
},
"transport": {
"config": {
- "remote-port": 17901,
+ "remote-port": 180,
"passive-mode": True
}
},
@@ -78,7 +79,7 @@ peer_internal2 = deepcopy(peer_internal)
peer_internal2["bgp-openconfig-extensions:neighbor"][0]["neighbor-address"] = \
address_internal2
-# Application BGP peer for CRUD tests
+# Application BGP peer for CRUD test
address_application = "192.168.0.4"
peer_application = {
"bgp-openconfig-extensions:neighbor": [{
@@ -103,6 +104,7 @@ peer_application = {
}]
}
+# IPv4 route for CRUD test
route_address_ipv4 = "192.168.0.5/32"
route_id_ipv4 = 0
route_data_ipv4 = {
@@ -124,6 +126,7 @@ route_data_ipv4 = {
}]
}
+# IPv4 route for testing Update operation
route_data_ipv4_update = {
"bgp-inet:ipv4-route": [{
"path-id": route_id_ipv4,
@@ -143,6 +146,7 @@ route_data_ipv4_update = {
}]
}
+# IPv4 route for testing multiple routes
route_address_ipv4_2 = "192.168.0.6/32"
route_id_ipv4_2 = 1
route_data_ipv4_2 = {
@@ -164,6 +168,7 @@ route_data_ipv4_2 = {
}]
}
+# IPv6 route for CRUD test
route_address_ipv6 = "3ffe:62::1/64"
route_id_ipv6 = 0
route_data_ipv6 = {
@@ -185,8 +190,164 @@ route_data_ipv6 = {
}]
}
+# IPv4 route operational data in routing table
table1_oper = {
"destination-prefix": route_address_ipv4,
"next-hop": "192.168.1.1",
"vpp-ipv4-route-state": {}
-} \ No newline at end of file
+}
+
+# Peer configurations for traffic test
+dut1_peer = {
+ "bgp-openconfig-extensions:neighbor": [{
+ "neighbor-address": "192.168.1.1",
+ "config": {
+ "peer-type": "INTERNAL"
+ },
+ "timers": {
+ "config": {
+ "connect-retry": 3,
+ "hold-time": 60
+ }
+ },
+ "transport": {
+ "config": {
+ "remote-port": 179,
+ "passive-mode": False
+ }
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": True,
+ "send-max": 0},
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV6-UNICAST",
+ "receive": True,
+ "send-max": 0},
+ {
+ "afi-safi-name": "LINKSTATE"
+ }
+ ]
+ }
+ }]
+}
+
+dut2_peer = {
+ "bgp-openconfig-extensions:neighbor": [{
+ "neighbor-address": "192.168.1.2",
+ "config": {
+ "peer-type": "INTERNAL"
+ },
+ "timers": {
+ "config": {
+ "connect-retry": 3,
+ "hold-time": 60
+ }
+ },
+ "transport": {
+ "config": {
+ "remote-port": 179,
+ "passive-mode": True
+ }
+ },
+ "afi-safis": {
+ "afi-safi": [
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV4-UNICAST",
+ "receive": True,
+ "send-max": 0},
+ {
+ "afi-safi-name": "openconfig-bgp-types:IPV6-UNICAST",
+ "receive": True,
+ "send-max": 0},
+ {
+ "afi-safi-name": "LINKSTATE"
+ }
+ ]
+ }
+ }]
+}
+
+# IPv4 route for traffic test
+dut1_route_address = "192.168.0.5/32"
+dut1_route_id = 1
+dut1_route = {
+ "bgp-inet:ipv4-route": [{
+ "path-id": dut1_route_id,
+ "prefix": dut1_route_address,
+ "attributes": {
+ "as-path": {},
+ "origin": {
+ "value": "igp"
+ },
+ "local-pref": {
+ "pref": 100
+ },
+ "ipv4-next-hop": {
+ "global": "192.168.1.3"
+ }
+ }
+ }]
+}
+
+# IPv4 route in peer operational data
+rib_operational = {
+ "loc-rib": {"tables": [
+ {
+ "afi": "bgp-types:ipv4-address-family",
+ "safi": "bgp-types:unicast-subsequent-address-family",
+ "bgp-inet:ipv4-routes": {
+ "ipv4-route": dut1_route["bgp-inet:ipv4-route"]
+ }
+ }
+ ]}
+}
+
+route_operational = {
+ "vpp-ipv4-route-state": {},
+ "next-hop": "192.168.1.3",
+ "destination-prefix": dut1_route_address
+}
+
+# IPv6 route for traffic test
+dut1_route_ip6_address = "3ffe:62::1/64"
+dut1_route_ip6_id = 1
+dut1_route_ip6 = {
+ "bgp-inet:ipv6-route": [{
+ "path-id": dut1_route_ip6_id,
+ "prefix": dut1_route_ip6_address,
+ "attributes": {
+ "as-path": {},
+ "origin": {
+ "value": "igp"
+ },
+ "local-pref": {
+ "pref": 100
+ },
+ "ipv6-next-hop": {
+ "global": "3ffe:63::1"
+ }
+ }
+ }]
+}
+
+# IPv6 route in peer operational data
+rib_ip6_operational = {
+ "loc-rib": {"tables": [
+ {
+ "afi": "bgp-types:ipv6-address-family",
+ "safi": "bgp-types:unicast-subsequent-address-family",
+ "bgp-inet:ipv6-routes": {
+ "ipv6-route": dut1_route_ip6["bgp-inet:ipv6-route"]
+ }
+ }
+ ]}
+}
+
+route_ip6_operational = {
+ "vpp-ipv6-route-state": {},
+ "next-hop": "3ffe:63::1",
+ "destination-prefix": dut1_route_ip6_address
+}
diff --git a/resources/traffic_scripts/honeycomb/bgp_open.py b/resources/traffic_scripts/honeycomb/bgp_open.py
new file mode 100755
index 0000000000..e7bb7d841a
--- /dev/null
+++ b/resources/traffic_scripts/honeycomb/bgp_open.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+# Copyright (c) 2016 Cisco and/or its affiliates.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Traffic script that listens for incoming BGP connections and verifies
+received GBP Open message."""
+
+import sys
+import socket
+
+from scapy.main import load_contrib
+from scapy.layers.inet import Raw
+from scapy.contrib.bgp import BGPHeader, BGPOpen
+
+from resources.libraries.python.TrafficScriptArg import TrafficScriptArg
+
+
+def main():
+ """Open a TCP listener socket on the default BGP port. Accept an incoming
+ connection, receive data and verify if data is a valid BGP Open message."""
+ args = TrafficScriptArg(['rx_ip', 'src_ip', 'rx_port', 'as_number',
+ 'holdtime'])
+
+ rx_ip = args.get_arg('rx_ip')
+ src_ip = args.get_arg('src_ip')
+ rx_port = int(args.get_arg('rx_port'))
+ as_number = int(args.get_arg('as_number'))
+ holdtime = int(args.get_arg('holdtime'))
+
+ load_contrib("bgp")
+
+ soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ soc.bind((rx_ip, rx_port))
+ soc.listen(1)
+
+ print "Listener active, awaiting connection..."
+ soc.settimeout(8)
+ conn, addr = soc.accept()
+ print 'Connection established with peer:', addr
+
+ data = conn.recv(256)
+ conn.close()
+ soc.close()
+
+ bgp_layer = (BGPHeader(Raw(data).load))
+ bgp_layer.show()
+
+ if not bgp_layer.haslayer(BGPOpen):
+ raise RuntimeError("Received data is not a BGP OPEN message.")
+ bgp_open = bgp_layer.getlayer(BGPOpen)
+ if bgp_open.bgp_id != src_ip:
+ raise RuntimeError(
+ "BGP ID mismatch. Received {0} but should be {1}".
+ format(bgp_open.bgp_id, src_ip))
+ else:
+ print "BGP ID matched."
+
+ if bgp_open.AS != as_number:
+ raise RuntimeError(
+ "BGP AS number mismatch. Received {0} but should be {1}".
+ format(bgp_open.AS, as_number))
+ else:
+ print "BGP AS number matched."
+
+ if bgp_open.hold_time != holdtime:
+ raise RuntimeError(
+ "Hold Time parameter mismatch. Received {0} but should be {1}.".
+ format(bgp_layer.getlayer(BGPOpen).holdtime, holdtime))
+ else:
+ print "BGP Hold Time parameter matched."
+
+ sys.exit(0)
+
+if __name__ == "__main__":
+ main()