From e86ec9847f5ce3d99e8b7b10a56babdc0545d9e3 Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Tue, 11 Jun 2024 14:00:01 -0500 Subject: [PATCH 1/6] fix(community): pack asn in the community string as the gives the format the routers expect wrapping in a try/except because the max asn you can give by RFC is equivalent to uint32 which is the type of variable the community attribute is in gobgp. This means you can hand over a valid asn and community and end up overflowing it. --- translator/gobgp.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index cb547ae6..adb802a1 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -84,7 +84,11 @@ def _build_path(self, ip, event_data={}): # Set our community number communities = Any() - communities.Pack(attribute_pb2.CommunitiesAttribute(communities=[community])) + try: + comm_id = (asn << 16) + community + communities.Pack(attribute_pb2.CommunitiesAttribute(communities=[comm_id])) + except ValueError: + logging.warning(f"Community {comm_id} too large to use; please pick a smaller ASN and try again") attributes = [origin, next_hop, as_path, communities] From 32dd19baf529716791086ee08de122a67f467ec2 Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Tue, 11 Jun 2024 22:40:35 -0500 Subject: [PATCH 2/6] feat(large-communities): support large communities we need to accept an ASN in our community so we might as well allow for large communities in case someone needs that --- translator/gobgp.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index adb802a1..810625bf 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -83,12 +83,23 @@ def _build_path(self, ip, event_data={}): as_path.Pack(as_segments) # Set our community number + # Large community: attribute is a set of one or more 12-byte values, + # each of which is in the format of Global Administrator:LocalData1:LocalData2 + # + # global_admin = The Global Administrator field is intended to represent a complete 4-byte ASN + # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. + # + # Use local_data2 for any "flag" you want to send to the router that can be used for routing policy decisions. communities = Any() - try: - comm_id = (asn << 16) + community - communities.Pack(attribute_pb2.CommunitiesAttribute(communities=[comm_id])) - except ValueError: - logging.warning(f"Community {comm_id} too large to use; please pick a smaller ASN and try again") + global_admin = asn + local_data1 = community + local_data2 = 0 + large_community = attribute_pb2.LargeCommunity( + global_admin=global_admin, + local_data1=local_data1, + local_data2=local_data2, + ) + communities.Pack(attribute_pb2.LargeCommunitiesAttribute(communities=[large_community])) attributes = [origin, next_hop, as_path, communities] From b307f5355a50e61f840694f6b6bdfe2b8ee8471e Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Tue, 11 Jun 2024 22:40:55 -0500 Subject: [PATCH 3/6] docs(comments): update comment to be more readable --- translator/gobgp.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index 810625bf..7536ba8c 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -83,9 +83,6 @@ def _build_path(self, ip, event_data={}): as_path.Pack(as_segments) # Set our community number - # Large community: attribute is a set of one or more 12-byte values, - # each of which is in the format of Global Administrator:LocalData1:LocalData2 - # # global_admin = The Global Administrator field is intended to represent a complete 4-byte ASN # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. # From 887ad3177add8c0fc5e125d2ea2e3b1653c8de3d Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Wed, 12 Jun 2024 14:00:53 -0500 Subject: [PATCH 4/6] feat(communities): support both large and standard communities no need to rip out large community support, but also our routers will ignore announcements using them for now so make sure we can still use standard communities --- translator/gobgp.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index 7536ba8c..5cf1a0c3 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -83,20 +83,29 @@ def _build_path(self, ip, event_data={}): as_path.Pack(as_segments) # Set our community number - # global_admin = The Global Administrator field is intended to represent a complete 4-byte ASN - # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. - # - # Use local_data2 for any "flag" you want to send to the router that can be used for routing policy decisions. + # The ASN gets packed into the community so we need to be careful about size to not overflow the structure communities = Any() - global_admin = asn - local_data1 = community - local_data2 = 0 - large_community = attribute_pb2.LargeCommunity( - global_admin=global_admin, - local_data1=local_data1, - local_data2=local_data2, - ) - communities.Pack(attribute_pb2.LargeCommunitiesAttribute(communities=[large_community])) + # Standard community + # Since we pack both into the community string we need to make sure they will both fit + if asn < 65536 and community < 65536: + comm_id = (asn << 16) + community + communities.Pack(attribute_pb2.CommunitiesAttribute(communities=[comm_id])) + else: + # Large Community: 3 fields of 4 bytes version of a community string + # global_admin = The Global Administrator field is intended to represent a complete 4-byte ASN + # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. + # + # Use local_data2 for any "flag" you want to send to the router to be used for routing policy decisions. + logging.warning(f"LargeCommunity Used - ASN:{asn} Community: {community}") + global_admin = asn + local_data1 = community + local_data2 = 0 + large_community = attribute_pb2.LargeCommunity( + global_admin=global_admin, + local_data1=local_data1, + local_data2=local_data2, + ) + communities.Pack(attribute_pb2.LargeCommunitiesAttribute(communities=[large_community])) attributes = [origin, next_hop, as_path, communities] From 0ee43ef844d3da4e6be4a77cac4d9546a79a821b Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Thu, 13 Jun 2024 11:52:35 -0500 Subject: [PATCH 5/6] refactor(logging): log as info not warning we want people to know they used a large community, but there's no need to make it a warning --- translator/gobgp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index 5cf1a0c3..48ab41ac 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -96,7 +96,7 @@ def _build_path(self, ip, event_data={}): # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. # # Use local_data2 for any "flag" you want to send to the router to be used for routing policy decisions. - logging.warning(f"LargeCommunity Used - ASN:{asn} Community: {community}") + logging.info(f"LargeCommunity Used - ASN:{asn} Community: {community}") global_admin = asn local_data1 = community local_data2 = 0 From 9bcf273f6cb68b64b501913b8e736840aed04eab Mon Sep 17 00:00:00 2001 From: Sam Oehlert Date: Thu, 13 Jun 2024 11:58:03 -0500 Subject: [PATCH 6/6] docs(large-community): remove confusing large community comments shouldn't need to describe what a large community is if people are using it --- translator/gobgp.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/translator/gobgp.py b/translator/gobgp.py index 48ab41ac..fe0b679b 100644 --- a/translator/gobgp.py +++ b/translator/gobgp.py @@ -91,14 +91,10 @@ def _build_path(self, ip, event_data={}): comm_id = (asn << 16) + community communities.Pack(attribute_pb2.CommunitiesAttribute(communities=[comm_id])) else: - # Large Community: 3 fields of 4 bytes version of a community string - # global_admin = The Global Administrator field is intended to represent a complete 4-byte ASN - # local_data* is for more flexible routing policy. can be set to ME:ACTION:YOU or ASN:Function:Parameter. - # - # Use local_data2 for any "flag" you want to send to the router to be used for routing policy decisions. logging.info(f"LargeCommunity Used - ASN:{asn} Community: {community}") global_admin = asn local_data1 = community + # set to 0 because there's no use case for it, but we need a local_data2 for gobgp to read any of it local_data2 = 0 large_community = attribute_pb2.LargeCommunity( global_admin=global_admin,