16-bit BGP Community Architecture
There are a lot of reasons a network engineer might use a 16-bit BGP community tag in an enterprise environment. It can be forced from pre-existing constraints and overcoming technical debt while still giving the opportunity for managing and propagating routing information at scale. Or you just want a compact way to assign and manipulate routes. The first 16-bits available within the full 32-bit field might currently be strictly assigned to each AS and must stay in place as a legacy system. Whatever the reasons, I came up with this methodology as a thought process to better understand compact BGP community architecture.
BGP communities provide a mechanism to tag and group routes with metadata that facilitates streamlined routing policies and efficient traffic engineering. Gone are the days of manually filtering routes based on actual subnets over a long chain of routers to propagate new routes. This is a strong but dangerous tool. If your architecture is set to advertise certain communities it would be easy for widespread impact to happen very quickly. While extended BGP communities offer additional flexibility, the 16-bit standard community remains relevant for backward compatibility or hardware limitations.
Standard BGP communities, as defined in RFC 1997, are 32-bit values used to tag routes. These values are typically represented in a decimal:decimal format, such as 64512:100
, where the first part usually corresponds to an Autonomous System Number (ASN) and the second part is a custom identifier. The 16-bit section could range from a defined value of 0 all the way to 65,535. Standard communities are widely supported across BGP implementations and are frequently used for purposes like route tagging, filtering, and marking routes for specific treatment. Their simplicity and broad adoption make them an effective tool for basic routing policies. Standard communities also include well-known values such as NO_EXPORT
(65535:65281), which prevents a route from being advertised to external peers, and NO_ADVERTISE
(65535:65282), which stops the route from being advertised to any BGP peer.
Extended BGP communities, introduced later in RFC 4360, expand on the capabilities of standard communities by using a 64-bit format. These communities include additional fields that allow for more complex tagging, enabling operators to encode information such as route target attributes, route origin, or specific traffic engineering requirements. Extended communities have a defined structure with fields for type and sub-type information, which determine how the community should be interpreted. For example, extended communities can be used in Multi-Protocol Label Switching (MPLS) Virtual Private Networks (VPNs) to control the scope of route propagation within a VPN. Values in extended communities are often represented as hexadecimal or in a similar “ASN:value” format, depending on the context.
Not every situation allows for the deployment of 64-bit BGP communities so it is interesting to explore the capacity within 16-bit communities. Using the below categorizations you could easily accommodate for a wide variety of enterprise network designations while staying within 16 bits.
Bits | Field | Description |
---|---|---|
5 | Origin Type | 0–31 (internal, external, upstream, etc) |
5 | Route Role | 0–31 (production, backup, etc) |
6 | Scope or Custom | 0–63 (global, regional, local, etc) |
This layout allows 32 values for Origin Type and Route Role, and 64 values for Scope, providing sufficient granularity for most enterprise needs. The assignments could also be moved around if greater capability was needed in a specific category compared to others.
Origin Type (5 bits):
0
: Internal (data centers, branches, etc).1
: Upstream providers (ISPs, etc).2
: Peering routes (IXPs, etc).3
: Cloud provider routes.- … up to
31
.
Route Role (5 bits):
0
: Production traffic.1
: Backup routes.2
: Management traffic.3
: Test/lab environments.- … up to
31
.
Scope (6 bits):
0
: Global (advertised broadly).1
: Regional (advertised within a region).2
: Local (specific to a branch or device).3
: Internet-bound.4
: Enterprise-only.- … up to
63
.
Based on the possible values in these 3 categories, you can create compact community values that stay in the 16 bit capacity. Some examples might include:
Community Value (Decimal) | Binary | Meaning |
---|---|---|
1000 | 00001 00001 000000 | External route, production, global. |
2001 | 00010 00000 000001 | Peering route, backup, regional. |
3072 | 00011 00000 010000 | Cloud route, production, local. |
It might make more sense if we use some practical implementations to filter routes for various needs. But first you’ll need to be aware of how the bits are referred to as they show from left to right. Bit 15 is the most left bit in a 16-bit field. In the context of a binary number, bit numbering typically starts from the leftmost (most significant bit, MSB) and moves to the rightmost (least significant bit, LSB). Here is how the bit positions are numbered in a 16-bit binary field:
Bits: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
| | | | | | | | | | | | | | | |
Binary: 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
To block all routes from origin type 1
(Upstream Providers), match communities where bits 15–11 encode the value of 1
in binary. Translating to decimal the minimum possible value would be 00001 00000 000000
(32) where the maximum would be 00001 11111 111111
(63). We can use that decimal range to craft appropriate regex that captures that range.
policy-options {
community upstream-providers {
members "^.*:((3[2-9])|([4-5][0-9])|(6[0-3]))$";
}
policy-statement block-upstream {
term block {
from community upstream-providers;
then reject;
}
}
}
Crafting a filter for other values of the origin type category would include variations on the binary and decimal value. For 0
the binary would be 00000xxxxx xxxxxx
with a decimal range of 0-31. Type 2
would be 00010xxxxx xxxxxx
with the decimal range of 64-95. Type 3
would be 00011xxxxx xxxxxx
with a range of 96-127.
To allow routes marked as route role 0
(Production Traffic), match communities where bits 10–6 are 0
in binary. This would be a decimal sequence from 0 to 2016. Not really clean and compact but it accomplishes the original goal.
policy-options {
community production-traffic {
members "^.*:(0|32|64|96|128|160|192|224|256|288|320|352|384|416|448|480|512|544|576|608|640|672|704|736|768|800|832|864|896|928|960|992|1024|1056|1088|1120|1152|1184|1216|1248|1280|1312|1344|1376|1408|1440|1472|1504|1536|1568|1600|1632|1664|1696|1728|1760|1792|1824|1856|1888|1920|1952|1984|2016)$";
}
policy-statement allow-production {
term allow {
from community production-traffic;
then accept;
}
}
}
To block any route not scoped for enterprise only traffic with scope 4
, match communities where bits 5–0 are not 4 in binary.
policy-options {
community non-enterprise-routes {
members "^(?!.*4$).*$";
}
policy-statement block-non-enterprise {
term block {
from community non-enterprise-routes;
then reject;
}
}
}
For routes originating from the cloud and that are also backup, match origin type 3 and route role 1.
policy-options {
community cloud-backup {
members "^.*:((3[2-9]|[4-5][0-9]){1})$";
}
policy-statement permit-cloud-backup {
term allow {
from community cloud-backup;
then accept;
}
}
}