Revert "tests: add bgp_linkstate_topo1"

This reverts commit a0e6cd4c8f.

(cherry picked from commit c4edb3a453)
This commit is contained in:
Donald Sharp 2023-10-10 16:43:17 -04:00 committed by Mergify
parent 492d542ba0
commit 880183419a
14 changed files with 0 additions and 1164 deletions

View File

@ -1,202 +0,0 @@
// Check content with
// cat bgp_injector.cfg | sed -e 's|//.*||g' | jq .
{
"my_as": 65001,
"hold_time": 30,
"bgp_identifier": "192.0.2.1",
"local_address": "192.0.2.1",
"peer_address": "192.0.2.2",
"mss": 4000,
"port": 179,
"path_attributes":
{
"as-path": "65001",
"next-hop": "192.0.2.1",
"origin": 0
},
"link_states":
[
{
"nlri":
{
"proto": "01", // IS-IS L1
"id": "0000000000000020",
"type": "0002", // Link-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"515": "000000001001" // router-id: 0000.0000.1001
},
"257": { // Remote Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"515": "000000001000" // router-id: 0000.0000.1000
},
"259": "0a010001", // IPv4 interface address TLV
"260": "0a010002", // IPv4 Neighbor address TLV
"261": "20010000000000000000000000000001", // IPv6 interface address TLV
"262": "20010000000000000000000000000002", // IPv6 Neighbor address TLV
"263": "00000002" // MT-ID
},
"attr":
{
"1028": "01010101", //IPv4 Router-ID of Local Node TLV
"1030": "0a0a0a0a", //IPv4 Router-ID of Remote Node TLV
"1089": "4d2817c8", // Maximum link bandwidth TLV 1410.07 Mbps
"1090": "4d2817c8", // Maximum reservable link bandwidth TLV 1410.07 Mbps
"1091": "4d2817c84d2817c84d2817c84d2817c84d2817c84d2817c84d2817c84d2817c8", // Unreserved bandwidth TLV
"1092": "00000064", // TE Default Metric TLV
"1095": "00000a", // Metric TLV
// Adjacency SID TLV
// Flags: 0x30, Value Flag (V), Local Flag (L)
// Weight: 0
// .... 0000 0011 1010 1001 1000 = SID/Label: 15000
"1099": "30000000003a98",
//Unidirectional Link Delay TLV
// TE Metric Flags: 0x00
// Delay: 8500
"1114": "00002134",
//Min/Max Unidirectional Link Delay TLV
// TE Metric Flags: 0x00
// Min Delay: 8000
// Reserved: 0x00
// Max Delay: 9000
"1115": "00001f4000002328",
"1122": { //Application-Specific Link Attributes TLV
// Type: 1122
// Length: 48
// SABM Length: 4
// UDABM Length: 4
// Reserved: 0x0000
// Standard Application Identifier Bit Mask: 0x10000000, Flexible Algorithm (X)
// User-Defined Application Identifier Bit Mask: 00 00 00 00
"0": "040400001000000000000000", // 0 means encode data directly
"1088": "00000001", // Administrative group (color) TLV
"1092": "00000064", // TE Default Metric TLV
"1115": "00001f4000002328", // Min/Max Unidirectional Link Delay TLV
"1173": "00000001"// Extended Administrative Group TLV
}
}
},
{
"nlri":
{
"proto": "01", // IS-IS L1
"id": "0000000000000020",
"type": "0001", // Node-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"515": "00000000100300" // router-id: 0000.0000.1003.00
}
},
"attr":
{
"0": "0107000400000002010a00020108040200027233040300034910000404000403030303040a000cc000000fa004890003004e20040b0003008082040c000c00000003e804890003003a98"
}
},
{
"nlri":
{
"proto": "03", // OSPFv2
"id": "0000000000000020",
"type": "0001", // Node-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"514": "00000000", // Area 0
"515": "0a0a0a0a" // router-id: 10.10.10.10
}
}
},
{
"nlri":
{
"proto": "03", // OSPFv2
"id": "0000000000000020",
"type": "0001", // Node-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"514": "00000000", // Area 0
"515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1
}
}
},
{
"nlri":
{
"proto": "03", // OSPFv2
"id": "0000000000000020",
"type": "0003", // IPv4-topo-prefix-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"514": "00000000", // Area 0
"515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1
},
"265": "18590a0b" // IP Reachability Information TLV (89.10.11.0/24)
}
},
{
"nlri":
{
"proto": "02", // IS-IS L2
"id": "0000000000000020",
"type": "0004", // IPv6-topo-prefix-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"515": "00000000100300" // router-id: 0000.0000.1003.00
},
"263": "0002", // MT-ID
// IP Reachability Information TLV (12:12::12:12/128)
"265": "8000120012000000000000000000120012"
}
},
{
"nlri":
{
"proto": "06", // OSPFv3
"id": "0000000000000020",
"type": "0004", // IPv6-topo-prefix-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "0000fde9", // AS 65001
"513": "00000000", // BGP-LS ID
"514": "00000000", // Area 0
"515": "0a0a0a0a" // router-id: 10.10.10.10
},
"263": "0002", // MT-ID
"264": "01", // OSPF: route-type Intra-Area (0x1)
// IP Reachability Information TLV (12:12::12:12/128)
"265": "8000120012000000000000000000120012"
}
},
{
"nlri":
{
"proto": "06", // OSPFv3
"id": "ffffffffffffffff",
"type": "0002", // Link-NLRI
"256": { // Local Link-Node Descriptor TLV
"512": "ffffffff", // AS
"513": "ffffffff", // BGP-LS ID
"514": "ffffffff", // OSPF area ID
"515": "0a0a0a0b02020202" // router-id: 10.10.10.11:2.2.2.2
},
"257": { // Remote Link-Node Descriptor TLV
"512": "ffffffff", // AS
"513": "ffffffff", // BGP-LS ID
"514": "ffffffff", // OSPF area ID
"515": "0a0a0a0a01010101" // router-id: 10.10.10.10:1.1.1.1
},
"259": "0a010001", // IPv4 interface address TLV
"260": "0a010002", // IPv4 Neighbor address TLV
"261": "20010000000000000000000000000001", // IPv6 interface address TLV
"262": "20010000000000000000000000000002", // IPv6 Neighbor address TLV
"263": "00000002", // MT-ID
"424": "200100000000000001" // unknown TLV
}
}
]
}

