]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Implement XSK and eBPF via YAML
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 27 Dec 2024 14:54:43 +0000 (15:54 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Jan 2025 08:51:10 +0000 (09:51 +0100)
pdns/dnsdistdist/dnsdist-configuration-yaml.cc
pdns/dnsdistdist/dnsdist-rust-lib/rust/src/lib.rs
pdns/dnsdistdist/dnsdist-settings-definitions.yml
pdns/dnsdistdist/docs/reference/yaml-settings.rst

index da6dae586bfcd7317df2c3154c04e93e151a2338..bd0b6553cf5eebfad962d48584a36f809d35ff7e 100644 (file)
 #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"
@@ -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;
@@ -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);
@@ -490,6 +505,44 @@ bool loadConfigurationFromFile(const std::string& fileName, bool isClient, bool
       });
     }
 
+#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));
@@ -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;
@@ -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));
           }
         }
index 2a45c57a050d2cb626d93f833a456202f545772e..f975c906a6aea8926833e4c3e5db2e4a2080409d 100644 (file)
@@ -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,
@@ -1135,6 +1136,7 @@ mod dnsdistsettings {
         tuning: TuningConfiguration,
         webserver: WebserverConfiguration,
         xfr_response_rules: Vec<ResponseRuleConfiguration>,
+        xsk: Vec<XskConfiguration>,
     }
 
     #[derive(Deserialize, Serialize, Debug, PartialEq)]
@@ -1336,6 +1338,32 @@ 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 {
+        #[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 {
@@ -1644,6 +1672,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)]
@@ -1792,6 +1822,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)]
@@ -2040,6 +2072,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)
@@ -2281,6 +2325,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")]
@@ -2321,6 +2367,8 @@ impl dnsdistsettings::SharedDNSResponseAction {
         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)]
@@ -2579,6 +2627,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();
@@ -3053,6 +3117,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();
@@ -3084,6 +3165,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()?;
@@ -3114,6 +3196,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(())
     }
@@ -3229,6 +3314,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(())
@@ -3472,6 +3572,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 {
@@ -3495,6 +3600,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()?;
@@ -3525,6 +3631,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(())
     }
index 513d1f12ac7caff54f3851ec0e91a54677d1846e..25910f860e3b6db1e173665e9b08162e68e31907 100644 (file)
@@ -45,6 +45,10 @@ global:
       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
@@ -130,6 +134,10 @@ global:
       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:
@@ -392,6 +400,36 @@ console:
       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"
@@ -815,6 +853,9 @@ bind:
     - name: "additional-addresses"
       type: "Vec<String>"
       default: true
+    - name: "xsk"
+      type: "String"
+      default: ""
 
 outgoing-tcp:
   parameters:
@@ -1012,6 +1053,9 @@ backend:
     - name: "cpus"
       type: "String"
       default: ""
+    - name: "xsk"
+      type: "String"
+      default: ""
 
 tuning:
   parameters:
@@ -1473,3 +1517,18 @@ response-rule:
       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"
index ee4c8d37c7d65b8246556c263f99186f8b68a9f5..8da8a2424f7fbb9cab2bef8f97fdb53bddeb12d7 100644 (file)
@@ -30,6 +30,7 @@ GlobalConfiguration
 - **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
@@ -50,6 +51,7 @@ GlobalConfiguration
 - **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
 
 
 
@@ -87,6 +89,7 @@ BackendConfiguration
 - **xsk-sockets**: Sequence of String
 - **mac-address**: String ``("")``
 - **cpus**: String ``("")``
+- **xsk**: String ``("")``
 
 
 .. _yaml-settings-BindConfiguration:
@@ -108,6 +111,7 @@ BindConfiguration
 - **quic**: :ref:`IncomingQuicConfiguration <yaml-settings-IncomingQuicConfiguration>`
 - **dnscrypt**: :ref:`IncomingDnscryptConfiguration <yaml-settings-IncomingDnscryptConfiguration>`
 - **additional-addresses**: Sequence of String
+- **xsk**: String ``("")``
 
 
 .. _yaml-settings-CDBKVStoreConfiguration:
@@ -240,6 +244,28 @@ DynamicRulesSettingsConfiguration
 - **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
@@ -785,3 +811,15 @@ WebserverConfiguration
 - **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)``
+
+