Browse Source

[5377] Support for outbound-interface added.

Tomek Mrugalski 7 years ago
parent
commit
42d2139093

+ 8 - 0
doc/examples/kea4/advanced.json

@@ -31,6 +31,14 @@
         // Ethernet/IP stack processing.
         "dhcp-socket-type": "udp",
 
+        // Typically the DHCP server will send its response back on the same
+        // interface the query came in. This is the default ("same-as-inbound").
+        // However, sometimes it is useful to have the ability to send the
+        // packet as plain UDP packet and let the kernel and the routing tables
+        // to determine the right interface ("use-routing"). This option is
+        // expected to work only for dhcp-socket-type set to udp.
+        "outbound-interface": "use-routing",
+
         // This makes interfaces to be re-detected at each (re-)configuration.
         // By default it is true.
         "re-detect": true

+ 27 - 0
src/bin/dhcp4/dhcp4_lexer.ll

@@ -225,6 +225,33 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     }
 }
 
+\"outbound-interface\" {
+    switch(driver.ctx_) {
+    case Parser4Context::INTERFACES_CONFIG:
+        return  isc::dhcp::Dhcp4Parser::make_OUTBOUND_INTERFACE(driver.loc_);
+    default:
+        return isc::dhcp::Dhcp4Parser::make_STRING("outbound-interface", driver.loc_);
+    }
+}
+
+\"same-as-inbound\" {
+    switch(driver.ctx_) {
+    case Parser4Context::OUTBOUND_INTERFACE:
+        return Dhcp4Parser::make_SAME_AS_INBOUND(driver.loc_);
+    default:
+        return Dhcp4Parser::make_STRING("same-as-inbound", driver.loc_);
+    }
+}
+
+\"use-routing\" {
+    switch(driver.ctx_) {
+    case Parser4Context::OUTBOUND_INTERFACE:
+        return Dhcp4Parser::make_USE_ROUTING(driver.loc_);
+    default:
+        return Dhcp4Parser::make_STRING("use-routing", driver.loc_);
+    }
+}
+
 \"interfaces\" {
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::INTERFACES_CONFIG:

+ 18 - 0
src/bin/dhcp4/dhcp4_parser.yy

@@ -55,6 +55,9 @@ using namespace std;
   DHCP_SOCKET_TYPE "dhcp-socket-type"
   RAW "raw"
   UDP "udp"
+  OUTBOUND_INTERFACE "outbound-interface"
+  SAME_AS_INBOUND "same-as-inbound"
+  USE_ROUTING "use-routing"
   RE_DETECT "re-detect"
 
   ECHO_CLIENT_ID "echo-client-id"
@@ -212,6 +215,7 @@ using namespace std;
 %type <ElementPtr> value
 %type <ElementPtr> map_value
 %type <ElementPtr> socket_type
+%type <ElementPtr> outbound_interface_value
 %type <ElementPtr> db_type
 %type <ElementPtr> hr_mode
 %type <ElementPtr> ncr_protocol_value
@@ -477,6 +481,7 @@ interfaces_config_params: interfaces_config_param
 
 interfaces_config_param: interfaces_list
                        | dhcp_socket_type
+                       | outbound_interface
                        | re_detect
                        ;
 
@@ -510,6 +515,19 @@ socket_type: RAW { $$ = ElementPtr(new StringElement("raw", ctx.loc2pos(@1))); }
            | UDP { $$ = ElementPtr(new StringElement("udp", ctx.loc2pos(@1))); }
            ;
 