View File

@ -1,596 +0,0 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: MIT
#
# Copyright 2018 Jorge Borreicho
# Copyright 2023 6WIND S.A.
"""
BGP prefix injection tool
"""
import socket
import sys
import time
from datetime import datetime
import struct
import threading
import json
import os
import re
import signal
import errno
AFI_IPV4 = 1
SAFI_UNICAST = 1
AFI_LINKSTATE = 16388
SAFI_LINKSTATE = 71
saved_pid = False
global pid_file
class Unbuffered(object):
def __init__(self, stream):
self.stream = stream
def write(self, data):
self.stream.write(data)
self.stream.flush()
def writelines(self, datas):
self.stream.writelines(datas)
self.stream.flush()
def __getattr__(self, attr):
return getattr(self.stream, attr)
def keepalive_thread(conn, interval):
# infinite loop so that function do not terminate and thread do not end.
while True:
time.sleep(interval)
keepalive_bgp(conn)
def receive_thread(conn):
# infinite loop so that function do not terminate and thread do not end.
while True:
# Receiving from client
r = conn.recv(1500)
while True:
start_ptr = (
r.find(
b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
)
+ 16
)
end_ptr = (
r[16:].find(
b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
)
+ 16
)
if (
start_ptr >= end_ptr
): # a single message was sent in the BGP packet OR it is the last message of the BGP packet
decode_bgp(r[start_ptr:])
break
else: # more messages left to decode
decode_bgp(r[start_ptr:end_ptr])
r = r[end_ptr:]
def decode_bgp(msg):
if len(msg) < 3:
return
msg_length, msg_type = struct.unpack("!HB", msg[0:3])
if msg_type == 4:
# print(timestamp + " - " + "Received KEEPALIVE") #uncomment to debug
pass
elif msg_type == 2:
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Received UPDATE")
elif msg_type == 1:
version, remote_as, holdtime, i1, i2, i3, i4, opt_length = struct.unpack(
"!BHHBBBBB", msg[3:13]
)
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Received OPEN")
print()
print(
"--> Version:"
+ str(version)
+ ", Remote AS: "
+ str(remote_as)
+ ", Hold Time:"
+ str(holdtime)
+ ", Remote ID: "
+ str(i1)
+ "."
+ str(i2)
+ "."
+ str(i3)
+ "."
+ str(i4)
)
print()
elif msg_type == 3:
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Received NOTIFICATION")
def multiprotocol_capability(afi, safi):
hexstream = bytes.fromhex("02060104")
hexstream += struct.pack("!H", afi)
hexstream += struct.pack("!B", 0)
hexstream += struct.pack("!B", safi)
return hexstream
def open_bgp(conn, config):
# Build the BGP Message
bgp_version = b"\x04"
bgp_as = struct.pack("!H", config["my_as"])
bgp_hold_time = struct.pack("!H", config["hold_time"])
octet = config["bgp_identifier"].split(".")
bgp_identifier = struct.pack(
"!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3])
)
bgp_opt = b""
bgp_opt += multiprotocol_capability(AFI_IPV4, SAFI_UNICAST)
bgp_opt += multiprotocol_capability(AFI_LINKSTATE, SAFI_LINKSTATE)
bgp_opt_lenght = struct.pack("!B", len(bgp_opt))
bgp_message = (
bgp_version + bgp_as + bgp_hold_time + bgp_identifier + bgp_opt_lenght + bgp_opt
)
# Build the BGP Header
total_length = len(bgp_message) + 16 + 2 + 1
bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
bgp_length = struct.pack("!H", total_length)
bgp_type = b"\x01"
bgp_header = bgp_marker + bgp_length + bgp_type
bgp_packet = bgp_header + bgp_message
conn.send(bgp_packet)
return 0
def keepalive_bgp(conn):
# Build the BGP Header
total_length = 16 + 2 + 1
bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
bgp_length = struct.pack("!H", total_length)
bgp_type = b"\x04"
bgp_header = bgp_marker + bgp_length + bgp_type
bgp_packet = bgp_header
conn.send(bgp_packet)
return 0
def encode_ipv4_prefix(address, netmask):
octet = address.split(".")
length = struct.pack("!B", int(netmask))
if int(netmask) <= 8:
prefix = struct.pack("!B", int(octet[0]))
elif int(netmask) <= 16:
prefix = struct.pack("!BB", int(octet[0]), int(octet[1]))
elif int(netmask) <= 24:
prefix = struct.pack("!BBB", int(octet[0]), int(octet[1]), int(octet[2]))
else:
prefix = struct.pack(
"!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3])
)
return length + prefix
def encode_path_attribute_mp_reach_nrli(afi, safi, data, config):
hexstream = b""
hexstream += b"\x90" # flags optional, extended
hexstream += struct.pack("!B", 14) # type code MP_REACH_NLRI
hexstream2 = b""
hexstream2 += struct.pack("!H", afi)
hexstream2 += struct.pack("!B", safi)
hexstream2 += struct.pack("!B", 4) # nexthop length
hexstream2 += socket.inet_aton(config["local_address"]) # nexthop IPv4
hexstream2 += b"\x00" # SNPA
hexstream2 += data
hexstream += struct.pack("!H", len(hexstream2)) # length
hexstream += hexstream2
return hexstream
def encode_path_attribute_linkstate(data):
hexstream = b""
hexstream += b"\x80" # flags optional
hexstream += struct.pack("!B", 29) # type code BGP-LS
hexstream += struct.pack("!B", len(data)) # length
hexstream += data
return hexstream
def encode_path_attribute(type, value):
path_attributes = {
"origin": [b"\x40", 1],
"as-path": [b"\x40", 2],
"next-hop": [b"\x40", 3],
"med": [b"\x80", 4],
"local_pref": [b"\x40", 5],
"communities": [b"\xc0", 8],
}
attribute_flag = path_attributes[type][0]
attribute_type_code = struct.pack("!B", int(path_attributes[type][1]))
if type == "origin":
attribute_value = struct.pack("!B", value)
elif type == "as-path":
as_number_list = value.split(" ")
attribute_value = struct.pack("!BB", 2, len(as_number_list))
for as_number in as_number_list:
attribute_value += struct.pack("!H", int(as_number))
elif type == "next-hop":
octet = value.split(".")
attribute_value = struct.pack(
"!BBBB", int(octet[0]), int(octet[1]), int(octet[2]), int(octet[3])
)
elif type == "med":
attribute_value = struct.pack("!I", value)
elif type == "local_pref":
attribute_value = struct.pack("!I", value)
elif type == "communities":
communities_list = value.split(" ")
attribute_value = b""
for community in communities_list:
aux = community.split(":")
attribute_value += struct.pack("!HH", int(aux[0]), int(aux[1]))
attribute_length = struct.pack("!B", len(attribute_value))
return attribute_flag + attribute_type_code + attribute_length + attribute_value
def encode_tlvs(tlvs):
stream = b""
for key, tlv_data in tlvs.items():
if isinstance(key, str) and key.isdigit():
tlv_type = int(key)
else:
# key is not a TLV
continue
if isinstance(tlv_data, str):
if tlv_type != 0:
# TLV type 0 is fake TLV
stream += struct.pack("!H", tlv_type)
stream += struct.pack("!H", len(bytes.fromhex(tlv_data)))
stream += bytes.fromhex(tlv_data)
elif isinstance(tlv_data, dict):
# TLV contains sub-TLV
stream += struct.pack("!H", tlv_type)
stream_subtlv = encode_tlvs(tlv_data)
stream += struct.pack("!H", len(stream_subtlv))
stream += stream_subtlv
else:
# invalid input
assert 0
return stream
def encode_linkstate_nrli_tlv(nlri):
stream = b""
stream += bytes.fromhex(nlri["type"])
stream2 = b""
stream2 += bytes.fromhex(nlri["proto"])
stream2 += bytes.fromhex(nlri["id"])
stream2 += encode_tlvs(nlri)
stream += struct.pack("!H", len(stream2))
stream += stream2
return stream
def update_bgp(conn, link_state, config):
# Build the BGP Message
# Expired Routes
# 1 - Withdrawn Routes
bgp_withdrawn_routes = b""
max_length_reached = False
bgp_withdrawn_routes_length = struct.pack("!H", len(bgp_withdrawn_routes))
bgp_withdrawn_routes = bgp_withdrawn_routes_length + bgp_withdrawn_routes
# New Routes
# 2 - Path Attributes
path_attributes = config["path_attributes"]
bgp_mss = config["mss"]
bgp_total_path_attributes = b""
# encode link-state MP_REACH NLRI
data = encode_linkstate_nrli_tlv(link_state["nlri"])
bgp_total_path_attributes += encode_path_attribute_mp_reach_nrli(
AFI_LINKSTATE, SAFI_LINKSTATE, data, config
)
# encode classic attributes
for key in path_attributes.keys():
bgp_total_path_attributes += encode_path_attribute(key, path_attributes[key])
# encode link-state attributes
if "attr" in link_state:
data = encode_tlvs(link_state["attr"])
else:
data = b""
bgp_total_path_attributes += encode_path_attribute_linkstate(data)
bgp_total_path_attributes_length = struct.pack("!H", len(bgp_total_path_attributes))
bgp_total_path_attributes = (
bgp_total_path_attributes_length + bgp_total_path_attributes
)
# 3- Network Layer Reachability Information (NLRI)
bgp_new_routes = b""
bgp_message = bgp_withdrawn_routes + bgp_total_path_attributes + bgp_new_routes
# Build the BGP Header
total_length = len(bgp_message) + 16 + 2 + 1
bgp_marker = b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
bgp_length = struct.pack("!H", total_length)
bgp_type = b"\x02"
bgp_header = bgp_marker + bgp_length + bgp_type
bgp_packet = bgp_header + bgp_message
conn.send(bgp_packet)
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Sent UPDATE")
return 0
def str2ip(ip_str):
s_octet = ip_str.split(".")
ip_addr = struct.pack(
"!BBBB", int(s_octet[0]), int(s_octet[1]), int(s_octet[2]), int(s_octet[3])
)
return ip_addr
def check_pid(pid):
if pid < 0: # user input error
return False
if pid == 0: # all processes
return False
try:
os.kill(pid, 0)
return True
except OSError as err:
if err.errno == errno.EPERM: # a process we were denied access to
return True
if err.errno == errno.ESRCH: # No such process
return False
# should never happen
return False
def savepid():
ownid = os.getpid()
flags = os.O_CREAT | os.O_EXCL | os.O_WRONLY
mode = ((os.R_OK | os.W_OK) << 6) | (os.R_OK << 3) | os.R_OK
try:
fd = os.open(pid_file, flags, mode)
except OSError:
try:
pid = open(pid_file, "r").readline().strip()
if check_pid(int(pid)):
sys.stderr.write(
"PIDfile already exists and program still running %s\n" % pid_file
)
return False
else:
# If pid is not running, reopen file without O_EXCL
fd = os.open(pid_file, flags ^ os.O_EXCL, mode)
except (OSError, IOError, ValueError):
sys.stderr.write(
"issue accessing PID file %s (most likely permission or ownership)\n"
% pid_file
)
return False
try:
f = os.fdopen(fd, "w")
line = "%d\n" % ownid
f.write(line)
f.close()
saved_pid = True
except IOError:
sys.stderr.write("Can not create PIDfile %s\n" % pid_file)
return False
print("Created PIDfile %s with value %d\n" % (pid_file, ownid))
return True
def removepid():
if not saved_pid:
return
try:
os.remove(pid_file)
except OSError as exc:
if exc.errno == errno.ENOENT:
pass
else:
sys.stderr.write("Can not remove PIDfile %s\n" % pid_file)
return
sys.stderr.write("Removed PIDfile %s\n" % pid_file)
def daemonize():
try:
pid = os.fork()
if pid > 0:
# Exit first parent
sys.exit(0)
except OSError as e:
print("Fork #1 failed: %d (%s)" % (e.errno, e.strerror))
sys.exit(1)
# Decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# Do second fork
try:
pid = os.fork()
if pid > 0:
# Exit from second parent
sys.exit(0)
except OSError as e:
print("Fork #2 failed: %d (%s)" % (e.errno, e.strerror))
sys.exit(1)
# Redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, "r")
so = open(os.devnull, "a+")
se = open(os.devnull, "a+")
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
def term(signal, frame):
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "^C received, shutting down.\n")
bgp_socket.close()
removepid()
exit()
if __name__ == "__main__":
if len(sys.argv) > 1:
# daemonize and log to file
daemonize()
pid_file = os.path.join(sys.argv[1], "bgp_injector.pid")
savepid()
# deal with daemon termination
signal.signal(signal.SIGTERM, term)
signal.signal(signal.SIGINT, term) # CTRL + C
log_dir = os.path.join(sys.argv[1], "bgp_injector.log")
f = open(log_dir, 'w')
sys.stdout = Unbuffered(f)
sys.stderr = Unbuffered(f)
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Starting BGP injector ")
CONFIG_FILENAME = os.path.join(sys.path[0], "bgp_injector.cfg")
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Reading config file " + CONFIG_FILENAME)
input_file = open(CONFIG_FILENAME, "r")
input = input_file.read()
# cleanup comments that are not supported by JSON
json_input = re.sub(r"//.*\n", "", input, flags=re.MULTILINE)
config = json.loads(json_input)
bgp_peer = config["peer_address"]
bgp_local = config["local_address"]
bgp_mss = config["mss"]
bgp_port = config["port"]
rib = dict()
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Starting BGP... (peer: " + str(bgp_peer) + ")")
retry = 30
while retry:
retry -= 1
try:
bgp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bgp_socket.bind((bgp_local, 0))
bgp_socket.connect((bgp_peer, bgp_port))
open_bgp(bgp_socket, config)
break
except TimeoutError:
if retry == 0:
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Error: timeout connecting to the peer.")
exit()
time.sleep(1)
except OSError as e:
if retry == 0:
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "Error: cannot connect to the peer: " + str(e))
exit()
time.sleep(1)
receive_worker = threading.Thread(
target=receive_thread, args=(bgp_socket,)
) # wait from BGP msg from peer and process them
receive_worker.setDaemon(True)
receive_worker.start()
keepalive_worker = threading.Thread(
target=keepalive_thread,
args=(
bgp_socket,
(config["hold_time"]) / 3,
),
) # send keep alives every 10s by default
keepalive_worker.setDaemon(True)
keepalive_worker.start()
# send a first keepalive packet before sending the initial UPDATE packet
keepalive_bgp(bgp_socket)
timestamp = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
print(timestamp + " - " + "BGP is up.")
time.sleep(3)
for link_state in config["link_states"]:
update_bgp(
bgp_socket,
link_state,
config,
)
while True:
time.sleep(60)

