netd: Route MTU

- Route may include optional MTU parameter
- Change route is added so routes don't need to be deleted then re-added
- Add/Del/Change functions to pass route info as parcel

Bug: 142892223
Test: new unit tests
Change-Id: Idc32ecb0520b1f4136b3fe0e3f7b6800fb3005a6
diff --git a/server/RouteController.cpp b/server/RouteController.cpp
index a62ed6b..c4c3cfb 100644
--- a/server/RouteController.cpp
+++ b/server/RouteController.cpp
@@ -118,6 +118,13 @@
 rtattr RTATTR_OIF       = { U16_RTA_LENGTH(sizeof(uint32_t)),           RTA_OIF };
 rtattr RTATTR_PRIO      = { U16_RTA_LENGTH(sizeof(uint32_t)),           RTA_PRIORITY };
 
+// One or more nested attributes in the RTA_METRICS attribute.
+rtattr RTATTRX_MTU      = { U16_RTA_LENGTH(sizeof(uint32_t)),           RTAX_MTU};
+
+// The RTA_METRICS attribute itself.
+constexpr int RTATTR_METRICS_SIZE = sizeof(RTATTRX_MTU) + sizeof(uint32_t);
+rtattr RTATTR_METRICS   = { U16_RTA_LENGTH(RTATTR_METRICS_SIZE),         RTA_METRICS };
+
 uint8_t PADDING_BUFFER[RTA_ALIGNTO] = {0, 0, 0, 0};
 
 // END CONSTANTS ----------------------------------------------------------------------------------
@@ -339,8 +346,8 @@
 
 // Adds or deletes an IPv4 or IPv6 route.
 // Returns 0 on success or negative errno on failure.
-int modifyIpRoute(uint16_t action, uint32_t table, const char* interface, const char* destination,
-                  const char* nexthop) {
+int modifyIpRoute(uint16_t action, uint16_t flags, uint32_t table, const char* interface,
+                  const char* destination, const char* nexthop, uint32_t mtu) {
     // At least the destination must be non-null.
     if (!destination) {
         ALOGE("null destination");
@@ -410,22 +417,23 @@
     rtattr rtaGateway = { U16_RTA_LENGTH(rawLength), RTA_GATEWAY };
 
     iovec iov[] = {
-        { nullptr,          0 },
-        { &route,        sizeof(route) },
-        { &RTATTR_TABLE, sizeof(RTATTR_TABLE) },
-        { &table,        sizeof(table) },
-        { &rtaDst,       sizeof(rtaDst) },
-        { rawAddress,    static_cast<size_t>(rawLength) },
-        { &RTATTR_OIF,   interface != OIF_NONE ? sizeof(RTATTR_OIF) : 0 },
-        { &ifindex,      interface != OIF_NONE ? sizeof(ifindex) : 0 },
-        { &rtaGateway,   nexthop ? sizeof(rtaGateway) : 0 },
-        { rawNexthop,    nexthop ? static_cast<size_t>(rawLength) : 0 },
-        { &RTATTR_PRIO,  isDefaultThrowRoute ? sizeof(RTATTR_PRIO) : 0 },
-        { &PRIO_THROW,   isDefaultThrowRoute ? sizeof(PRIO_THROW) : 0 },
+        { nullptr,         0 },
+        { &route,          sizeof(route) },
+        { &RTATTR_TABLE,   sizeof(RTATTR_TABLE) },
+        { &table,          sizeof(table) },
+        { &rtaDst,         sizeof(rtaDst) },
+        { rawAddress,      static_cast<size_t>(rawLength) },
+        { &RTATTR_OIF,     interface != OIF_NONE ? sizeof(RTATTR_OIF) : 0 },
+        { &ifindex,        interface != OIF_NONE ? sizeof(ifindex) : 0 },
+        { &rtaGateway,     nexthop ? sizeof(rtaGateway) : 0 },
+        { rawNexthop,      nexthop ? static_cast<size_t>(rawLength) : 0 },
+        { &RTATTR_METRICS, mtu != 0 ? sizeof(RTATTR_METRICS) : 0 },
+        { &RTATTRX_MTU,    mtu != 0 ? sizeof(RTATTRX_MTU) : 0 },
+        { &mtu,            mtu != 0 ? sizeof(mtu) : 0 },
+        { &RTATTR_PRIO,    isDefaultThrowRoute ? sizeof(RTATTR_PRIO) : 0 },
+        { &PRIO_THROW,     isDefaultThrowRoute ? sizeof(PRIO_THROW) : 0 },
     };
 
-    uint16_t flags = (action == RTM_NEWROUTE) ? NETLINK_ROUTE_CREATE_FLAGS : NETLINK_REQUEST_FLAGS;
-
     // Allow creating multiple link-local routes in the same table, so we can make IPv6
     // work on all interfaces in the local_network table.
     if (family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(reinterpret_cast<in6_addr*>(rawAddress))) {
@@ -697,11 +705,13 @@
         return ret;
     }
 
-    if ((ret = modifyIpRoute(RTM_NEWROUTE, table, interface, "0.0.0.0/0", nullptr))) {
+    if ((ret = modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table, interface,
+                             "0.0.0.0/0", nullptr, 0 /* mtu */))) {
         return ret;
     }
 
-    if ((ret = modifyIpRoute(RTM_NEWROUTE, table, interface, "::/0", nullptr))) {
+    if ((ret = modifyIpRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, table, interface, "::/0",
+                             nullptr, 0 /* mtu */))) {
         return ret;
     }
 
@@ -859,8 +869,9 @@
 
 // Adds or removes an IPv4 or IPv6 route to the specified table.
 // Returns 0 on success or negative errno on failure.
-int RouteController::modifyRoute(uint16_t action, const char* interface, const char* destination,
-                                 const char* nexthop, TableType tableType) {
+int RouteController::modifyRoute(uint16_t action, uint16_t flags, const char* interface,
+                                 const char* destination, const char* nexthop, TableType tableType,
+                                 int mtu) {
     uint32_t table;
     switch (tableType) {
         case RouteController::INTERFACE: {
@@ -884,7 +895,7 @@
         }
     }
 
-    int ret = modifyIpRoute(action, table, interface, destination, nexthop);
+    int ret = modifyIpRoute(action, flags, table, interface, destination, nexthop, mtu);
     // Trying to add a route that already exists shouldn't cause an error.
     if (ret && !(action == RTM_NEWROUTE && ret == -EEXIST)) {
         return ret;
@@ -1066,13 +1077,21 @@
 }
 
 int RouteController::addRoute(const char* interface, const char* destination, const char* nexthop,
-                              TableType tableType) {
-    return modifyRoute(RTM_NEWROUTE, interface, destination, nexthop, tableType);
+                              TableType tableType, int mtu) {
+    return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_CREATE_FLAGS, interface, destination, nexthop,
+                       tableType, mtu);
 }
 
 int RouteController::removeRoute(const char* interface, const char* destination,
                                  const char* nexthop, TableType tableType) {
-    return modifyRoute(RTM_DELROUTE, interface, destination, nexthop, tableType);
+    return modifyRoute(RTM_DELROUTE, NETLINK_REQUEST_FLAGS, interface, destination, nexthop,
+                       tableType, 0);
+}
+
+int RouteController::updateRoute(const char* interface, const char* destination,
+                                 const char* nexthop, TableType tableType, int mtu) {
+    return modifyRoute(RTM_NEWROUTE, NETLINK_ROUTE_REPLACE_FLAGS, interface, destination, nexthop,
+                       tableType, mtu);
 }
 
 int RouteController::enableTethering(const char* inputInterface, const char* outputInterface) {