Skip to content

Commit

Permalink
dnsdist: Implement XSK and eBPF via YAML
Browse files Browse the repository at this point in the history
  • Loading branch information
rgacogne committed Dec 27, 2024
1 parent 1d02750 commit 970895f
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 3 deletions.
81 changes: 78 additions & 3 deletions pdns/dnsdistdist/dnsdist-configuration-yaml.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@
#include "dnsdist-rules-factory.hh"
#include "dnsdist-kvs.hh"
#include "dnsdist-web.hh"
#include "dnsdist-xsk.hh"
#include "doh.hh"
#include "fstrm_logger.hh"
#include "iputils.hh"
#include "remote_logger.hh"
#include "xsk.hh"

#include "rust/cxx.h"
#include "rust/lib.rs.h"
Expand All @@ -53,7 +55,9 @@ namespace dnsdist::configuration::yaml
{
#if defined(HAVE_YAML_CONFIGURATION)

using RegisteredTypes = std::variant<std::shared_ptr<DNSDistPacketCache>, std::shared_ptr<dnsdist::rust::settings::DNSSelector>, std::shared_ptr<dnsdist::rust::settings::DNSActionWrapper>, std::shared_ptr<dnsdist::rust::settings::DNSResponseActionWrapper>, std::shared_ptr<NetmaskGroup>, std::shared_ptr<KeyValueStore>, std::shared_ptr<KeyValueLookupKey>, std::shared_ptr<RemoteLoggerInterface>, std::shared_ptr<ServerPolicy>>;
using XSKMap = std::vector<std::shared_ptr<XskSocket>>;

using RegisteredTypes = std::variant<std::shared_ptr<DNSDistPacketCache>, std::shared_ptr<dnsdist::rust::settings::DNSSelector>, std::shared_ptr<dnsdist::rust::settings::DNSActionWrapper>, std::shared_ptr<dnsdist::rust::settings::DNSResponseActionWrapper>, std::shared_ptr<NetmaskGroup>, std::shared_ptr<KeyValueStore>, std::shared_ptr<KeyValueLookupKey>, std::shared_ptr<RemoteLoggerInterface>, std::shared_ptr<ServerPolicy>, std::shared_ptr<XSKMap>>;
static LockGuarded<std::unordered_map<std::string, RegisteredTypes>> s_registeredTypesMap;
static std::atomic<bool> s_inConfigCheckMode;
static std::atomic<bool> s_inClientMode;
Expand Down Expand Up @@ -423,14 +427,25 @@ static std::shared_ptr<DownstreamState> createBackendFromConfiguration(const dns

backendConfig.remote = ComboAddress(std::string(config.address), serverPort);

#warning handle XSK

if (protocol == "dot" || protocol == "doh") {
tlsCtx = getTLSContext(backendConfig.d_tlsParams);
}

auto downstream = std::make_shared<DownstreamState>(std::move(backendConfig), std::move(tlsCtx), !configCheck);

#if defined(HAVE_XSK)
if (!config.xsk.empty()) {
auto xskMap = getRegisteredTypeByName<XSKMap>(config.xsk);
if (!xskMap) {
throw std::runtime_error("XSK map " + std::string(config.xsk) + " attached to backend " + std::string(config.address) + " not found");
}
downstream->registerXsk(*xskMap);
if (!configCheck) {
infolog("Added downstream server %s via XSK in %s mode", std::string(config.address), xskMap->at(0)->getXDPMode());
}
}
#endif /* defined(HAVE_XSK) */

const auto& autoUpgradeConf = config.auto_upgrade;
if (autoUpgradeConf.enabled && downstream->getProtocol() != dnsdist::Protocol::DoT && downstream->getProtocol() != dnsdist::Protocol::DoH) {
dnsdist::ServiceDiscovery::addUpgradeableServer(downstream, autoUpgradeConf.interval, std::string(autoUpgradeConf.pool), autoUpgradeConf.doh_key, autoUpgradeConf.keep);
Expand Down Expand Up @@ -490,6 +505,44 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool
});
}