View File

@ -1 +0,0 @@
ip route 192.0.2.2/32 192.168.1.2

View File

@ -1,7 +0,0 @@
!
interface lo
ip address 192.0.2.1/32
!
interface r1-eth0
ip address 192.168.1.1/24
!

View File

@ -1,20 +0,0 @@
router bgp 65002
no bgp ebgp-requires-policy
neighbor 192.0.2.1 remote-as 65001
neighbor 192.0.2.1 timers connect 1
neighbor 192.0.2.1 ebgp-multihop 3
neighbor 192.0.2.1 update-source 192.0.2.2
neighbor 192.0.2.3 remote-as 65003
neighbor 192.0.2.3 timers 1 3
neighbor 192.0.2.3 timers connect 1
neighbor 192.0.2.3 ebgp-multihop 3
neighbor 192.0.2.3 update-source 192.0.2.2
address-family ipv4 unicast
no neighbor 192.0.2.1 activate
no neighbor 192.0.2.3 activate
exit-address-family
address-family link-state link-state
neighbor 192.0.2.1 activate
neighbor 192.0.2.3 activate
exit-address-family
!

View File

@ -1,189 +0,0 @@
{
"routes": {
"Link OSPFv3 ID:0xffffffffffffffff {Local {AS:4294967295 ID:4294967295 Area:4294967295 Rtr:10.10.10.11:2.2.2.2} Remote {AS:4294967295 ID:4294967295 Area:4294967295 Rtr:10.10.10.10:1.1.1.1} IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2 424:0x200100000000000001}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "Link",
"protocol": "OSPFv3",
"identifier": "0xffffffffffffffff",
"localNode": {
"as": 4294967295,
"identifier": 4294967295,
"area": 4294967295,
"routerID": "10.10.10.11:2.2.2.2"
},
"remoteNode": {
"as": 4294967295,
"identifier": 4294967295,
"area": 4294967295,
"routerID": "10.10.10.10:1.1.1.1"
},
"interfaceIPv4": "10.1.0.1",
"neighborIPv4": "10.1.0.2",
"interfaceIPv6": "2001::1",
"neighborIPv6": "2001::2",
"mtID": [0, 2],
"424": ["0x2001000000000000", "0x01"]
},
"weight": 0,
"origin": "IGP"
}
],
"IPv6-Prefix OSPFv3 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10} MT:2 OSPF-Route-Type:1 IPv6:12:12::12:12/128}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "IPv6-Prefix",
"protocol": "OSPFv3",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"area": 0,
"routerID": "10.10.10.10"
},
"ospfRouteType": 1,
"ipReachability": "12:12::12:12/128",
"mtID": [2]
},
"weight": 0,
"origin": "IGP"
}
],
"IPv6-Prefix ISIS-L2 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1003.00} MT:2 IPv6:12:12::12:12/128}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "IPv6-Prefix",
"protocol": "ISIS-L2",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"routerID": "0000.0000.1003.00"
},
"ipReachability": "12:12::12:12/128",
"mtID": [2]
},
"weight": 0,
"origin": "IGP"
}
],
"IPv4-Prefix OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1} IPv4:89.10.11.0/24}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "IPv4-Prefix",
"protocol": "OSPFv2",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"area": 0,
"routerID": "10.10.10.10:1.1.1.1"
},
"ipReachability": "89.10.11.0/24"
},
"weight": 0,
"origin": "IGP"
}
],
"Node OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10:1.1.1.1}}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "Node",
"protocol": "OSPFv2",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"area": 0,
"routerID": "10.10.10.10:1.1.1.1"
}
},
"weight": 0,
"origin": "IGP"
}
],
"Node OSPFv2 ID:0x20 {Local {AS:65001 ID:0 Area:0 Rtr:10.10.10.10}}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "Node",
"protocol": "OSPFv2",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"area": 0,
"routerID": "10.10.10.10"
}
},
"weight": 0,
"origin": "IGP"
}
],
"Node ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1003.00}}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "Node",
"protocol": "ISIS-L1",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"routerID": "0000.0000.1003.00"
}
},
"weight": 0,
"origin": "IGP"
}
],
"Link ISIS-L1 ID:0x20 {Local {AS:65001 ID:0 Rtr:0000.0000.1001} Remote {AS:65001 ID:0 Rtr:0000.0000.1000} IPv4:10.1.0.1 Neigh-IPv4:10.1.0.2 IPv6:2001::1 Neigh-IPv6:2001::2 MT:0,2}/XX": [
{
"valid": true,
"bestpath": true,
"pathFrom": "external",
"linkStateNLRI": {
"nlriType": "Link",
"protocol": "ISIS-L1",
"identifier": "0x20",
"localNode": {
"as": 65001,
"identifier": 0,
"routerID": "0000.0000.1001"
},
"remoteNode": {
"as": 65001,
"identifier": 0,
"routerID": "0000.0000.1000"
},
"interfaceIPv4": "10.1.0.1",
"neighborIPv4": "10.1.0.2",
"interfaceIPv6": "2001::1",
"neighborIPv6": "2001::2",
"mtID": [0, 2]
},
"weight": 0,
"origin": "IGP"
}
]
}
}

