ncsi: make Interface virtual

Now that we have encapsulation for passing NCSI commands and responses
to/from an interface, we can make the Interface object virtual, and have
the Netlink implementation as a subclass.

We keep the netlink-specific operations in NetlinkInterface; getInfo(),
setChannel(), clearInterface(), and the channel/package mask operations
are all netlink-specific items to control kernel state.

Change-Id: I30b9cec41712d2e32d12685dd8406e08c6dea1f0
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
diff --git a/src/ncsi_netlink_main.cpp b/src/ncsi_netlink_main.cpp
index ce9b3f2..8859950 100644
--- a/src/ncsi_netlink_main.cpp
+++ b/src/ncsi_netlink_main.cpp
@@ -122,7 +122,7 @@
                       argv);
     }
 
-    Interface interface{indexInt};
+    NetlinkInterface interface(indexInt);
 
     // Parse out package argument.
     auto package = (options)["package"];
diff --git a/src/ncsi_util.cpp b/src/ncsi_util.cpp
index d8ad3b2..c9ac7b5 100644
--- a/src/ncsi_util.cpp
+++ b/src/ncsi_util.cpp
@@ -272,7 +272,7 @@
     return static_cast<int>(NL_STOP);
 };
 
-int applyCmd(Interface& interface, const NetlinkCommand& cmd,
+int applyCmd(NetlinkInterface& interface, const NetlinkCommand& cmd,
              int package = DEFAULT_VALUE, int channel = DEFAULT_VALUE,
              int flags = NONE, CallBack function = nullptr, void* arg = nullptr)
 {
@@ -422,10 +422,17 @@
 
 std::string to_string(Interface& interface)
 {
-    return std::to_string(interface.ifindex);
+    return interface.toString();
 }
 
-std::optional<NCSIResponse> Interface::sendCommand(NCSICommand& cmd)
+NetlinkInterface::NetlinkInterface(int ifindex) : ifindex(ifindex) {}
+
+std::string NetlinkInterface::toString()
+{
+    return std::to_string(ifindex);
+}
+
+std::optional<NCSIResponse> NetlinkInterface::sendCommand(NCSICommand& cmd)
 {
     lg2::debug("Send Command, CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, "
                "INTERFACE: {INTERFACE}",
@@ -448,7 +455,7 @@
     return ctx.resp;
 }
 
-int Interface::setChannel(int package, int channel)
+int NetlinkInterface::setChannel(int package, int channel)
 {
     lg2::debug("Set CHANNEL : {CHANNEL} , PACKAGE : {PACKAGE}, INTERFACE : "
                "{INTERFACE}",
@@ -460,7 +467,7 @@
     return internal::applyCmd(*this, cmd, package, channel);
 }
 
-int Interface::clearInterface()
+int NetlinkInterface::clearInterface()
 {
     lg2::debug("ClearInterface , INTERFACE : {INTERFACE}", "INTERFACE", this);
 
@@ -468,7 +475,7 @@
     return internal::applyCmd(*this, cmd);
 }
 
-std::optional<InterfaceInfo> Interface::getInfo(int package)
+std::optional<InterfaceInfo> NetlinkInterface::getInfo(int package)
 {
     int rc, flags = package == DEFAULT_VALUE ? NLM_F_DUMP : NONE;
     InterfaceInfo info;
@@ -493,7 +500,7 @@
     return info;
 }
 
-int Interface::setPackageMask(unsigned int mask)
+int NetlinkInterface::setPackageMask(unsigned int mask)
 {
     lg2::debug("Set Package Mask , INTERFACE: {INTERFACE} MASK: {MASK}",
                "INTERFACE", this, "MASK", lg2::hex, mask);
@@ -506,7 +513,7 @@
     return internal::applyCmd(*this, cmd);
 }
 
-int Interface::setChannelMask(int package, unsigned int mask)
+int NetlinkInterface::setChannelMask(int package, unsigned int mask)
 {
     lg2::debug(
         "Set Channel Mask , INTERFACE: {INTERFACE}, PACKAGE : {PACKAGE} MASK: {MASK}",
diff --git a/src/ncsi_util.hpp b/src/ncsi_util.hpp
index 0ca0df1..250c096 100644
--- a/src/ncsi_util.hpp
+++ b/src/ncsi_util.hpp
@@ -83,7 +83,26 @@
      * @param[in] payload - OEM data to send.
      * @returns the NCSI response message to this command, or no value on error.
      */
+    virtual std::optional<NCSIResponse> sendCommand(NCSICommand& cmd) = 0;
+
+    /**
+     * @brief Create a string representation of this interface
+     *
+     * @returns a string containing an interface identifier, for logging
+     */
+    virtual std::string toString() = 0;
+
+    /* virtual destructor for vtable */
+    virtual ~Interface() {};
+};
+
+std::string to_string(Interface& interface);
+
+struct NetlinkInterface : Interface
+{
+    /* implementations for Interface */
     std::optional<NCSIResponse> sendCommand(NCSICommand& cmd);
+    std::string toString();
 
     /* @brief  This function will ask underlying NCSI driver
      *         to set a specific  package or package/channel
@@ -129,11 +148,11 @@
      */
     int setChannelMask(int package, unsigned int mask);
 
+    NetlinkInterface(int ifindex);
+
     int ifindex;
 };
 
-std::string to_string(Interface& interface);
-
 } // namespace ncsi
 } // namespace network
 } // namespace phosphor