#if defined(HAVE_EBPF)
if (!configCheck) {
BPFFilter::MapFormat format = globalConfig.ebpf.external ? BPFFilter::MapFormat::WithActions : BPFFilter::MapFormat::Legacy;
std::unordered_map<std::string, BPFFilter::MapConfiguration> mapsConfig;

const auto convertParamsToConfig = [&mapsConfig](const std::string& name, BPFFilter::MapType type, const dnsdist::rust::settings::EbpfMapConfiguration& mapConfig) {
if (mapConfig.max_entries == 0) {
return;
}
BPFFilter::MapConfiguration config;
config.d_type = type;
config.d_maxItems = mapConfig.max_entries;
config.d_pinnedPath = std::string(mapConfig.pinned_path);
mapsConfig[name] = std::move(config);
};

convertParamsToConfig("ipv4", BPFFilter::MapType::IPv4, globalConfig.ebpf.ipv4);
convertParamsToConfig("ipv6", BPFFilter::MapType::IPv6, globalConfig.ebpf.ipv6);
convertParamsToConfig("qnames", BPFFilter::MapType::QNames, globalConfig.ebpf.qnames);
convertParamsToConfig("cidr4", BPFFilter::MapType::CIDR4, globalConfig.ebpf.cidr_ipv4);
convertParamsToConfig("cidr6", BPFFilter::MapType::CIDR6, globalConfig.ebpf.cidr_ipv6);
auto filter = std::make_shared<BPFFilter>(mapsConfig, format, globalConfig.ebpf.external);
g_defaultBPFFilter = std::move(filter);
}
#endif /* defined(HAVE_EBPF) */

#if defined(HAVE_XSK)
for (const auto& xskEntry : globalConfig.xsk) {
auto map = std::shared_ptr<XSKMap>();
for (size_t counter = 0; counter < xskEntry.queues; ++counter) {
auto socket = std::make_shared<XskSocket>(xskEntry.frames, std::string(xskEntry.interface), counter, std::string(xskEntry.map_path));
dnsdist::xsk::g_xsk.push_back(socket);
map->push_back(std::move(socket));
}
registerType<XSKMap>(map, xskEntry.name);
}
#endif /* defined(HAVE_XSK) */

