ethernet_interface: Merge VLAN into EthernetInterface

This simplifies the ethernet interface as it codepended on the vlan
interface to make VLANs. It also removes the naming dependency and
tracks VLANs by adapter type and parent indexes.

Change-Id: I8db09cc2474472e6d4a06c6be5cf0440ee48d132
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/system_queries.cpp b/src/system_queries.cpp
index 0152f4a..f0222ec 100644
--- a/src/system_queries.cpp
+++ b/src/system_queries.cpp
@@ -125,6 +125,47 @@
     getIFSock().ioctl(SIOCSIFFLAGS, &ifr);
 }
 
+static void parseVlanInfo(InterfaceInfo& info, std::string_view msg)
+{
+    if (msg.data() == nullptr)
+    {
+        throw std::runtime_error("Missing VLAN data");
+    }
+    while (!msg.empty())
+    {
+        auto [hdr, data] = netlink::extractRtAttr(msg);
+        switch (hdr.rta_type)
+        {
+            case IFLA_VLAN_ID:
+                info.vlan_id.emplace(stdplus::raw::copyFrom<uint16_t>(data));
+                break;
+        }
+    }
+}
+
+static void parseLinkInfo(InterfaceInfo& info, std::string_view msg)
+{
+    std::string_view submsg;
+    while (!msg.empty())
+    {
+        auto [hdr, data] = netlink::extractRtAttr(msg);
+        switch (hdr.rta_type)
+        {
+            case IFLA_INFO_KIND:
+                data.remove_suffix(1);
+                info.kind.emplace(data);
+                break;
+            case IFLA_INFO_DATA:
+                submsg = data;
+                break;
+        }
+    }
+    if (info.kind == "vlan"sv)
+    {
+        parseVlanInfo(info, submsg);
+    }
+}
+
 InterfaceInfo detail::parseInterface(const nlmsghdr& hdr, std::string_view msg)
 {
     if (hdr.nlmsg_type != RTM_NEWLINK)
@@ -138,22 +179,28 @@
     while (!msg.empty())
     {
         auto [hdr, data] = netlink::extractRtAttr(msg);
-        if (hdr.rta_type == IFLA_IFNAME)
+        switch (hdr.rta_type)
         {
-            ret.name.emplace(data.begin(), data.end() - 1);
-        }
-        else if (hdr.rta_type == IFLA_ADDRESS)
-        {
-            if (data.size() != sizeof(ether_addr))
-            {
-                // Some interfaces have IP addresses for their LLADDR
-                continue;
-            }
-            ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data));
-        }
-        else if (hdr.rta_type == IFLA_MTU)
-        {
-            ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
+            case IFLA_IFNAME:
+                ret.name.emplace(data.begin(), data.end() - 1);
+                break;
+            case IFLA_ADDRESS:
+                if (data.size() != sizeof(ether_addr))
+                {
+                    // Some interfaces have IP addresses for their LLADDR
+                    break;
+                }
+                ret.mac.emplace(stdplus::raw::copyFrom<ether_addr>(data));
+                break;
+            case IFLA_MTU:
+                ret.mtu.emplace(stdplus::raw::copyFrom<unsigned>(data));
+                break;
+            case IFLA_LINK:
+                ret.parent_idx.emplace(stdplus::raw::copyFrom<unsigned>(data));
+                break;
+            case IFLA_LINKINFO:
+                parseLinkInfo(ret, data);
+                break;
         }
     }
     return ret;