+outbound_interface: OUTBOUND_INTERFACE {
+    ctx.enter(ctx.OUTBOUND_INTERFACE);
+} COLON outbound_interface_value {
+    ctx.stack_.back()->set("outbound-interface", $4);
+    ctx.leave();
+}
+
+outbound_interface_value: SAME_AS_INBOUND {
+    $$ = ElementPtr(new StringElement("same-as-inbound", ctx.loc2pos(@1)));
+} | USE_ROUTING {
+    $$ = ElementPtr(new StringElement("use-routing", ctx.loc2pos(@1)));
+    } ;
+
 re_detect: RE_DETECT COLON BOOLEAN {
     ElementPtr b(new BoolElement($3, ctx.loc2pos(@3)));
     ctx.stack_.back()->set("re-detect", b);

+ 2 - 0
src/bin/dhcp4/parser_context.cc

@@ -144,6 +144,8 @@ Parser4Context::contextName()
         return ("interfaces-config");
     case DHCP_SOCKET_TYPE:
         return ("dhcp-socket-type");
+    case OUTBOUND_INTERFACE:
+        return ("outbound-interface");
     case LEASE_DATABASE:
         return ("lease-database");
     case HOSTS_DATABASE:

+ 3 - 0
src/bin/dhcp4/parser_context.h

@@ -214,6 +214,9 @@ public:
         /// Used while parsing Dhcp4/interfaces/dhcp-socket-type structures.
         DHCP_SOCKET_TYPE,
 
+        /// Used while parsing Dhcp4/interfaces/outbound-interface structures.
+        OUTBOUND_INTERFACE,
+
         /// Used while parsing Dhcp4/lease-database structures.
         LEASE_DATABASE,
 

+ 31 - 1
src/lib/dhcpsrv/cfg_iface.cc

@@ -22,7 +22,8 @@ namespace dhcp {
 const char* CfgIface::ALL_IFACES_KEYWORD = "*";
 
 CfgIface::CfgIface()
-    : wildcard_used_(false), socket_type_(SOCKET_RAW), re_detect_(false) {
+    : wildcard_used_(false), socket_type_(SOCKET_RAW), re_detect_(false),
+      outbound_iface_(SAME_AS_INBOUND) {
 }
 
 void
@@ -226,6 +227,35 @@ CfgIface::textToSocketType(const std::string& socket_type_name) const {
     }
 }
 
+std::string
+CfgIface::outboundTypeToText() const {
+    switch (outbound_iface_) {
+    case SAME_AS_INBOUND: return ("same-as-inbound");
+    case USE_ROUTING:      return ("use-routing");
+    default: isc_throw(Unexpected, "unsupported outbound-type " << socket_type_);
+    }
+
+}
+
+CfgIface::OutboundIface
+CfgIface::textToOutboundIface(const std::string& txt) {
+    if (txt == "same-as-inbound") {
+        return (SAME_AS_INBOUND);
+
+    } else if (txt == "use-routing") {
+        return (USE_ROUTING);
+
+    } else {
+        isc_throw(InvalidSocketType, "unsupported socket type '"
+                  << txt << "'");
+    }
+}
+
+void
+CfgIface::setOutboundIface(const OutboundIface& traffic_type) {
+    outbound_iface_ = traffic_type;
+}
+
 void
 CfgIface::use(const uint16_t family, const std::string& iface_name) {
     // The interface name specified may have two formats:

+ 16 - 0
src/lib/dhcpsrv/cfg_iface.h

@@ -137,6 +137,12 @@ public:
         SOCKET_UDP
     };
 
+    enum OutboundIface {
+        SAME_AS_INBOUND,
+
+        USE_ROUTING
+    };
+
     /// @brief Keyword used to enable all interfaces.
     ///
     /// This keyword can be used instead of the interface name to specify
@@ -227,6 +233,14 @@ public:
     /// @brief Returns the socket type in the textual format.
     std::string socketTypeToText() const;
 
+    void setOutboundIface(const OutboundIface& traffic_type);
+
+    OutboundIface getOutboundIface() const;
+
+    std::string outboundTypeToText() const;
+
+    static OutboundIface textToOutboundIface(const std::string& txt);
+
     /// @brief Converts the socket type in the textual format to the type
     /// represented by the @c SocketType.
     ///
@@ -340,6 +354,8 @@ private:
 
     /// @brief A boolean value which reflects current re-detect setting
     bool re_detect_;
+
+    OutboundIface outbound_iface_;
 };
 
 /// @brief A pointer to the @c CfgIface .

+ 12 - 0
src/lib/dhcpsrv/parsers/ifaces_config_parser.cc

@@ -76,6 +76,18 @@ IfacesConfigParser::parse(const CfgIfacePtr& cfg,
                 }
             }
 
+            if (element.first == "outbound-interface") {
+                if (protocol_ == AF_INET) {
+                    CfgIface::OutboundIface type =
+                        CfgIface::textToOutboundIface(element.second->stringValue());
+                    cfg->setOutboundIface(type);
+                    continue;
+                } else {
+                    isc_throw(DhcpConfigError,
+                              "outbound-interface is not supported in DHCPv6");
+                }
+            }
+
             // This should never happen as the input produced by the parser
             // see (src/bin/dhcpX/dhcpX_parser.yy) should not produce any
             // other parameter, so this case is only to catch bugs in