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

use BPF_MAP_TYPE_LPM_TRIE for range matching #11526

Merged
merged 28 commits into from
Jun 10, 2022
Merged

Conversation

Y7n05h
Copy link
Contributor

@Y7n05h Y7n05h commented Apr 13, 2022

Short description

#9690

Checklist

I have:

  • read the CONTRIBUTING.md document
  • compiled this code
  • tested this code
  • included documentation (including possible behaviour changes)
  • documented the code
  • added or modified regression test(s)
  • added or modified unit test(s)
  • checked that this code was merged to master

@Y7n05h Y7n05h changed the title [WIP]using BPF_MAP_TYPE_LPM_TRIE for range matching [WIP]use BPF_MAP_TYPE_LPM_TRIE for range matching Apr 13, 2022
@Y7n05h
Copy link
Contributor Author

Y7n05h commented Apr 13, 2022

Like the size of the three maps specified in newBPFFilter, the size of the two newly added maps in blockRange also needs to be specified.
It may not be good practice to add two extra parameters to newBPFFilter to specify the size of the two maps.

@rgacogne
Copy link
Member

It may not be good practice to add two extra parameters to newBPFFilter to specify the size of the two maps.

It might be time to use a table-based approach for these parameters instead?

@Y7n05h
Copy link
Contributor Author

Y7n05h commented Apr 13, 2022

It might be time to use a table-based approach for these parameters instead?

Can you elaborate? I didn't understand what you meant.

@rgacogne
Copy link
Member

Can you elaborate? I didn't understand what you meant.

Yes, my bad, I should have included an example right away! If you take a look at, for example, setWebserverConfig https://dnsdist.org/reference/config.html#setWebserverConfig you will see that it takes a Lua associative table instead of a fixed number of parameters. That way we can be much more flexible in what we accept, and add parameters without breaking compatibility with existing configurations.
So I think we have two options for newBPFFilter, we can either:

  • add an additional, optional associative table after the existing parameters: newBPFFilter(v4Parameters, v6Parameters, qnamesParameters [, optionalTable])
  • or replace all parameters by a single associative table: newBPFFilter(table)

The second one is a lot cleaner but would break compatibility with existing configurations. I'm fine with doing that in 1.8.0 if needed.

@Y7n05h
Copy link
Contributor Author

Y7n05h commented Apr 13, 2022

Can you elaborate? I didn't understand what you meant.

Yes, my bad, I should have included an example right away! If you take a look at, for example, setWebserverConfig https://dnsdist.org/reference/config.html#setWebserverConfig you will see that it takes a Lua associative table instead of a fixed number of parameters. That way we can be much more flexible in what we accept, and add parameters without breaking compatibility with existing configurations. So I think we have two options for newBPFFilter, we can either:

  • add an additional, optional associative table after the existing parameters: newBPFFilter(v4Parameters, v6Parameters, qnamesParameters [, optionalTable])
  • or replace all parameters by a single associative table: newBPFFilter(table)

The second one is a lot cleaner but would break compatibility with existing configurations. I'm fine with doing that in 1.8.0 if needed.

I prefer the second one. Compatibility is necessary, but newBPFFilter has extended the 4th parameter in a similar way. It might not be nice to add new optional parameters after optional parameters.

If we add an optional table for newBPFFilter then newBPFFilter will become:

newBPFFilter(v4Parameters, v6Parameters, qnamesParameters [,external] [,optionalTable])

Or we could merge the 4th parameter with the 5th parameter, but this is also not consistent with the previous program. In this case, let's put all the parameters into the table.

@rgacogne
Copy link
Member

In this case, let's put all the parameters into the table.

Agreed, that seems to be the best option!

@Y7n05h
Copy link
Contributor Author

Y7n05h commented Apr 14, 2022

Why do we need use different types of value depending on format == MapFormat::Legacy. Why doesn't MapFormat::Legacy use CounterAndActionValue as value?

pdns/pdns/bpf-filter.cc

Lines 211 to 246 in 053a020

if (format == MapFormat::Legacy) {
switch (d_config.d_type) {
case MapType::IPv4:
keySize = sizeof(uint32_t);
valueSize = sizeof(uint64_t);
break;
case MapType::IPv6:
keySize = sizeof(KeyV6);
valueSize = sizeof(uint64_t);
break;
case MapType::QNames:
keySize = sizeof(QNameKey);
valueSize = sizeof(QNameValue);
break;
default:
throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
}
}
else {
switch (d_config.d_type) {
case MapType::IPv4:
keySize = sizeof(uint32_t);
valueSize = sizeof(CounterAndActionValue);
break;
case MapType::IPv6:
keySize = sizeof(KeyV6);
valueSize = sizeof(CounterAndActionValue);
break;
case MapType::QNames:
keySize = sizeof(QNameAndQTypeKey);
valueSize = sizeof(CounterAndActionValue);
break;
default:
throw std::runtime_error("Unsupported eBPF map type: " + std::to_string(static_cast<uint8_t>(d_config.d_type)));
}
}

@rgacogne
Copy link
Member

Why do we need use different types of value depending on format == MapFormat::Legacy. Why doesn't MapFormat::Legacy use CounterAndActionValue as value?

