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

Various pitfalls when trying to use complex BGP filters #107

Open
tkern0 opened this issue May 7, 2021 · 0 comments
Open

Various pitfalls when trying to use complex BGP filters #107

tkern0 opened this issue May 7, 2021 · 0 comments

Comments

@tkern0
Copy link

tkern0 commented May 7, 2021

So I want to write something like the following to the bgpd config (with a more complex prefix list in practice):

router bgp 200
    ...
    address-family ipv4 unicast
        neighbor 192.168.100.1 route-map r1-ipv4-in in
...

ip prefix-list inbound-filter deny 192.168.0.0/16 ge 16
ip prefix-list inbound-filter permit 0.0.0.0/0 le 32

route-map r1-ipv4-in permit 10
    match ip address prefix-list inbound-filter
!

I ran into a number of pitfalls trying to do this, though I did eventually get something working. I figure it's good to list these anyway, even if only as a resource to point other to.

Summary:

  1. Prefix lists are always permit, there's no way to add a deny entry, use a deny route map instead
  2. You can only properly pass the filter functions a single prefix list, even though they allegedly take a tuple
  3. You can't give multiple prefix lists the same name
  4. The order does not autoincrement between filtering calls which using the same route map name (i.e. the autogenerated one)
  5. If you have multiple different route map names all going the same direction, only the last one (including the autogenerated defaults) gets applied

Examples

        r2.get_config(BGP).permit(from_peer=r1, matching=(
            PrefixList(name="inbound-filter", family="ipv4", entries=(
                PrefixListEntry("192.168.1.0/24", ge=24),
                PrefixListEntry("192.168.2.0/24", ge=24),
            )),
            PrefixList(name="inbound-filter", family="ipv4", entries=(
                PrefixListEntry("192.168.3.0/24", ge=24),
            )),
            PrefixList(name="inbound-filter-2", family="ipv4", entries=(
                PrefixListEntry("192.168.4.0/24", ge=24),
            )),
        ))

This generates the following (ignoring the default prefix lists/route maps):

ip prefix-list inbound-filter permit 192.168.1.0/24  ge 24
ip prefix-list inbound-filter permit 192.168.2.0/24  ge 24
ip prefix-list inbound-filter-2 permit 192.168.4.0/24  ge 24

route-map r1-ipv4-in permit 10
   match ip address prefix-list inbound-filter
   match ip address prefix-list inbound-filter
   match ip address prefix-list inbound-filter-2
!

Firstly, trying to write the same prefix list twice results in only the first being written. This is kind of a "don't do that then" situation, but figured it's worth noting, I accidentally ran into when I forgot entries was a tuple. The first inbound-filter prefix list is written to file perfectly fine however. The other thing worth noting here is that it adds every prefix list as it's own match statement to the route map, when bgpd only accepts the last.

r2# show route-map r1-ipv4-in
BGP:
route-map: r1-ipv4-in Invoked: 0 Optimization: enabled Processed Change: false
 permit, sequence 10 Invoked 0
  Match clauses:
    ip address prefix-list inbound-filter-2
  Set clauses:

This is the same sort of "don't do that then" type situation, but again it's something I blindly ran into.

Now trying to add a deny entry:
Generates:

        r2.get_config(BGP).permit(from_peer=r1, matching=(
            PrefixList(name="inbound-filter-permit", family="ipv4", entries=(
                PrefixListEntry("192.168.1.0/24", ge=24),
                PrefixListEntry("192.168.2.0/24", ge=24),
            )),
        ))
        r2.get_config(BGP).deny(from_peer=r1, matching=(
            PrefixList(name="inbound-filter-deny", family="ipv4", entries=(
                PrefixListEntry("192.168.3.0/24", ge=24),
            )),
        ))
ip prefix-list inbound-filter-permit permit 192.168.1.0/24  ge 24
ip prefix-list inbound-filter-permit permit 192.168.2.0/24  ge 24
ip prefix-list inbound-filter-deny permit 192.168.3.0/24  ge 24

route-map r1-ipv4-in deny 10
    match ip address prefix-list inbound-filter-deny
!

Because neither filter explicitly specified a name, they both got the same autogenerated one, and neither explicitly specified an order so they they both used the same default one. In this case only the last call is added to the route map.

Another issue you see in this case is that the deny only applies to the route map - there's no way for a prefix list to get a deny entry.

Giving both filters names leads to another interesting situation.

    address-family ipv4 unicast
        neighbor 192.168.100.1 route-map inbound-permit in
        neighbor 192.168.100.1 route-map inbound-deny in
        neighbor 192.168.100.1 route-map r1-ipv4-in in
...

ip prefix-list inbound-filter permit 192.168.1.0/24  ge 24
ip prefix-list inbound-filter permit 192.168.2.0/24  ge 24
ip prefix-list hello-world-v4 permit 0.0.0.0/0 le 32 

route-map inbound-permit permit 10
    match ip address prefix-list inbound-filter
!
!
route-map inbound-deny deny 10
    match ip address prefix-list inbound-filter
!
!
route-map r1-ipv4-in permit 65535
    match ip address prefix-list hello-world-v4
!

Each different name gets added to the file separately as it's own route map, and it tries to apply all of them to the neighbor. Bgpd again only uses the last one however - the default in this case.

If we go back to the autogenerated name, but use different orders, we get closest to what I initially wanted.

        r2.get_config(BGP).permit(order=10, from_peer=r1, matching=(
            PrefixList(name="inbound-filter-permit", family="ipv4", entries=(
                PrefixListEntry("192.168.1.0/24", ge=24),
                PrefixListEntry("192.168.2.0/24", ge=24),
            )),
        ))
        r2.get_config(BGP).deny(order=15, from_peer=r1, matching=(
            PrefixList(name="inbound-filter-deny", family="ipv4", entries=(
                PrefixListEntry("192.168.3.0/24", ge=24),
            )),
        ))
ip prefix-list inbound-filter-permit permit 192.168.1.0/24  ge 24
ip prefix-list inbound-filter-permit permit 192.168.2.0/24  ge 24
ip prefix-list inbound-filter-deny permit 192.168.3.0/24  ge 24

route-map r1-ipv4-in permit 10
    match ip address prefix-list inbound-filter-permit
!
route-map r1-ipv4-in deny 15
    match ip address prefix-list inbound-filter-deny
!

Adapting this eventually led me to the behavior I wanted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant