Add support for MTU property

This commit add support for the MTU property,
which shows the maximum size of the Protocol Data Uint (PDU) in bytes,
that can be passed in an Ethernet frame on the network interface.

We can Get or Set the MTU Size of any interface.
Also this property helps to populate MTUSize in Redfish.

The backend DBus interface code is committed to below location -
https://gerrit.openbmc-project.xyz/c/openbmc/phosphor-dbus-interfaces/+/45033

Tested:

Verified the property with dbus tool for Get, Set operations.

busctl introspect xyz.openbmc_project.Network /xyz/openbmc_project/network/eth3
NAME						TYPE		SIGNATURE RESULT/VALUE
xyz.openbmc_project.Network.EthernetInterface	interface	-	  -
.MTU						property	u	  1500

dbus-send --system --print-reply --dest="xyz.openbmc_project.Network" "/xyz/openbmc_project/network/eth3" org.freedesktop.DBus.Properties.Get string:"xyz.openbmc_project.Network.EthernetInterface" string:"MTU"
method return time=1627365497.929314 sender=:1.39 -> destination=:1.46740 serial=3219493 reply_serial=2
    variant       uint32 1500

dbus-send --system --print-reply --dest="xyz.openbmc_project.Network" "/xyz/openbmc_project/network/eth3" org.freedesktop.DBus.Properties.Set string:"xyz.openbmc_project.Network.EthernetInterface" string:"MTU" variant:uint32:1480
method return time=1627365546.988526 sender=:1.39 -> destination=:1.46751 serial=3219999 reply_serial=2

dbus-send --system --print-reply --dest="xyz.openbmc_project.Network" "/xyz/openbmc_project/network/eth3" org.freedesktop.DBus.Properties.Get string:"xyz.openbmc_project.Network.EthernetInterface" string:"MTU"
method return time=1627365561.546701 sender=:1.39 -> destination=:1.46754 serial=3220200 reply_serial=2
    variant       uint32 1480

Signed-off-by: Tejas Patil <tejaspp@ami.com>
Change-Id: I1f501d89d0853467357751577e0c9a4d35f843cc
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index fc0550f..504090f 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -126,6 +126,7 @@
     EthernetInterfaceIntf::ntpServers(getNTPServersFromConf());
 
     EthernetInterfaceIntf::linkUp(linkUp());
+    EthernetInterfaceIntf::mtu(mtu());
 
 #ifdef NIC_SUPPORTS_ETHTOOL
     InterfaceInfo ifInfo = EthernetInterface::getInterfaceInfo();
@@ -369,11 +370,13 @@
     DuplexMode duplex = {};
     LinkUp linkState = {};
     NICEnabled enabled = {};
+    MTU mtuSize = {};
     EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
 
     if (eifSocket.sock < 0)
     {
-        return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
+        return std::make_tuple(speed, duplex, autoneg, linkState, enabled,
+                               mtuSize);
     }
 
     std::strncpy(ifr.ifr_name, interfaceName().c_str(), IFNAMSIZ - 1);
@@ -389,8 +392,9 @@
 
     enabled = nicEnabled();
     linkState = linkUp();
+    mtuSize = mtu();
 
-    return std::make_tuple(speed, duplex, autoneg, linkState, enabled);
+    return std::make_tuple(speed, duplex, autoneg, linkState, enabled, mtuSize);
 }
 #endif
 
@@ -602,6 +606,62 @@
     return value;
 }
 
+size_t EthernetInterface::mtu() const
+{
+    EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+    size_t value = EthernetInterfaceIntf::mtu();
+
+    if (eifSocket.sock < 0)
+    {
+        return value;
+    }
+
+    ifreq ifr = {};
+    std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
+    if (ioctl(eifSocket.sock, SIOCGIFMTU, &ifr) == 0)
+    {
+        value = ifr.ifr_mtu;
+    }
+    else
+    {
+        log<level::ERR>("ioctl failed for SIOCGIFMTU:",
+                        entry("ERROR=%s", strerror(errno)));
+    }
+    return value;
+}
+
+size_t EthernetInterface::mtu(size_t value)
+{
+    if (value == EthernetInterfaceIntf::mtu())
+    {
+        return value;
+    }
+    else if (value == 0)
+    {
+        return EthernetInterfaceIntf::mtu();
+    }
+
+    EthernetIntfSocket eifSocket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+    if (eifSocket.sock < 0)
+    {
+        return EthernetInterfaceIntf::mtu();
+    }
+
+    ifreq ifr = {};
+    std::strncpy(ifr.ifr_name, interfaceName().c_str(), IF_NAMESIZE - 1);
+    ifr.ifr_mtu = value;
+
+    if (ioctl(eifSocket.sock, SIOCSIFMTU, &ifr) != 0)
+    {
+        log<level::ERR>("ioctl failed for SIOCSIFMTU:",
+                        entry("ERROR=%s", strerror(errno)));
+        return EthernetInterfaceIntf::mtu();
+    }
+    EthernetInterfaceIntf::mtu(value);
+
+    return value;
+}
+
 bool EthernetInterface::queryNicEnabled() const
 {
     constexpr auto svc = "org.freedesktop.network1";
diff --git a/src/ethernet_interface.hpp b/src/ethernet_interface.hpp
index 8256954..0fe3778 100644
--- a/src/ethernet_interface.hpp
+++ b/src/ethernet_interface.hpp
@@ -52,10 +52,11 @@
 using Autoneg = uint8_t;
 using LinkUp = bool;
 using NICEnabled = bool;
+using MTU = size_t;
 using VlanId = uint32_t;
 using InterfaceName = std::string;
 using InterfaceInfo =
-    std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp, NICEnabled>;
+    std::tuple<LinkSpeed, DuplexMode, Autoneg, LinkUp, NICEnabled, MTU>;
 using AddressMap = std::map<std::string, std::shared_ptr<IPAddress>>;
 using NeighborMap = std::map<std::string, std::shared_ptr<Neighbor>>;
 using VlanInterfaceMap =
@@ -168,6 +169,12 @@
     /** Retrieve Link State */
     bool linkUp() const override;
 
+    /** Retrieve MTU Size */
+    size_t mtu() const override;
+
+    /** Set size of MTU */
+    size_t mtu(size_t value) override;
+
     /** Set value of NICEnabled */
     bool nicEnabled(bool value) override;
 
@@ -235,6 +242,7 @@
     using EthernetInterfaceIntf::dhcpEnabled;
     using EthernetInterfaceIntf::interfaceName;
     using EthernetInterfaceIntf::linkUp;
+    using EthernetInterfaceIntf::mtu;
     using EthernetInterfaceIntf::nicEnabled;
     using MacAddressIntf::macAddress;