Adding XFRM mark support for xfrm global policy

The xfrm mark will be sent to kernel in XFRMA_MARK netlink
attribute.

Bug: 63589600
Test: runtest -x server/netd_unit_test.cpp
Change-Id: If2d2fdda2d0b3959ed79a3b948b033d76e4236aa
diff --git a/server/XfrmControllerTest.cpp b/server/XfrmControllerTest.cpp
index 762bede..46ef6e4 100644
--- a/server/XfrmControllerTest.cpp
+++ b/server/XfrmControllerTest.cpp
@@ -102,6 +102,8 @@
 static constexpr int DROID_SPI = 0xD1201D;
 static constexpr size_t KEY_LENGTH = 32;
 static constexpr int NLMSG_DEFAULTSIZE = 8192;
+static constexpr uint32_t TEST_XFRM_MARK = 0x123;
+static constexpr uint32_t TEST_XFRM_MASK = 0xFFFFFFFF;
 
 static constexpr char LOCALHOST_V4[] = "127.0.0.1";
 static constexpr char LOCALHOST_V6[] = "::1";
@@ -277,7 +279,8 @@
     size_t expectedMsgLength =
         NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_usersa_info)) +
         NLA_ALIGN(offsetof(XfrmController::nlattr_algo_crypt, key) + KEY_LENGTH) +
-        NLA_ALIGN(offsetof(XfrmController::nlattr_algo_auth, key) + KEY_LENGTH);
+        NLA_ALIGN(offsetof(XfrmController::nlattr_algo_auth, key) + KEY_LENGTH) +
+        NLA_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
 
     std::vector<uint8_t> nlMsgBuf;
     EXPECT_CALL(mockSyscalls, writev(_, _))
@@ -288,10 +291,10 @@
     XfrmController ctrl;
     Status res = ctrl.ipSecAddSecurityAssociation(
         1 /* resourceId */, static_cast<int>(mode), localAddr, remoteAddr,
-        0 /* underlying network */, DROID_SPI, "hmac(sha256)" /* auth algo */,
-        authKey, 128 /* auth trunc length */, "cbc(aes)" /* encryption algo */, cryptKey,
-        0 /* crypt trunc length? */, "" /* AEAD algo */, {}, 0,
-        static_cast<int>(XfrmEncapType::NONE), 0 /* local port */, 0 /* remote port */);
+        0 /* underlying network */, DROID_SPI, TEST_XFRM_MARK /* mark */, TEST_XFRM_MASK /* mask */,
+        "hmac(sha256)" /* auth algo */, authKey, 128 /* auth trunc length */,
+        "cbc(aes)" /* encryption algo */, cryptKey, 0 /* crypt trunc length? */, "" /* AEAD algo */,
+        {}, 0, static_cast<int>(XfrmEncapType::NONE), 0 /* local port */, 0 /* remote port */);
 
     EXPECT_TRUE(isOk(res)) << res;
     EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -324,7 +327,9 @@
     // Extract and check the encryption/authentication algorithm
     XfrmController::nlattr_algo_crypt encryptAlgo{};
     XfrmController::nlattr_algo_auth authAlgo{};
-    auto attrHandler = [&encryptAlgo, &authAlgo](const nlattr& attr, const Slice& attr_payload) {
+    XfrmController::nlattr_xfrm_mark mark{};
+    auto attrHandler = [&encryptAlgo, &authAlgo, &mark](const nlattr& attr,
+                                                        const Slice& attr_payload) {
         Slice buf = attr_payload;
         if (attr.nla_type == XFRMA_ALG_CRYPT) {
             encryptAlgo.hdr = attr;
@@ -336,6 +341,9 @@
             netdutils::extract(buf, authAlgo.auth);
             buf = drop(buf, sizeof(xfrm_algo_auth));
             netdutils::extract(buf, authAlgo.key);
+        } else if (attr.nla_type == XFRMA_MARK) {
+            mark.hdr = attr;
+            netdutils::extract(buf, mark.mark);
         } else {
             FAIL() << "Unexpected nlattr type: " << attr.nla_type;
         }
@@ -347,6 +355,8 @@
                         reinterpret_cast<void*>(&encryptAlgo.key), KEY_LENGTH));
     EXPECT_EQ(0, memcmp(reinterpret_cast<void*>(authKey.data()),
                         reinterpret_cast<void*>(&authAlgo.key), KEY_LENGTH));
