From fb4903139486b6cd396c56f7076120c8960b583b Mon Sep 17 00:00:00 2001 From: Thomas Mangin Date: Wed, 29 Mar 2023 16:22:33 +0100 Subject: [PATCH] add path-info parsing to announce attributes #1147 --- etc/exabgp/api-attributes-path.conf | 26 ++++++++++++++++++++ etc/exabgp/run/api-attributes-path.run | 26 ++++++++++++++++++++ qa/ci/api-attributes-path.ci | 1 + qa/ci/api-attributes-path.msg | 4 +++ src/exabgp/application/decode.py | 27 +++++++++------------ src/exabgp/configuration/static/__init__.py | 13 ++++++++++ 6 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 etc/exabgp/api-attributes-path.conf create mode 100755 etc/exabgp/run/api-attributes-path.run create mode 100644 qa/ci/api-attributes-path.ci create mode 100644 qa/ci/api-attributes-path.msg diff --git a/etc/exabgp/api-attributes-path.conf b/etc/exabgp/api-attributes-path.conf new file mode 100644 index 000000000..deaca91b9 --- /dev/null +++ b/etc/exabgp/api-attributes-path.conf @@ -0,0 +1,26 @@ +process announce-routes { + run ./run/api-attributes-path.run; + encoder text; +} + +neighbor 127.0.0.1 { + router-id 1.2.3.4; + local-address 127.0.0.1; + local-as 300; + peer-as 300; + + family { + ipv4 unicast; + ipv6 unicast; + } + + capability { + add-path send/receive; + route-refresh; + } + + api { + processes [ announce-routes ]; + neighbor-changes; + } +} diff --git a/etc/exabgp/run/api-attributes-path.run b/etc/exabgp/run/api-attributes-path.run new file mode 100755 index 000000000..956607b61 --- /dev/null +++ b/etc/exabgp/run/api-attributes-path.run @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 + +import os +import sys +import time + +messages = [ + 'neighbor 127.0.0.1 announce attributes path-information 1.2.3.4 next-hop 10.11.12.13 community [14:15] local-preference 16 nlri 16.17.18.19/32 20.21.22.23/32', + 'neighbor 127.0.0.1 announce attributes path-information 4.3.2.1 next-hop 10.11.12.13 community [14:15] local-preference 16 nlri 16.17.18.19/32 20.21.22.23/32', +] + +while messages: + message = messages.pop(0) + sys.stdout.write(message + '\n') + sys.stdout.flush() + time.sleep(0.3) + +try: + now = time.time() + while os.getppid() != 1 and time.time() < now + 5: + line = sys.stdin.readline().strip() + if not line or 'shutdown' in line: + break + time.sleep(1) +except IOError: + pass diff --git a/qa/ci/api-attributes-path.ci b/qa/ci/api-attributes-path.ci new file mode 100644 index 000000000..1f6840f51 --- /dev/null +++ b/qa/ci/api-attributes-path.ci @@ -0,0 +1 @@ +api-attributes-path.conf diff --git a/qa/ci/api-attributes-path.msg b/qa/ci/api-attributes-path.msg new file mode 100644 index 000000000..891830b52 --- /dev/null +++ b/qa/ci/api-attributes-path.msg @@ -0,0 +1,4 @@ +1:raw:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001702:00000000 +1:raw:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:001E:02:00000007900F0003000201 +1:raw:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0045:02:0000001C400101004002004003040A0B0C0D40050400000010C00804000E000F010203042010111213010203042014151617 +1:raw:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:0045:02:0000001C400101004002004003040A0B0C0D40050400000010C00804000E000F040302012010111213040302012014151617 \ No newline at end of file diff --git a/src/exabgp/application/decode.py b/src/exabgp/application/decode.py index ed65a0943..6a40df14e 100644 --- a/src/exabgp/application/decode.py +++ b/src/exabgp/application/decode.py @@ -16,7 +16,7 @@ from exabgp.logger import log -conf_all = """\ +conf_template = """\ neighbor 127.0.0.1 { router-id 10.0.0.2; local-address 127.0.0.1; @@ -24,20 +24,11 @@ peer-as 65533; family { - all; + [families]; } -} -""" -conf_none = """\ -neighbor 127.0.0.1 { - router-id 10.0.0.2; - local-address 127.0.0.1; - local-as 65533; - peer-as 65533; - - family { - [families]; + capability { + [path-information] } } """ @@ -54,7 +45,8 @@ def setargs(sub): sub.add_argument('-d', '--debug', help='start the python debugger errors', action='store_true') sub.add_argument('-p', '--pdb', help='fire the debugger on fault', action='store_true') sub.add_argument('-c', '--configuration', help='configuration file(s)', type=str) - sub.add_argument('-f', '--family', help='family expected', type=str) + sub.add_argument('-f', '--family', help='family expected (format like "ipv4 unicast")', type=str) + sub.add_argument('-i', '--path-information', help='decode path-information', action='store_true') sub.add_argument('payload', help='the BGP payload in hexadecimal', type=str) # fmt:on @@ -97,6 +89,8 @@ def cmdline(cmdarg): log.init(env) trace_interceptor(env.debug.pdb) + conf = conf_template.replace('[path-information]', 'add-path send/receive;' if cmdarg.path_information else '') + sanitized = ''.join(cmdarg.payload).replace(':', '').replace(' ', '') if cmdarg.configuration: configuration = Configuration([getconf(cmdarg.configuration)]) @@ -109,11 +103,12 @@ def cmdline(cmdarg): sys.exit(1) families_pair = [families[n : n + 2] for n in range(0, len(families), 2)] families_text = ';'.join([f'{a} {s}' for a, s in families_pair]) - conf = conf_none.replace('[families]', families_text) + conf = conf.replace('[families]', families_text) configuration = Configuration([conf], text=True) else: - configuration = Configuration([conf_all], text=True) + conf = conf.replace('[families]', 'all') + configuration = Configuration([conf], text=True) valid_nlri = Reactor(configuration).display(sanitized, cmdarg.nlri) if valid_nlri: diff --git a/src/exabgp/configuration/static/__init__.py b/src/exabgp/configuration/static/__init__.py index 4bed2c03c..7ded2f229 100644 --- a/src/exabgp/configuration/static/__init__.py +++ b/src/exabgp/configuration/static/__init__.py @@ -29,6 +29,7 @@ from exabgp.configuration.static.mpls import label from exabgp.configuration.static.mpls import route_distinguisher +from exabgp.configuration.static.parser import path_information def _check_true(change, afi): @@ -89,6 +90,10 @@ def route(tokeniser): nlri.rd = route_distinguisher(tokeniser) continue + if command == 'path-information': + nlri.path_info = path_information(tokeniser) + continue + action = ParseStatic.action.get(command, '') if action == 'attribute-add': @@ -126,6 +131,7 @@ def attributes(tokeniser): labels = None rd = None + path = None while True: command = tokeniser() @@ -140,6 +146,10 @@ def attributes(tokeniser): labels = label(tokeniser) continue + if command == 'path-information': + path = path_information(tokeniser) + continue + if command == 'rd' or command == 'route-distinguisher': rd = route_distinguisher(tokeniser) continue @@ -160,6 +170,7 @@ def attributes(tokeniser): raise ValueError('unknown command "%s"' % command) changes = [] + while True: peeked_nlri = tokeniser.peek() if not peeked_nlri: @@ -172,6 +183,8 @@ def attributes(tokeniser): new.nlri.labels = labels if rd: new.nlri.rd = rd + if path: + new.nlri.path_info = path new.nlri.nexthop = nlri.nexthop changes.append(new)