for (const auto& bind : globalConfig.binds) {
updateImmutableConfiguration([&bind](ImmutableConfiguration& config) {
auto protocol = boost::to_lower_copy(std::string(bind.protocol));
Expand All @@ -502,6 +555,17 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool
}
ComboAddress listeningAddress(std::string(bind.listen_address), defaultPort);
auto cpus = getCPUPiningFromStr("binds", std::string(bind.cpus));
std::shared_ptr<XSKMap> xskMap;
if (!bind.xsk.empty()) {
xskMap = getRegisteredTypeByName<XSKMap>(bind.xsk);
if (!xskMap) {
throw std::runtime_error("XSK map " + std::string(bind.xsk) + " attached to bind " + std::string(bind.listen_address) + " not found");
}
if (xskMap->size() != bind.threads) {
throw std::runtime_error("XSK map " + std::string(bind.xsk) + " attached to bind " + std::string(bind.listen_address) + " has less queues than the number of threads of the bind");
}
}

for (size_t idx = 0; idx < bind.threads; idx++) {
#if defined(HAVE_DNSCRYPT)
std::shared_ptr<DNSCryptContext> dnsCryptContext;
Expand Down Expand Up @@ -552,6 +616,17 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool
#if defined(HAVE_DNSCRYPT)
state->dnscryptCtx = dnsCryptContext;
#endif /* defined(HAVE_DNSCRYPT) */
#if defined(HAVE_XSK)
if (xskMap) {
auto xsk = xskMap->at(idx);
state->xskInfo = XskWorker::create(XskWorker::Type::Bidirectional, xsk->sharedEmptyFrameOffset);
xsk->addWorker(state->xskInfo);
xsk->addWorkerRoute(state->xskInfo, listeningAddress);
state->xskInfoResponder = XskWorker::create(XskWorker::Type::OutgoingOnly, xsk->sharedEmptyFrameOffset);
xsk->addWorker(state->xskInfoResponder);
vinfolog("Enabling XSK in %s mode for incoming UDP packets to %s", xsk->getXDPMode(), listeningAddress.toStringWithPort());
}
#endif /* defined(HAVE_XSK) */
config.d_frontends.emplace_back(std::move(state));
}
}
Expand Down
105 changes: 105 additions & 0 deletions pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,7 @@ mod dnsdistsettings {
console: ConsoleConfiguration,
dynamic_rules: Vec<DynamicRulesConfiguration>,
dynamic_rules_settings: DynamicRulesSettingsConfiguration,
ebpf: EbpfConfiguration,
edns_client_subnet: EdnsClientSubnetConfiguration,
general: GeneralConfiguration,
key_value_stores: KeyValueStoresConfiguration,
Expand All @@ -1135,6 +1136,7 @@ mod dnsdistsettings {
tuning: TuningConfiguration,
webserver: WebserverConfiguration,
xfr_response_rules: Vec<ResponseRuleConfiguration>,
xsk: Vec<XskConfiguration>,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
Expand Down Expand Up @@ -1336,6 +1338,29 @@ mod dnsdistsettings {
max_concurrent_connections: u64,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
struct EbpfMapConfiguration {
#[serde(rename = "max-entries", default, skip_serializing_if = "crate::is_default")]
max_entries: u32,
#[serde(rename = "pinned-path", default, skip_serializing_if = "crate::is_default")]
pinned_path: String,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
struct EbpfConfiguration {
ipv4: EbpfMapConfiguration,
ipv6: EbpfMapConfiguration,
#[serde(rename = "cidr-ipv4", )]
cidr_ipv4: EbpfMapConfiguration,
#[serde(rename = "cidr-ipv6", )]
cidr_ipv6: EbpfMapConfiguration,
qnames: EbpfMapConfiguration,
#[serde(default, skip_serializing_if = "crate::is_default")]
external: bool,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
struct EdnsClientSubnetConfiguration {
Expand Down Expand Up @@ -1644,6 +1669,8 @@ mod dnsdistsettings {
dnscrypt: IncomingDnscryptConfiguration,
#[serde(rename = "additional-addresses", default, skip_serializing_if = "crate::is_default")]
additional_addresses: Vec<String>,
#[serde(default, skip_serializing_if = "crate::is_default")]
xsk: String,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
Expand Down Expand Up @@ -1792,6 +1819,8 @@ mod dnsdistsettings {
mac_address: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
cpus: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
xsk: String,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
Expand Down Expand Up @@ -2040,6 +2069,18 @@ mod dnsdistsettings {
action: SharedDNSResponseAction,
}

#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
struct XskConfiguration {
name: String,
interface: String,
queues: u16,
#[serde(default = "crate::U32::<65536>::value", skip_serializing_if = "crate::U32::<65536>::is_equal")]
frames: u32,
#[serde(rename = "map-path", default = "crate::default_value_xsk_map_path", skip_serializing_if = "crate::default_value_equal_xsk_map_path")]
map_path: String,
}


/*
* Functions callable from Rust (actions and selectors)
Expand Down Expand Up @@ -2281,6 +2322,8 @@ impl dnsdistsettings::SharedDNSResponseAction {
dynamic_rules: Vec<dnsdistsettings::DynamicRulesConfiguration>,
#[serde(rename = "dynamic-rules-settings", default, skip_serializing_if = "crate::is_default")]
dynamic_rules_settings: dnsdistsettings::DynamicRulesSettingsConfiguration,
#[serde(default, skip_serializing_if = "crate::is_default")]
ebpf: dnsdistsettings::EbpfConfiguration,
#[serde(rename = "edns-client-subnet", default, skip_serializing_if = "crate::is_default")]
edns_client_subnet: dnsdistsettings::EdnsClientSubnetConfiguration,
#[serde(default, skip_serializing_if = "crate::is_default")]
Expand Down Expand Up @@ -2321,6 +2364,7 @@ impl dnsdistsettings::SharedDNSResponseAction {
webserver: dnsdistsettings::WebserverConfiguration,
#[serde(rename = "xfr-response-rules", default, skip_serializing_if = "crate::is_default")]
xfr_response_rules: Vec<ResponseRuleConfigurationSerde>,
xsk: Vec<dnsdistsettings::XskConfiguration>,
}

#[derive(Default, Serialize, Deserialize, Debug, PartialEq)]
Expand Down Expand Up @@ -2579,6 +2623,22 @@ impl Default for dnsdistsettings::ConsoleConfiguration {
}


impl Default for dnsdistsettings::EbpfMapConfiguration {
fn default() -> Self {
let deserialized: dnsdistsettings::EbpfMapConfiguration = serde_yaml::from_str("").unwrap();
deserialized
}
}


impl Default for dnsdistsettings::EbpfConfiguration {
fn default() -> Self {
let deserialized: dnsdistsettings::EbpfConfiguration = serde_yaml::from_str("").unwrap();
deserialized
}
}


impl Default for dnsdistsettings::EdnsClientSubnetConfiguration {
fn default() -> Self {
let deserialized: dnsdistsettings::EdnsClientSubnetConfiguration = serde_yaml::from_str("").unwrap();
Expand Down Expand Up @@ -3053,6 +3113,23 @@ impl Default for dnsdistsettings::LoadBalancingPoliciesConfiguration {
}


// DEFAULT HANDLING for xsk_map_path
fn default_value_xsk_map_path() -> String {
String::from("/sys/fs/bpf/dnsdist/xskmap")
}
fn default_value_equal_xsk_map_path(value: &str)-> bool {
value == default_value_xsk_map_path()
}


impl Default for dnsdistsettings::XskConfiguration {
fn default() -> Self {
let deserialized: dnsdistsettings::XskConfiguration = serde_yaml::from_str("").unwrap();
deserialized
}
}


impl Default for GlobalConfigurationSerde {
fn default() -> Self {
let deserialized: GlobalConfigurationSerde = serde_yaml::from_str("").unwrap();
Expand Down Expand Up @@ -3084,6 +3161,7 @@ impl dnsdistsettings::GlobalConfiguration {
sub_type.validate()?;
}
self.dynamic_rules_settings.validate()?;
self.ebpf.validate()?;
self.edns_client_subnet.validate()?;
self.general.validate()?;
self.key_value_stores.validate()?;
Expand Down Expand Up @@ -3114,6 +3192,9 @@ impl dnsdistsettings::GlobalConfiguration {
self.webserver.validate()?;
for sub_type in &self.xfr_response_rules {
sub_type.validate()?;
}
for sub_type in &self.xsk {
sub_type.validate()?;
}
Ok(())
}
Expand Down Expand Up @@ -3229,6 +3310,21 @@ impl dnsdistsettings::ConsoleConfiguration {
Ok(())
}
}
impl dnsdistsettings::EbpfMapConfiguration {
fn validate(&self) -> Result<(), ValidationError> {
Ok(())
}
}
impl dnsdistsettings::EbpfConfiguration {
fn validate(&self) -> Result<(), ValidationError> {
self.ipv4.validate()?;
self.ipv6.validate()?;
self.cidr_ipv4.validate()?;
self.cidr_ipv6.validate()?;
self.qnames.validate()?;
Ok(())
}
}
impl dnsdistsettings::EdnsClientSubnetConfiguration {
fn validate(&self) -> Result<(), ValidationError> {
Ok(())
Expand Down Expand Up @@ -3472,6 +3568,11 @@ impl dnsdistsettings::ResponseRuleConfiguration {
Ok(())
}
}
impl dnsdistsettings::XskConfiguration {
fn validate(&self) -> Result<(), ValidationError> {
Ok(())
}
}
impl GlobalConfigurationSerde {
fn validate(&self) -> Result<(), ValidationError> {
for sub_type in &self.backends {
Expand All @@ -3495,6 +3596,7 @@ impl GlobalConfigurationSerde {
sub_type.validate()?;
}
self.dynamic_rules_settings.validate()?;
self.ebpf.validate()?;
self.edns_client_subnet.validate()?;
self.general.validate()?;
self.key_value_stores.validate()?;
Expand Down Expand Up @@ -3525,6 +3627,9 @@ impl GlobalConfigurationSerde {
self.webserver.validate()?;
for sub_type in &self.xfr_response_rules {
sub_type.validate()?;
}
for sub_type in &self.xsk {
sub_type.validate()?;
}
Ok(())
}
Expand Down
Loading

0 comments on commit 970895f

Please sign in to comment.