+    EXPECT_EQ(TEST_XFRM_MARK, mark.mark.v);
+    EXPECT_EQ(TEST_XFRM_MASK, mark.mark.m);
 }
 
 TEST_P(XfrmControllerParameterizedTest, TestTransportModeIpSecAddSecurityAssociation) {
@@ -371,7 +381,7 @@
     XfrmController ctrl;
     Status res = ctrl.ipSecAddSecurityAssociation(
         1, static_cast<int>(XfrmMode::TRANSPORT),
-        LOCALHOST_V6, TEST_ADDR_V6, 0, DROID_SPI, "hmac(sha256)", {}, 128, "cbc(aes)",
+        LOCALHOST_V6, TEST_ADDR_V6, 0, DROID_SPI, 0, 0, "hmac(sha256)", {}, 128, "cbc(aes)",
         {}, 0, "", {}, 0, static_cast<int>(XfrmEncapType::ESPINUDP_NON_IKE), 0, 0);
 
     EXPECT_FALSE(isOk(res)) << "IPv6 UDP encap not rejected";
@@ -471,10 +481,11 @@
     const std::string remoteAddr = (version == 6) ? TEST_ADDR_V6 : TEST_ADDR_V4;
 
     NetlinkResponse response{};
-    response.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI;
+    response.hdr.nlmsg_type = XFRM_MSG_DELSA;
     Slice responseSlice = netdutils::makeSlice(response);
 
-    size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_usersa_id));
+    size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_usersa_id)) +
+                               NLA_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
 
     std::vector<uint8_t> nlMsgBuf;
     EXPECT_CALL(mockSyscalls, writev(_, _))
@@ -483,8 +494,8 @@
         .WillOnce(DoAll(SetArgSlice<1>(responseSlice), Return(responseSlice)));
 
     XfrmController ctrl;
-    Status res = ctrl.ipSecDeleteSecurityAssociation(
-        1 /* resourceId */, localAddr, remoteAddr, DROID_SPI);
+    Status res = ctrl.ipSecDeleteSecurityAssociation(1 /* resourceId */, localAddr, remoteAddr,
+                                                     DROID_SPI, TEST_XFRM_MARK, TEST_XFRM_MASK);
 
     EXPECT_TRUE(isOk(res)) << res;
     EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -510,7 +521,8 @@
     Slice responseSlice = netdutils::makeSlice(response);
 
     size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_userpolicy_info)) +
-                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_user_tmpl));
+                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_user_tmpl)) +
+                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
 
     std::vector<uint8_t> nlMsgBuf;
     EXPECT_CALL(mockSyscalls, writev(_, _))
@@ -519,9 +531,9 @@
         .WillOnce(DoAll(SetArgSlice<1>(responseSlice), Return(responseSlice)));
 
     XfrmController ctrl;
-    Status res =
-        ctrl.ipSecAddSecurityPolicy(1 /* resourceId */, static_cast<int>(XfrmDirection::OUT),
-                                    localAddr, remoteAddr, 0 /* SPI */);
+    Status res = ctrl.ipSecAddSecurityPolicy(
+        1 /* resourceId */, static_cast<int>(XfrmDirection::OUT), localAddr, remoteAddr,
+        0 /* SPI */, TEST_XFRM_MARK, TEST_XFRM_MASK);
 
     EXPECT_TRUE(isOk(res)) << res;
     EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -540,13 +552,17 @@
     // Drop the user policy info.
     Slice attr_buf = drop(nlMsgSlice, NLA_ALIGN(sizeof(xfrm_userpolicy_info)));
 
-    // Extract and check the user tmpl.
+    // Extract and check the user tmpl and mark.
     XfrmController::nlattr_user_tmpl usertmpl{};
