Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Extended Next Hop Encoding Capability (Type 5) #165

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions yabgp/common/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,20 @@
NEW_ROUTE_REFRESH = False
GRACEFUL_RESTART = False

# AFI_SAFI mapping
# AFI mapping
AFI_DICT = {
1: 'ipv4',
2: 'ipv6'
}
AFI_STR_DICT = {
'ipv4': 1,
'ipv6': 2
}

# AFI_SAFI mapping
AFI_SAFI_DICT = {
(1, 1): 'ipv4',
(1, 2): 'ipv4_mcast',
(2, 1): 'ipv6',
(1, 4): 'ipv4_lu',
(2, 4): 'ipv6_lu',
Expand All @@ -328,8 +338,9 @@
(2, 133): 'ipv6_flowspec'
}
AFI_SAFI_STR_DICT = {
'ipv6': (2, 1),
'ipv4': (1, 1),
'ipv4_mcast': (1, 2),
'ipv6': (2, 1),
'ipv4_lu': (1, 4),
'ipv6_lu': (2, 4),
'flowspec': (1, 133),
Expand Down
22 changes: 19 additions & 3 deletions yabgp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@

from oslo_config import cfg

CONF = cfg.CONF
from yabgp.common.constants import AFI_SAFI_STR_DICT
from yabgp.common.constants import AFI_STR_DICT

CONF = cfg.CONF

BGP_CONFIG_OPTS = [
cfg.IntOpt('peer_start_interval',
Expand Down Expand Up @@ -50,7 +52,10 @@
help='if support cisco multi session'),
cfg.DictOpt('running_config',
default={},
help='The running configuration for BGP')
help='The running configuration for BGP'),
cfg.ListOpt('ext_nexthop',
default=[['ipv4', 'ipv6'], ['ipv4_mcast', 'ipv6'], ['vpnv4', 'ipv6']],
help='The ext_nexthop for BGP')
]

CONF.register_opts(BGP_CONFIG_OPTS, group='bgp')
Expand Down Expand Up @@ -129,10 +134,21 @@ def get_bgp_config():
'enhanced_route_refresh': CONF.bgp.enhanced_route_refresh,
'graceful_restart': CONF.bgp.graceful_restart,
'cisco_multi_session': CONF.bgp.cisco_multi_session,
'add_path': CONF.bgp.add_path},
'add_path': CONF.bgp.add_path
},
'remote': {}
}
}
if ('vpnv4' in CONF.bgp.afi_safi) or ('vpnv6' in CONF.bgp.afi_safi):
ext_nexthop_from_cli = CONF.bgp.ext_nexthop
ext_nexthop = []
for each in ext_nexthop_from_cli:
afi_safi, nexthop_afi = each
ext_nexthop.append({
'afi_safi': AFI_SAFI_STR_DICT[afi_safi],
'nexthop_afi': AFI_STR_DICT[nexthop_afi]
})
CONF.bgp.running_config['capability']['local']['ext_nexthop'] = ext_nexthop
else:
LOG.error('Please provide enough parameters!')
sys.exit()
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()
Loading