One of the things that I hated most (amongst other things) about BGP was regular expressions. I never used to get those things right: Filter out routes that originated from AS 65000, blah blah. However, when I started reading about BGP again, I found a very interesting and helpful article written by Brian McGahan on understanding BGP regular expressions. You can find the article here. What I want to do in this article is to build on his article with scenarios using GNS3.

Our network diagram for this article is as shown below:

Before we can begin writing regular expressions (regex), we need to first familiarize ourselves with the various regex characters used in Cisco IOS, which can be found here. A watered-down version of the table is as shown below:

Regex character Meaning
^ Start of input string
$ End of input string
[] Listed characters or a range of characters
– (hyphen) Used to specify a range of characters
. Any single character
* 0 or more instances of a character
+ 1 or more instances of a character
? 0 or 1 instance of a character
_ (underscore) Comma, (, ), {, }, ^, $, space

In BGP, one of the filtering methods we can use is AS_PATH filtering, i.e., filtering by AS numbers. Please refer to this previous article to remind yourself about what the AS_PATH attribute is and how it is used.

I have configured BGP on all the routers in our topology and the BGP peering sessions have formed. Now let’s begin with our regular expression configuration by considering commonly used regular expressions.

Note: The GNS3 topology and configuration files are attached to this article.

Example #1: Send only locally originated routes to neighbor

In this first example, we want R1 to send only locally originated routes – routes that were originated in its AS—to its EBGP neighbor, which is R3. One reason to do this is so that your AS is not used as a transit AS. For example, notice below that R3 is learning about (originated by R4) through both R4 and R1.

Even though the path through R4 is currently the best path, R3 will use the path through R1 when the one through R4 goes down. Imagine if R3 and R4 were your ISPs: You definitely don’t want ISP traffic using your AS for transit traffic.

To achieve this, we will apply an AS_PATH filter on R1 for neighbor R3, allowing only locally originated routes.

Note: In a real-life scenario, you will probably also apply the same type of filter on R2 for its neighbor R4.

How do we recognize locally originated routes? It’s that they have an empty AS_PATH attribute. Notice that and do not have any AS number under the Path column – the “i” is an origin code of IGP since I used the network statement to advertise those routes into BGP.

Therefore, to match locally originated routes, the regular expression will simply be (without the quotes) “^$”. This matches the start of the string immediately followed by the end of the string, i.e., empty.

One cool thing is that we can test this regular expression before applying it using the show ip bgp regexp
command. This command will show you what routes in your BGP table match the regex you specified. As you can see, when we use the ^$ regex on R1, it matches only and

We can now go ahead to apply our regular expression. First, we need to define our regex using an AS_PATH access list. This can be achieved using the ip as-path access-list command.

The AS_PATH access list also has the implicit deny any rule at the end of the access list, just like any normal ACL. Now, I can apply this AS_PATH access list to the neighbor under the BGP process using the neighbor filter-list command.

Hint: We can also match the AS_PATH access list in a route map and then apply the route map to the neighbor.

When we check R3 now, you will see that the path through R1 is no more in the BGP table; only the path through R4 is there.

Example #2: Accept routes originated in a particular AS

The second example we will consider is where we want R3 to accept only routes that were originated in AS1 from R4. What this means is that R3 will not learn any other routes except AS1 routes from R4, even routes originated in AS4 itself.

To configure this regular expression, you need to think about what happens to the AS_PATH when routes are advertised between ASs. For example, the route received from R2 has an AS_PATH of “1” in R4’s BGP table.

If R4 wants to advertise that route to R3, it will prepend its own AS number to the AS_PATH attribute before sending it to R3. Therefore, if we check the BGP table of R3, we will see the route has an AS_PATH of “4 1”.

Thus we can infer that the AS that originated a route will always be at the rightmost part in the AS_PATH attribute. Furthermore, if it was received from the AS that originated it, then it will not have another other AS numbers in the AS_PATH (as in the case of received from R2 by R4). Otherwise, if it was received from an AS other than the one that originated it, then it will have other AS numbers in the left portion (as in the case of received from R4 by R3).

Therefore, for our regex, we only care about the position of the originating AS and it has to be just before the end of the string, e.g., 1$. We don’t care about the leftmost portion, i.e., it could be a space (meaning there are other AS numbers in the left portion) or the start of the string (meaning there are no other AS numbers). The regex character to match space or start of string (^) is the underscore (_). Therefore the full form of our regex is “_1$”.

Note: Since we are considering only R3 and R4, assuming we wanted to apply the filter on R3, our regex could simply be “4 1”. However, this is restrictive. Imagine we have another AS connected to R3, say AS5: We can’t use the same filter “4 1” for the neighbor in AS5 because AS1 routes advertised to R3 from AS5 will have an AS_PATH of “5 1”.

To test our regex, let’s go to R3.

As you can see, the regex matches the routes originated in AS1 received from both R1 and R4. We can now apply our filter. Before the filter, notice that R3 is receiving the route from R4.

Note: We are not receiving this route from R1 because of our previous filter in example 1.

The configuration on R3 is as follows:

ip as-path access-list 1 permit _1$
router bgp 3
 neighbor filter-list 1 in

Notice that we are using the “in” keyword so that the filter applies to routes received from that neighbor. In example 1 we used “out” so that the filter affected routes sent to that neighbor.

Hint: You may have to clear (soft) the BGP session between R3 and R4 using the clear ip bgp <ip_addr> soft command for you to see the changes.

When we check the BGP table on R3 now, we will see that the route from R4 is no more there.

Example #3: Deny some, allow every other route

Let’s take this last example to wrap up this article. On R2, we want to accept all BGP routes from R4 except routes that originated in AS3. In the previous examples, we have been using only one entry in our AS_PATH access list; in this example, we will be using two entries—one permit and one deny.

We already know how to match routes that originated in a particular AS—refer to example 2. The other entry is to match every other route. The regex to match everything is “.*”, that is, “.” matches any single character and “*” matches zero or more instances of that character meaning zero or more instances of any character.

We can test this out. Compare the two outputs below and notice that there is no difference.

Our configuration on R2 thus becomes:

ip as-path access-list 1 deny _3$
ip as-path access-list 1 permit .*
router bgp 1
 neighbor filter-list 1 in

Before I apply this configuration, notice that R2 is receiving the route from R4 as highlighted below:

After I apply that configuration, notice now that R2 knows about the network only through R3 (via R1).


Let’s stop here for now. In the next article, we will look at more complex examples of BGP regular expressions. I hope you have found this article helpful and I look forward to presenting the next article in the series.

References and Further Reading

  1. Cisco IOS Terminal Services Configuration Guide, Release 12.2: Regular Expressions: