Skip to content

Commit

Permalink
✨ Feat(open.py): add support for construct the type 5 capability in B…
Browse files Browse the repository at this point in the history
…GP OPEN Message
  • Loading branch information
yuangezhizao committed Feb 26, 2024
1 parent 15c52e1 commit 53b8f7e
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 4 deletions.
31 changes: 27 additions & 4 deletions yabgp/message/open.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ def parse(self, message):
# (7) enhanced route refresh
elif capability.capa_code == capability.ENHANCED_ROUTE_REFRESH:
self.capa_dict['enhanced_route_refresh'] = True

# (8) add path
elif capability.capa_code == capability.ADD_PATH:
# could be more than one add path cap for different afi safi
Expand All @@ -180,6 +181,7 @@ def parse(self, message):
}
)
capability.capa_value = capability.capa_value[4:]

# (9) Long-Lived Graceful Restart (LLGR) Capability
elif capability.capa_code == capability.LLGR:
self.capa_dict['LLGR'] = []
Expand All @@ -191,6 +193,8 @@ def parse(self, message):
'time': time
})
capability.capa_value = capability.capa_value[7:]

# (10) Extended Next Hop Encoding Capability
elif capability.capa_code == capability.EXTENDED_NEXT_HOP:
self.capa_dict['ext_nexthop'] = []
while len(capability.capa_value) > 0:
Expand Down Expand Up @@ -225,9 +229,7 @@ def construct_header(msg):
# Maker | Length | Type | msg |
#---------------+--------+---------+------+
"""
return b'\xff'*16 + struct.pack('!HB',
len(msg) + 19,
1) + msg
return b'\xff' * 16 + struct.pack('!HB', len(msg) + 19, 1) + msg

def construct(self, my_capability):

Expand All @@ -252,6 +254,11 @@ def construct(self, my_capability):
else:
if my_capability.get('four_bytes_as'):
capas += Capability(capa_code=65, capa_length=4, capa_value=self.asn).construct(my_capability)

if 'ext_nexthop' in my_capability:
# Extended Next Hop Encoding Capability
capas += Capability(capa_code=5, capa_length=0).construct(my_capability)

# for add path
if my_capability.get('add_path'):
capas += Capability(capa_code=69, capa_length=4, capa_value=my_capability['add_path']).construct()
Expand Down Expand Up @@ -345,7 +352,7 @@ class Capability(object):
MULTISESSION_BGP = 0x44 # [Appanna]
ADD_PATH = 0x45 # [draft-ietf-idr-add-paths]
ENHANCED_ROUTE_REFRESH = 0x46
LLGR = 0x47 # [draft-uttaro-idr-bgp-persistence]
LLGR = 0x47 # [draft-uttaro-idr-bgp-persistence]
# 70-127 Unassigned
CISCO_ROUTE_REFRESH = 0x80 # I Can only find reference to this in the router logs
# 128-255 Reserved for Private Use [RFC5492]
Expand Down Expand Up @@ -418,6 +425,22 @@ def construct(self, my_capability=None):
'!BBBBHBB', 2, 6, self.ADD_PATH, self.capa_length, afi_safi[0], afi_safi[1], value)
return add_path

# (10) Extended Next Hop Encoding Capability
elif self.capa_code == self.EXTENDED_NEXT_HOP:
ext_nexthop_value = b''
# 1. Value
for each_ext_nexthop in my_capability['ext_nexthop']:
afi, safi = each_ext_nexthop['afi_safi']
nhafi = each_ext_nexthop['nexthop_afi']
ext_nexthop_value += struct.pack('!HHH', afi, safi, nhafi)

# 2. Header
ext_nexthop_value_length = len(ext_nexthop_value)
capability_and_ext_nexthtop_header = struct.pack('!BBBB', 2, ext_nexthop_value_length + 1 + 1,
self.EXTENDED_NEXT_HOP, ext_nexthop_value_length)
ext_nexthop = capability_and_ext_nexthtop_header + ext_nexthop_value
return ext_nexthop

elif self.capa_code == self.ENHANCED_ROUTE_REFRESH:
return struct.pack('!BBBB', 2, 2, self.ENHANCED_ROUTE_REFRESH, 0)

Expand Down
64 changes: 64 additions & 0 deletions yabgp/tests/unit/message/test_open.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,70 @@ def test_parse_add_path_llgr(self):
}
self.assertEqual(results, self.open.parse(msg_hex[HDR_LEN:]))

def test_parse_ext_nexthop(self):
"""
:return:
"""
real_msg_hex = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00S\x01' \
b'\x04\xfd\xe8\x00\xb4\x01\x01\x01\x016\x02\x06\x01\x04\x00\x01\x00\x01\x02' \
b'\x06\x01\x04\x00\x01\x00\x85\x02\x02\x80\x00\x02\x02\x02\x00\x02\x06A\x04' \
b'\x00\x00\xfd\xe8\x02\x14\x05\x12\x00\x01\x00\x01\x00\x02\x00\x01\x00\x02' \
b'\x00\x02\x00\x01\x00\x80\x00\x02'
open_msg = self.open.parse(real_msg_hex[HDR_LEN:])
results = {
'version': 4,
'asn': 65000,
'hold_time': 180,
'bgp_id': '1.1.1.1',
'capabilities': {
'afi_safi': [
(1, 1),
(1, 133)
],
'cisco_route_refresh': True,
'route_refresh': True,
'four_bytes_as': True,
'ext_nexthop': [
{'afi_safi': [1, 1], 'nexthop_afi': 2},
{'afi_safi': [1, 2], 'nexthop_afi': 2},
{'afi_safi': [1, 128], 'nexthop_afi': 2}
]
}
}
self.assertEqual(results, open_msg)

def test_construct_ext_nexthop(self):
"""
:return:
"""
self.open.version = VERSION
self.open.asn = 65000
self.open.hold_time = 180
self.open.bgp_id = int(netaddr.IPAddress('1.1.1.1'))
my_capabilities = {
'afi_safi': [
(1, 1),
(1, 133)
],
'cisco_route_refresh': True,
'route_refresh': True,
'four_bytes_as': True,
'ext_nexthop': [
{'afi_safi': [1, 1], 'nexthop_afi': 2},
{'afi_safi': [1, 2], 'nexthop_afi': 2},
{'afi_safi': [1, 128], 'nexthop_afi': 2}
]
}
msg_hex = self.open.construct(my_capabilities)
hope_hex = b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00S\x01' \
b'\x04\xfd\xe8\x00\xb4\x01\x01\x01\x016\x02\x06\x01\x04\x00\x01\x00\x01\x02' \
b'\x06\x01\x04\x00\x01\x00\x85\x02\x02\x80\x00\x02\x02\x02\x00\x02\x06A\x04' \
b'\x00\x00\xfd\xe8\x02\x14\x05\x12\x00\x01\x00\x01\x00\x02\x00\x01\x00\x02' \
b'\x00\x02\x00\x01\x00\x80\x00\x02'
self.assertEqual(hope_hex, msg_hex)


if __name__ == '__main__':
unittest.main()

0 comments on commit 53b8f7e

Please sign in to comment.