View File

@ -1,2 +0,0 @@
ip route 192.0.2.1/32 192.168.1.1
ip route 192.0.2.3/32 192.168.2.3

View File

@ -1,11 +0,0 @@
!
int lo
ip address 192.0.2.2/32
!
interface r2-eth0
ip address 192.168.1.2/24
!
interface r2-eth1
ip address 192.168.2.2/24
!

View File

@ -1,14 +0,0 @@
router bgp 65003
no bgp ebgp-requires-policy
neighbor 192.0.2.2 remote-as 65002
neighbor 192.0.2.2 timers 1 3
neighbor 192.0.2.2 timers connect 1
neighbor 192.0.2.2 ebgp-multihop 3
neighbor 192.0.2.2 update-source 192.0.2.3
address-family ipv4 unicast
no neighbor 192.0.2.2 activate
exit-address-family
address-family link-state link-state
neighbor 192.0.2.2 activate
exit-address-family
!

View File

@ -1 +0,0 @@
../r2/linkstate.json

View File

@ -1 +0,0 @@
ip route 192.0.2.2/32 192.168.2.2

View File

@ -1,7 +0,0 @@
!
int lo
ip address 192.0.2.3/32
!
interface r3-eth0
ip address 192.168.2.3/24
!

View File

@ -1,113 +0,0 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
# Copyright 2023 6WIND S.A.
import os
import sys
import json
import pytest
import functools
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.common_config import step
from lib.topolog import logger
pytestmark = [pytest.mark.bgpd]
def build_topo(tgen):
for routern in range(1, 4):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
def setup_module(mod):
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
)
if rname == "r1":
# use bgp_injector.py to inject BGP prefixes
continue
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.start_router()
r1_path = os.path.join(CWD, "r1")
log_dir = os.path.join(tgen.logdir, "r1")
tgen.gears["r1"].cmd("chmod u+x {}/bgp_injector.py".format(r1_path))
tgen.gears["r1"].run("{}/bgp_injector.py {}".format(r1_path, log_dir))
def teardown_module(mod):
tgen = get_topogen()
log_dir = os.path.join(tgen.logdir, "r1")
pid_file = os.path.join(log_dir, "bgp_injector.pid")
logger.info("r1: sending SIGTERM to bgp_injector")
tgen.gears["r1"].cmd("kill $(cat {})".format(pid_file))
tgen.stop_topology()
def test_show_bgp_link_state():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
def _remove_prefixlen(tmp_json):
new_json = {
prefix.split("}/")[0] + "}/XX": data
for prefix, data in tmp_json["routes"].items()
}
return new_json
def _show_bgp_link_state_json(rname, tmp_expected):
tmp_output = json.loads(
tgen.gears[rname].vtysh_cmd("show bgp link-state link-state json")
)
# prefix length is the size of prefix in memory
# which differs on 32 and 64 bits.
# do not compare the prefix length
output = _remove_prefixlen(tmp_output)
expected = _remove_prefixlen(tmp_expected)
return topotest.json_cmp(output, expected)
step("Check BGP Link-State tables")
for rname in ["r2", "r3"]:
expected = open(os.path.join(CWD, "{}/linkstate.json".format(rname))).read()
expected_json = json.loads(expected)
test_func = functools.partial(_show_bgp_link_state_json, rname, expected_json)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to see BGP prefixes on {}".format(rname)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))