--- /dev/null
+*** Settings ***
+Documentation Basic tests for iBGP peers.
+...
+... Copyright (c) 2015-2016 Cisco Systems, Inc. and others. All rights reserved.
+...
+... This program and the accompanying materials are made available under the
+... terms of the Eclipse Public License v1.0 which accompanies this distribution,
+... and is available at http://www.eclipse.org/legal/epl-v10.html
+...
+... Test suite performs basic iBGP functional test case for
+... carrying LSP State Information in BGP as described in
+... http://tools.ietf.org/html/draft-ietf-idr-te-lsp-distribution-03
+...
+Suite Setup Setup_Everything
+Suite Teardown Teardown_Everything
+Test Setup SetupUtils.Setup_Test_With_Logging_And_Without_Fast_Failing
+Test Teardown SetupUtils.Teardown_Test_Show_Bugs_If_Test_Failed
+Library OperatingSystem
+Library RequestsLibrary
+Library DateTime
+Variables ${CURDIR}/../../../variables/Variables.py
+Variables ${CURDIR}/../../../variables/bgpuser/variables.py ${ODL_SYSTEM_PROMPT}
+Resource ${CURDIR}/../../../libraries/BGPcliKeywords.robot
+Resource ${CURDIR}/../../../libraries/BGPSpeaker.robot
+Resource ${CURDIR}/../../../libraries/ConfigViaRestconf.robot
+Resource ${CURDIR}/../../../libraries/FailFast.robot
+Resource ${CURDIR}/../../../libraries/KarafKeywords.robot
+Resource ${CURDIR}/../../../libraries/KillPythonTool.robot
+Resource ${CURDIR}/../../../libraries/SetupUtils.robot
+Resource ${CURDIR}/../../../libraries/SSHKeywords.robot
+Resource ${CURDIR}/../../../libraries/Utils.robot
+Resource ${CURDIR}/../../../libraries/WaitForFailure.robot
+
+*** Variables ***
+${BGP_VARIABLES_FOLDER} ${CURDIR}/../../../variables/bgpuser/
+${COUNT} 1
+${HOLDTIME} 180
+${BGP_PEER_LOG_FILE} bgp_peer.log
+${BGP_PEER_COMMAND} python play.py --amount ${COUNT} --myip=${TOOLS_SYSTEM_IP} --myport=${BGP_TOOL_PORT} --peerip=${ODL_SYSTEM_IP} --peerport=${ODL_BGP_PORT} --${BGP_PEER_LOG_LEVEL} --logfile ${BGP_PEER_LOG_FILE} --bgpls True
+${BGP_PEER_OPTIONS} &>${BGP_PEER_LOG_FILE}
+${DEFAULT_RIB_CHECK_PERIOD} 1s
+${DEFAULT_RIB_CHECK_TIMEOUT} 10s
+${BGP_PEER_LOG_LEVEL} debug
+${CONTROLLER_LOG_LEVEL} INFO
+${CONTROLLER_BGP_LOG_LEVEL} DEFAULT
+
+*** Test Cases ***
+TC1_Configure_iBGP_Peer
+ [Tags] critical
+ [Documentation] Configure BGP peer module with initiate-connection set to false.
+ ${template_as_string}= BuiltIn.Set_Variable {'NAME': 'example-bgp-peer', 'IP': '${TOOLS_SYSTEM_IP}', 'HOLDTIME': '${HOLDTIME}', 'PEER_PORT': '${BGP_TOOL_PORT}', 'INITIATE': 'false'}
+ ConfigViaRestconf.Put_Xml_Template_Folder_Config_Via_Restconf ${BGP_VARIABLES_FOLDER}${/}bgp_peer ${template_as_string}
+
+TC1_Check_Example_Bgp_Rib_Is_Empty
+ [Documentation] Check RIB for none linkstate-routes
+ [Tags] critical
+ SSHLibrary.Switch Connection bgp_peer_console
+ Check_Example_Bgp_Rib_Does_Not_Contain "bgp-linkstate:linkstate-routes": {.+}
+
+TC1_Connect_BGP_Peer
+ [Documentation] Connect BGP peer
+ [Tags] critical
+ SSHLibrary.Switch Connection bgp_peer_console
+ BGPcliKeywords.Start_Console_Tool ${BGP_PEER_COMMAND} ${BGP_PEER_OPTIONS}
+ BGPcliKeywords.Read_And_Fail_If_Prompt_Is_Seen
+
+TC1_Check_Example_Bgp_Rib
+ [Documentation] Check RIB for linkstate-route(s)
+ [Tags] critical
+ SSHLibrary.Switch Connection bgp_peer_console
+ BuiltIn.Wait_Until_Keyword_Succeeds ${DEFAULT_RIB_CHECK_TIMEOUT} ${DEFAULT_RIB_CHECK_PERIOD} Check_Example_Bgp_Rib_Content "bgp-linkstate:linkstate-routes": {.+}
+
+TC1_Disconnect_BGP_Peer
+ [Documentation] Stop BGP peer & store logs
+ [Tags] critical
+ SSHLibrary.Switch Connection bgp_peer_console
+ BGPcliKeywords.Stop_Console_Tool
+ BGPcliKeywords.Store_File_To_Workspace ${BGP_PEER_LOG_FILE} tc1_${BGP_PEER_LOG_FILE}
+
+*** Keywords ***
+Setup_Everything
+ [Documentation] SSH-login to mininet machine, create HTTP session,
+ ... prepare directories for responses, put Python tool to mininet machine, setup imported resources.
+ SetupUtils.Setup_Utils_For_Setup_And_Teardown
+ SSHLibrary.Set_Default_Configuration prompt=${TOOLS_SYSTEM_PROMPT}
+ SSHLibrary.Open_Connection ${TOOLS_SYSTEM_IP} alias=bgp_peer_console
+ Utils.Flexible_Mininet_Login
+ SSHKeywords.Require_Python
+ SSHKeywords.Assure_Library_Ipaddr target_dir=.
+ SSHLibrary.Put_File ${CURDIR}/../../../../tools/fastbgp/play.py
+ RequestsLibrary.Create_Session operational http://${ODL_SYSTEM_IP}:${RESTCONFPORT}${OPERATIONAL_API} auth=${AUTH}
+ ConfigViaRestconf.Setup_Config_Via_Restconf
+ KarafKeywords.Execute_Controller_Karaf_Command_On_Background log:set ${CONTROLLER_LOG_LEVEL}
+ KarafKeywords.Execute_Controller_Karaf_Command_On_Background log:set ${CONTROLLER_BGP_LOG_LEVEL} org.opendaylight.bgpcep
+ KarafKeywords.Execute_Controller_Karaf_Command_On_Background log:set ${CONTROLLER_BGP_LOG_LEVEL} org.opendaylight.protocol
+
+Teardown_Everything
+ [Documentation] Create and Log the diff between expected and actual responses, make sure Python tool was killed.
+ ... Tear down imported Resources.
+ KillPythonTool.Search_And_Kill_Remote_Python 'play\.py'
+ ConfigViaRestconf.Teardown_Config_Via_Restconf
+ RequestsLibrary.Delete_All_Sessions
+ SSHLibrary.Close_All_Connections
+
+Check_Example_Bgp_Rib_Content
+ [Arguments] ${pattern} ${error_message}=Expected pattern not found.
+ [Documentation] Check the example-bgp-rib content for string
+ ${response}= RequestsLibrary.Get Request operational bgp-rib:bgp-rib/rib/example-bgp-rib
+ BuiltIn.Log ${response.status_code}
+ BuiltIn.Log ${response.text}
+ BuiltIn.Should_Match_Regexp ${response.text} ${pattern} ${error_message} values=False
+
+Check_Example_Bgp_Rib_Does_Not_Contain
+ [Arguments] ${pattern} ${error_message}=Unexpected pattern found.
+ [Documentation] Check the example-bgp-rib does not contain the string
+ ${response}= RequestsLibrary.Get Request operational bgp-rib:bgp-rib/rib/example-bgp-rib
+ BuiltIn.Log ${response.status_code}
+ BuiltIn.Log ${response.text}
+ BuiltIn.Should_Not_Match_Regexp ${response.text} ${pattern} ${error_message} values=False
str_help = "Minimum number of updates to reach to include result into csv."
parser.add_argument("--threshold", default="1000", type=int, help=str_help)
str_help = "RFC 4760 Multiprotocol Extensions for BGP-4 supported"
- parser.add_argument("--rfc4760", default="yes", type=str, help=str_help)
+ parser.add_argument("--rfc4760", default=True, type=bool, help=str_help)
+ str_help = "Link-State NLRI supported"
+ parser.add_argument("--bgpls", default=False, type=bool, help=str_help)
+ str_help = "Link-State NLRI: Identifier"
+ parser.add_argument("-lsid", default="1", type=int, help=str_help)
+ str_help = "Link-State NLRI: Tunnel ID"
+ parser.add_argument("-lstid", default="1", type=int, help=str_help)
+ str_help = "Link-State NLRI: LSP ID"
+ parser.add_argument("-lspid", default="1", type=int, help=str_help)
+ str_help = "Link-State NLRI: IPv4 Tunnel Sender Address"
+ parser.add_argument("--lstsaddr", default="1.2.3.4",
+ type=ipaddr.IPv4Address, help=str_help)
+ str_help = "Link-State NLRI: IPv4 Tunnel End Point Address"
+ parser.add_argument("--lsteaddr", default="5.6.7.8",
+ type=ipaddr.IPv4Address, help=str_help)
+ str_help = "Link-State NLRI: Identifier Step"
+ parser.add_argument("-lsidstep", default="1", type=int, help=str_help)
+ str_help = "Link-State NLRI: Tunnel ID Step"
+ parser.add_argument("-lstidstep", default="2", type=int, help=str_help)
+ str_help = "Link-State NLRI: LSP ID Step"
+ parser.add_argument("-lspidstep", default="4", type=int, help=str_help)
+ str_help = "Link-State NLRI: IPv4 Tunnel Sender Address Step"
+ parser.add_argument("-lstsaddrstep", default="16", type=int, help=str_help)
+ str_help = "Link-State NLRI: IPv4 Tunnel End Point Address Step"
+ parser.add_argument("-lsteaddrstep", default="1", type=int, help=str_help)
str_help = "How many play utilities are to be started."
parser.add_argument("--multiplicity", default="1", type=int, help=str_help)
arguments = parser.parse_args()
self.remaining_prefixes_threshold = self.total_prefix_amount - args.prefill
self.results_file_name_default = args.results
self.performance_threshold_default = args.threshold
- self.rfc4760 = args.rfc4760 == "yes"
+ self.rfc4760 = args.rfc4760
+ self.bgpls = args.bgpls
+ # Default values when BGP-LS Attributes are used
+ if self.bgpls:
+ self.prefix_count_to_add_default = 1
+ self.prefix_count_to_del_default = 0
+ self.ls_nlri_default = {"Identifier": args.lsid,
+ "TunnelID": args.lstid,
+ "LSPID": args.lspid,
+ "IPv4TunnelSenderAddress": args.lstsaddr,
+ "IPv4TunnelEndPointAddress": args.lsteaddr}
+ self.lsid_step = args.lsidstep
+ self.lstid_step = args.lstidstep
+ self.lspid_step = args.lspidstep
+ self.lstsaddr_step = args.lstsaddrstep
+ self.lsteaddr_step = args.lsteaddrstep
# Default values used for randomized part
s1_slots = ((self.total_prefix_amount -
self.remaining_prefixes_threshold - 1) /
self.prefix_count_to_add_default + 1)
self.randomize_lowest_default = s2_first_index
self.randomize_highest_default = s2_last_index
-
# Initialising counters
self.phase1_start_time = 0
self.phase1_stop_time = 0
new_index = index
return new_index
- # Get list of prefixes
+ def get_ls_nlri_values(self, index):
+ """Generates LS-NLRI parameters.
+ http://tools.ietf.org/html/draft-ietf-idr-te-lsp-distribution-03
+
+ Arguments:
+ :param index: index (iteration)
+ Returns:
+ :return: dictionary of LS NLRI parameters and values
+ """
+ # generating list of LS NLRI parameters
+ identifier = self.ls_nlri_default["Identifier"] + index / self.lsid_step
+ ipv4_tunnel_sender_address = self.ls_nlri_default["IPv4TunnelSenderAddress"] + index / self.lstsaddr_step
+ tunnel_id = self.ls_nlri_default["TunnelID"] + index / self.lstid_step
+ lsp_id = self.ls_nlri_default["LSPID"] + index / self.lspid_step
+ ipv4_tunnel_endpoint_address = self.ls_nlri_default["IPv4TunnelEndPointAddress"] + index / self.lsteaddr_step
+ ls_nlri_values = {"Identifier": identifier,
+ "IPv4TunnelSenderAddress": ipv4_tunnel_sender_address,
+ "TunnelID": tunnel_id, "LSPID": lsp_id,
+ "IPv4TunnelEndPointAddress": ipv4_tunnel_endpoint_address}
+ return ls_nlri_values
+
def get_prefix_list(self, slot_index, slot_size=None, prefix_base=None,
prefix_len=None, prefix_count=None, randomize=None):
"""Generates list of IP address prefixes.
logger.debug("Prefixes to be withdrawn in this iteration:")
prefix_list_to_del = self.get_prefix_list(slot_index_to_del,
prefix_count=prefix_count_to_del)
- # generating the mesage
- if self.single_update_default:
- # Send prefixes to be introduced and withdrawn
- # in one UPDATE message
- msg_out = self.update_message(wr_prefixes=prefix_list_to_del,
- nlri_prefixes=prefix_list_to_add)
+ # generating the UPDATE mesage with LS-NLRI only
+ if self.bgpls:
+ ls_nlri = self.get_ls_nlri_values(self.iteration)
+ msg_out = self.update_message(wr_prefixes=[], nlri_prefixes=[],
+ **ls_nlri)
else:
- # Send prefixes to be introduced and withdrawn
- # in separate UPDATE messages (if needed)
- msg_out = self.update_message(wr_prefixes=[],
- nlri_prefixes=prefix_list_to_add)
- if prefix_count_to_del:
- msg_out += self.update_message(wr_prefixes=prefix_list_to_del,
- nlri_prefixes=[])
+ # generating the UPDATE message with prefix lists
+ if self.single_update_default:
+ # Send prefixes to be introduced and withdrawn
+ # in one UPDATE message
+ msg_out = self.update_message(wr_prefixes=prefix_list_to_del,
+ nlri_prefixes=prefix_list_to_add)
+ else:
+ # Send prefixes to be introduced and withdrawn
+ # in separate UPDATE messages (if needed)
+ msg_out = self.update_message(wr_prefixes=[],
+ nlri_prefixes=prefix_list_to_add)
+ if prefix_count_to_del:
+ msg_out += self.update_message(wr_prefixes=prefix_list_to_del,
+ nlri_prefixes=[])
# updating counters - who knows ... maybe I am last time here ;)
if straightforward_scenario:
self.phase1_stop_time = time.time()
)
optional_parameters_hex += optional_parameter_hex
+ if self.bgpls:
+ optional_parameter_hex = (
+ "\x02" # Param type ("Capability Ad")
+ "\x06" # Length (6 bytes)
+ "\x01" # Capability type (NLRI Unicast),
+ # see RFC 4760, secton 8
+ "\x04" # Capability value length
+ "\x40\x04" # AFI (BGP-LS)
+ "\x00" # (reserved)
+ "\x47" # SAFI (BGP-LS)
+ )
+ optional_parameters_hex += optional_parameter_hex
+
optional_parameter_hex = (
"\x02" # Param type ("Capability Ad")
"\x06" # Length (6 bytes)
def update_message(self, wr_prefixes=None, nlri_prefixes=None,
wr_prefix_length=None, nlri_prefix_length=None,
my_autonomous_system=None, next_hop=None,
- originator_id=None, cluster_list_item=None):
+ originator_id=None, cluster_list_item=None,
+ end_of_rib=False, **ls_nlri_params):
"""Generates an UPDATE Message (rfc4271#section-4.3)
Arguments:
originator_id = self.originator_id_default
if cluster_list_item is None:
cluster_list_item = self.cluster_list_item_default
+ ls_nlri = self.ls_nlri_default.copy()
+ ls_nlri.update(ls_nlri_params)
# Marker
marker_hex = "\xFF" * 16
type_hex = struct.pack("B", type)
# Withdrawn Routes
- bytes = ((wr_prefix_length - 1) / 8) + 1
withdrawn_routes_hex = ""
- for prefix in wr_prefixes:
- withdrawn_route_hex = (struct.pack("B", wr_prefix_length) +
- struct.pack(">I", int(prefix))[:bytes])
- withdrawn_routes_hex += withdrawn_route_hex
+ if not self.bgpls:
+ bytes = ((wr_prefix_length - 1) / 8) + 1
+ for prefix in wr_prefixes:
+ withdrawn_route_hex = (struct.pack("B", wr_prefix_length) +
+ struct.pack(">I", int(prefix))[:bytes])
+ withdrawn_routes_hex += withdrawn_route_hex
# Withdrawn Routes Length
withdrawn_routes_length = len(withdrawn_routes_hex)
) # one CLUSTER_LIST item (4 bytes)
path_attributes_hex += struct.pack(">I", int(cluster_list_item))
+ if self.bgpls and not end_of_rib:
+ path_attributes_hex += (
+ "\x80" # Flags ("Optional, non-transitive")
+ "\x0e" # Type (MP_REACH_NLRI)
+ "\x22" # Length (34)
+ "\x40\x04" # AFI (BGP-LS)
+ "\x47" # SAFI (BGP-LS)
+ "\x04" # Next Hop Length (4)
+ )
+ path_attributes_hex += struct.pack(">I", int(next_hop))
+ path_attributes_hex += "\x00" # Reserved
+ path_attributes_hex += (
+ "\x00\x05" # LS-NLRI.NLRIType (IPv4 TE LSP NLRI)
+ "\x00\x15" # LS-NLRI.TotalNLRILength (21)
+ "\x07" # LS-NLRI.Variable.ProtocolID (RSVP-TE)
+ )
+ path_attributes_hex += struct.pack(">Q", int(ls_nlri["Identifier"]))
+ path_attributes_hex += struct.pack(">I", int(ls_nlri["IPv4TunnelSenderAddress"]))
+ path_attributes_hex += struct.pack(">H", int(ls_nlri["TunnelID"]))
+ path_attributes_hex += struct.pack(">H", int(ls_nlri["LSPID"]))
+ path_attributes_hex += struct.pack(">I", int(ls_nlri["IPv4TunnelEndPointAddress"]))
+
# Total Path Attributes Length
total_path_attributes_length = len(path_attributes_hex)
total_path_attributes_length_hex = struct.pack(">H", total_path_attributes_length)
# Network Layer Reachability Information
- bytes = ((nlri_prefix_length - 1) / 8) + 1
nlri_hex = ""
- for prefix in nlri_prefixes:
- nlri_prefix_hex = (struct.pack("B", nlri_prefix_length) +
- struct.pack(">I", int(prefix))[:bytes])
- nlri_hex += nlri_prefix_hex
+ if not self.bgpls:
+ bytes = ((nlri_prefix_length - 1) / 8) + 1
+ for prefix in nlri_prefixes:
+ nlri_prefix_hex = (struct.pack("B", nlri_prefix_length) +
+ struct.pack(">I", int(prefix))[:bytes])
+ nlri_hex += nlri_prefix_hex
# Length (big-endian)
length = (
logger.debug(" Originator id=" + str(originator_id))
if cluster_list_item is not None:
logger.debug(" Cluster list=" + str(cluster_list_item))
+ if self.bgpls:
+ logger.debug(" MP_REACH_NLRI: %s", ls_nlri)
logger.debug(" Network Layer Reachability Information=" +
str(nlri_prefixes) + "/" + str(nlri_prefix_length) +
" (0x" + binascii.hexlify(nlri_hex) + ")")
self.generator.store_results()
logger.info("Finally an END-OF-RIB is sent.")
msg_out += self.generator.update_message(wr_prefixes=[],
- nlri_prefixes=[])
+ nlri_prefixes=[],
+ end_of_rib=True)
self.writer.enqueue_message_for_sending(msg_out)
# Attempt for real sending to be done in next iteration.
return