-    auto attrHandler = [&usertmpl](const nlattr& attr, const Slice& attr_payload) {
+    XfrmController::nlattr_xfrm_mark mark{};
+    auto attrHandler = [&usertmpl, &mark](const nlattr& attr, const Slice& attr_payload) {
         Slice buf = attr_payload;
         if (attr.nla_type == XFRMA_TMPL) {
             usertmpl.hdr = attr;
             netdutils::extract(buf, usertmpl.tmpl);
+        } else if (attr.nla_type == XFRMA_MARK) {
+            mark.hdr = attr;
+            netdutils::extract(buf, mark.mark);
         } else {
             FAIL() << "Unexpected nlattr type: " << attr.nla_type;
         }
@@ -554,6 +570,9 @@
     forEachNetlinkAttribute(attr_buf, attrHandler);
 
     expectAddressEquals(family, remoteAddr, usertmpl.tmpl.id.daddr);
+    EXPECT_EQ(TEST_XFRM_MARK, mark.mark.v);
+    EXPECT_EQ(TEST_XFRM_MASK, mark.mark.m);
+
 }
 
 TEST_P(XfrmControllerParameterizedTest, TestIpSecUpdateSecurityPolicy) {
@@ -566,7 +585,8 @@
     Slice responseSlice = netdutils::makeSlice(response);
 
     size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_userpolicy_info)) +
-                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_user_tmpl));
+                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_user_tmpl)) +
+                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
 
     std::vector<uint8_t> nlMsgBuf;
     EXPECT_CALL(mockSyscalls, writev(_, _))
@@ -575,9 +595,9 @@
         .WillOnce(DoAll(SetArgSlice<1>(responseSlice), Return(responseSlice)));
 
     XfrmController ctrl;
-    Status res =
-        ctrl.ipSecUpdateSecurityPolicy(1 /* resourceId */, static_cast<int>(XfrmDirection::OUT),
-                                       localAddr, remoteAddr, 0 /* SPI */);
+    Status res = ctrl.ipSecUpdateSecurityPolicy(
+        1 /* resourceId */, static_cast<int>(XfrmDirection::OUT), localAddr, remoteAddr,
+        0 /* SPI */, 0 /* Mark */, 0 /* Mask */);
 
     EXPECT_TRUE(isOk(res)) << res;
     EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -597,7 +617,8 @@
     response.hdr.nlmsg_type = XFRM_MSG_DELPOLICY;
     Slice responseSlice = netdutils::makeSlice(response);
 
-    size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_userpolicy_id));
+    size_t expectedMsgLength = NLMSG_HDRLEN + NLMSG_ALIGN(sizeof(xfrm_userpolicy_id)) +
+                               NLMSG_ALIGN(sizeof(XfrmController::nlattr_xfrm_mark));
 
     std::vector<uint8_t> nlMsgBuf;
     EXPECT_CALL(mockSyscalls, writev(_, _))
@@ -606,9 +627,9 @@
         .WillOnce(DoAll(SetArgSlice<1>(responseSlice), Return(responseSlice)));
 
     XfrmController ctrl;
-    Status res =
-        ctrl.ipSecDeleteSecurityPolicy(1 /* resourceId */, static_cast<int>(XfrmDirection::OUT),
-                                       localAddr, remoteAddr);
+    Status res = ctrl.ipSecDeleteSecurityPolicy(
+        1 /* resourceId */, static_cast<int>(XfrmDirection::OUT), localAddr, remoteAddr,
+        TEST_XFRM_MARK, TEST_XFRM_MASK);
 
     EXPECT_TRUE(isOk(res)) << res;
     EXPECT_EQ(expectedMsgLength, nlMsgBuf.size());
@@ -620,6 +641,15 @@
     netdutils::extract(nlMsgSlice, policyid);
 
     EXPECT_EQ(static_cast<uint8_t>(XfrmDirection::OUT), policyid.dir);
+
+    // Drop the user policy id.
+    nlMsgSlice = drop(nlMsgSlice, NLA_ALIGN(sizeof(xfrm_userpolicy_id)));
+    // Extract and check the mark.
+    XfrmController::nlattr_xfrm_mark mark{};
+    netdutils::extract(nlMsgSlice, mark);
+    EXPECT_EQ(TEST_XFRM_MARK, mark.mark.v);
+    EXPECT_EQ(TEST_XFRM_MASK, mark.mark.m);
+
 }
 
 } // namespace net