It's quite frustrating! It comes from the limitations on eBPF socket filter programs in older kernels, where the number of eBPF instructions was very limited, so I couldn't get a composite key based qname + qtype to work and had to use that weird construct where the key is the qname only. We could get rid of that on newer kernels, but that would mean that all of a sudden eBPF filtering would not work on older kernels, which I would like to avoid for a bit longer, at least until major distributions no longer support these kernel versions.
The non-legacy format does not care about that, in part because XDP requires a more recent kernel anyway but also because I'm OK with requiring a recent kernel for new features, as opposed to breaking existing features.
By the way, it means that we will need to be able to build on kernel where LPM trie support does not exist, but of course that feature will not be enabled then.

@Y7n05h Y7n05h marked this pull request as ready for review April 15, 2022 16:50
@Y7n05h Y7n05h changed the title [WIP]use BPF_MAP_TYPE_LPM_TRIE for range matching use BPF_MAP_TYPE_LPM_TRIE for range matching Apr 15, 2022
@rgacogne rgacogne self-requested a review April 21, 2022 07:42
Copy link
Member

@rgacogne rgacogne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really great work, thank you! I have made a few comments and I think there are a couple points we might have to change, but I'm very happy with that pull request 👍

pdns/bpf-filter.cc Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>

Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Y7n05h and others added 4 commits April 23, 2022 02:10
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Co-authored-by: Remi Gacogne <github@coredump.fr>
Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Co-authored-by: Remi Gacogne <github@coredump.fr>
@rgacogne
Copy link
Member

rgacogne commented May 5, 2022

I use linux-zen in ArchLinux.

Kernel version: 5.17.5-zen1-1-zen

I test d3d121d and b1419e5 by executing sudo python xdp.py . They work fine for me.

Thanks, that's very helpful! I'm using Arch's hardened kernel, I'll try with -zen.

Co-authored-by: Remi Gacogne <github@coredump.fr>

Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
@Y7n05h Y7n05h requested a review from rgacogne May 13, 2022 05:37
@rgacogne
Copy link
Member

I did not manage to make it work last time I tried, but I will take the time to test this properly this week.

@Y7n05h
Copy link
Contributor Author

Y7n05h commented Jun 1, 2022

I just tested xdp.py on the linux-zen 5.18.1.zen1-1 and linux 5.18.1.arch1-1 kernels of ArchLinux, respectively, and he works fine. But when testing on linux-hardened 5.17.12.gardened2-1, I encountered this error:

unknown func bpf_probe_read#4

I think this is a linux-hardened specific problem, probably related to the kernel configuration used by linux-hardened.

Copy link
Member

@rgacogne rgacogne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finally managed to test this properly, sorry again it took me so long.
The code is very good, and apart from a couple issues I added comments for it works pretty well. Thanks a lot!

pdns/bpf-filter.cc Show resolved Hide resolved
pdns/bpf-filter.hh Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Outdated Show resolved Hide resolved
pdns/bpf-filter.cc Show resolved Hide resolved
Y7n05h and others added 3 commits June 4, 2022 02:37
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
@Y7n05h Y7n05h requested a review from rgacogne June 4, 2022 05:33
bpf:rmRangeRule bpf:lsRangeRule

Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Copy link
Member

@rgacogne rgacogne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks very good, I made a few comments but my feeling is that is pull request is almost done, nice job!

pdns/bpf-filter.hh Outdated Show resolved Hide resolved
pdns/bpf-filter.hh Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
Y7n05h and others added 2 commits June 9, 2022 22:29
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
@rgacogne
Copy link
Member

rgacogne commented Jun 9, 2022

I missed it but there is a build error when we build without HAVE_EBPF:

bpf-filter.cc:922:32: error: use of undeclared identifier 'CounterAndActionValue'
  std::vector<std::pair<Netmask, CounterAndActionValue>> BPFFilter::getRangeRule(){
  depbase=`echo dnsdist-console.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
                                 ^
  bpf-filter.cc:924:10: error: no viable conversion from returned value of type 'std::vector<std::pair<Netmask, CounterAndActionValue>>' to function return type 'int'
    return result;
           ^~~~~~
  2 errors generated.

@Y7n05h
Copy link
Contributor Author

Y7n05h commented Jun 9, 2022

I missed it but there is a build error when we build without HAVE_EBPF:

Can you post how you built it? I did not successfully reproduce it. The commands I used is:

git clean -fXd
autoreconf -i
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --with-gnutls --with-libsodium --with-libssl --with-nghttp2 --with-re2 --enable-dnstap --enable-dns-over-tls --enable-dns-over-https --enable-dnscrypt
make -j16

@rgacogne
Copy link
Member

rgacogne commented Jun 9, 2022

I missed it but there is a build error when we build without HAVE_EBPF:

Can you post how you built it? I did not successfully reproduce it. The commands I used is:

It's one of the checks in our continuous integration, but the option we are interested in is here is ./configure --without-ebpf

Signed-off-by: Y7n05h <Y7n05h@protonmail.com>
Copy link
Member

@rgacogne rgacogne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, I'm not 100% sure why the documentation is failing to build but I suggested a few changes that might help.

pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
pdns/dnsdistdist/docs/reference/ebpf.rst Outdated Show resolved Hide resolved
Y7n05h and others added 3 commits June 10, 2022 12:14
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
Co-authored-by: Remi Gacogne <github@coredump.fr>
@rgacogne
Copy link
Member

The latest CI failure is unrelated to this PR (Google resolvers were not in a good mood: AXFR-out zone 'example.com', client '127.0.0.1', error resolving for ALIAS google-public-dns-a.google.com., aborting AXFR).

@rgacogne rgacogne merged commit a562d7a into PowerDNS:master Jun 10, 2022
@rgacogne
Copy link
Member

Thanks a lot!

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

Successfully merging this pull request may close these issues.

2 participants