#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"
{
#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;
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);
});
}
+#if defined(HAVE_EBPF)
+ if (!configCheck && globalConfig.ebpf.ipv4.max_entries > 0 && globalConfig.ebpf.ipv6.max_entries > 0 && globalConfig.ebpf.qnames.max_entries > 0) {
+ 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));
}
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;
#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));
}
}
console: ConsoleConfiguration,
dynamic_rules: Vec<DynamicRulesConfiguration>,
dynamic_rules_settings: DynamicRulesSettingsConfiguration,
+ ebpf: EbpfConfiguration,
edns_client_subnet: EdnsClientSubnetConfiguration,
general: GeneralConfiguration,
key_value_stores: KeyValueStoresConfiguration,
tuning: TuningConfiguration,
webserver: WebserverConfiguration,
xfr_response_rules: Vec<ResponseRuleConfiguration>,
+ xsk: Vec<XskConfiguration>,
}
#[derive(Deserialize, Serialize, Debug, PartialEq)]
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 {
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ ipv4: EbpfMapConfiguration,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ ipv6: EbpfMapConfiguration,
+ #[serde(rename = "cidr-ipv4", default, skip_serializing_if = "crate::is_default")]
+ cidr_ipv4: EbpfMapConfiguration,
+ #[serde(rename = "cidr-ipv6", default, skip_serializing_if = "crate::is_default")]
+ cidr_ipv6: EbpfMapConfiguration,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ qnames: EbpfMapConfiguration,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ external: bool,
+ }
+
#[derive(Deserialize, Serialize, Debug, PartialEq)]
#[serde(deny_unknown_fields)]
struct EdnsClientSubnetConfiguration {
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)]
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)]
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)
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")]
webserver: dnsdistsettings::WebserverConfiguration,
#[serde(rename = "xfr-response-rules", default, skip_serializing_if = "crate::is_default")]
xfr_response_rules: Vec<ResponseRuleConfigurationSerde>,
+ #[serde(default, skip_serializing_if = "crate::is_default")]
+ xsk: Vec<dnsdistsettings::XskConfiguration>,
}
#[derive(Default, Serialize, Deserialize, Debug, PartialEq)]
}
+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();
}
+// 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();
sub_type.validate()?;
}
self.dynamic_rules_settings.validate()?;
+ self.ebpf.validate()?;
self.edns_client_subnet.validate()?;
self.general.validate()?;
self.key_value_stores.validate()?;
self.webserver.validate()?;
for sub_type in &self.xfr_response_rules {
sub_type.validate()?;
+ }
+ for sub_type in &self.xsk {
+ sub_type.validate()?;
}
Ok(())
}
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(())
Ok(())
}
}
+impl dnsdistsettings::XskConfiguration {
+ fn validate(&self) -> Result<(), ValidationError> {
+ Ok(())
+ }
+}
impl GlobalConfigurationSerde {
fn validate(&self) -> Result<(), ValidationError> {
for sub_type in &self.backends {
sub_type.validate()?;
}
self.dynamic_rules_settings.validate()?;
+ self.ebpf.validate()?;
self.edns_client_subnet.validate()?;
self.general.validate()?;
self.key_value_stores.validate()?;
self.webserver.validate()?;
for sub_type in &self.xfr_response_rules {
sub_type.validate()?;
+ }
+ for sub_type in &self.xsk {
+ sub_type.validate()?;
}
Ok(())
}
type: "DynamicRulesSettingsConfiguration"
default: true
description: "Dynamic rules-related settings"
+ - name: "ebpf"
+ type: "EbpfConfiguration"
+ default: true
+ description: "EBPF settings"
- name: "edns-client-subnet"
type: "EdnsClientSubnetConfiguration"
default: true
default: true
skip-serde: true
description: "List of rules executed when a XFR response is received"
+ - name: "xsk"
+ type: "Vec<XskConfiguration>"
+ default: true
+ description: "List of AF_XDP / XSK objects"
metrics:
parameters:
internal-field-name: "d_consoleMaxConcurrentConnections"
runtime-configurable: false
+ebpf-map:
+ parameters:
+ - name: "max-entries"
+ type: "u32"
+ default: 0
+ - name: "pinned-path"
+ type: "String"
+ default: ""
+
+ebpf:
+ parameters:
+ - name: "ipv4"
+ type: "EbpfMapConfiguration"
+ default: true
+ - name: "ipv6"
+ type: "EbpfMapConfiguration"
+ default: true
+ - name: "cidr-ipv4"
+ type: "EbpfMapConfiguration"
+ default: true
+ - name: "cidr-ipv6"
+ type: "EbpfMapConfiguration"
+ default: true
+ - name: "qnames"
+ type: "EbpfMapConfiguration"
+ default: true
+ - name: "external"
+ type: "bool"
+ default: "false"
+
edns-client-subnet:
parameters:
- name: "override-existing"
- name: "additional-addresses"
type: "Vec<String>"
default: true
+ - name: "xsk"
+ type: "String"
+ default: ""
outgoing-tcp:
parameters:
- name: "cpus"
type: "String"
default: ""
+ - name: "xsk"
+ type: "String"
+ default: ""
tuning:
parameters:
type: "Selector"
- name: "action"
type: "ResponseAction"
+
+xsk:
+ parameters:
+ - name: "name"
+ type: "String"
+ - name: "interface"
+ type: "String"
+ - name: "queues"
+ type: "u16"
+ - name: "frames"
+ type: "u32"
+ default: 65536
+ - name: "map-path"
+ type: "String"
+ default: "/sys/fs/bpf/dnsdist/xskmap"
- **console**: :ref:`ConsoleConfiguration <yaml-settings-ConsoleConfiguration>` - Console-related settings
- **dynamic-rules**: Sequence of :ref:`DynamicRulesConfiguration <yaml-settings-DynamicRulesConfiguration>` - List of dynamic rules
- **dynamic-rules-settings**: :ref:`DynamicRulesSettingsConfiguration <yaml-settings-DynamicRulesSettingsConfiguration>` - Dynamic rules-related settings
+- **ebpf**: :ref:`EbpfConfiguration <yaml-settings-EbpfConfiguration>` - EBPF settings
- **edns-client-subnet**: :ref:`EdnsClientSubnetConfiguration <yaml-settings-EdnsClientSubnetConfiguration>` - EDNS Client Subnet-related settings
- **general**: :ref:`GeneralConfiguration <yaml-settings-GeneralConfiguration>` - General settings
- **key-value-stores**: :ref:`KeyValueStoresConfiguration <yaml-settings-KeyValueStoresConfiguration>` - Key-Value stores
- **tuning**: :ref:`TuningConfiguration <yaml-settings-TuningConfiguration>` - Performance-related settings
- **webserver**: :ref:`WebserverConfiguration <yaml-settings-WebserverConfiguration>` - Internal web server configuration
- **xfr-response-rules**: Sequence of :ref:`ResponseRuleConfiguration <yaml-settings-ResponseRuleConfiguration>` - List of rules executed when a XFR response is received
+- **xsk**: Sequence of :ref:`XskConfiguration <yaml-settings-XskConfiguration>` - List of AF_XDP / XSK objects
- **xsk-sockets**: Sequence of String
- **mac-address**: String ``("")``
- **cpus**: String ``("")``
+- **xsk**: String ``("")``
.. _yaml-settings-BindConfiguration:
- **quic**: :ref:`IncomingQuicConfiguration <yaml-settings-IncomingQuicConfiguration>`
- **dnscrypt**: :ref:`IncomingDnscryptConfiguration <yaml-settings-IncomingDnscryptConfiguration>`
- **additional-addresses**: Sequence of String
+- **xsk**: String ``("")``
.. _yaml-settings-CDBKVStoreConfiguration:
- **default-action**: String ``(Drop)``
+.. _yaml-settings-EbpfConfiguration:
+
+EbpfConfiguration
+-----------------
+
+- **ipv4**: :ref:`EbpfMapConfiguration <yaml-settings-EbpfMapConfiguration>`
+- **ipv6**: :ref:`EbpfMapConfiguration <yaml-settings-EbpfMapConfiguration>`
+- **cidr-ipv4**: :ref:`EbpfMapConfiguration <yaml-settings-EbpfMapConfiguration>`
+- **cidr-ipv6**: :ref:`EbpfMapConfiguration <yaml-settings-EbpfMapConfiguration>`
+- **qnames**: :ref:`EbpfMapConfiguration <yaml-settings-EbpfMapConfiguration>`
+- **external**: Boolean ``(false)``
+
+
+.. _yaml-settings-EbpfMapConfiguration:
+
+EbpfMapConfiguration
+--------------------
+
+- **max-entries**: Unsigned integer ``(0)``
+- **pinned-path**: String ``("")``
+
+
.. _yaml-settings-EdnsClientSubnetConfiguration:
EdnsClientSubnetConfiguration
- **api-read-write**: Boolean ``(false)``
+.. _yaml-settings-XskConfiguration:
+
+XskConfiguration
+----------------
+
+- **name**: String
+- **interface**: String
+- **queues**: Unsigned integer
+- **frames**: Unsigned integer ``(65536)``
+- **map-path**: String ``(/sys/fs/bpf/dnsdist/xskmap)``
+
+