blob: 094319f8403d7506264cbf9b90fd2bb0031abf30 [file] [log] [blame]
Garrick Evans54861622019-07-19 09:05:09 +09001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Garrick Evans3388a032020-03-24 11:25:55 +09005#include "patchpanel/arc_service.h"
Garrick Evans54861622019-07-19 09:05:09 +09006
Garrick Evanse94b6de2020-02-20 09:19:13 +09007#include <net/if.h>
8
Garrick Evans54861622019-07-19 09:05:09 +09009#include <utility>
10#include <vector>
11
12#include <base/bind.h>
13
14#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
Garrick Evans3388a032020-03-24 11:25:55 +090017#include "patchpanel/address_manager.h"
18#include "patchpanel/fake_process_runner.h"
19#include "patchpanel/fake_shill_client.h"
20#include "patchpanel/mock_datapath.h"
21#include "patchpanel/net_util.h"
Garrick Evans54861622019-07-19 09:05:09 +090022
23using testing::_;
Garrick Evanse94b6de2020-02-20 09:19:13 +090024using testing::AnyNumber;
Garrick Evansc7071122020-04-17 12:31:57 +090025using testing::Eq;
26using testing::Pointee;
Garrick Evans54861622019-07-19 09:05:09 +090027using testing::Return;
Garrick Evansb4eb3892019-11-13 12:07:07 +090028using testing::ReturnRef;
Garrick Evans54861622019-07-19 09:05:09 +090029using testing::StrEq;
30
Garrick Evans3388a032020-03-24 11:25:55 +090031namespace patchpanel {
Garrick Evans54861622019-07-19 09:05:09 +090032namespace {
Garrick Evansb4eb3892019-11-13 12:07:07 +090033constexpr pid_t kTestPID = -2;
Garrick Evansb4eb3892019-11-13 12:07:07 +090034constexpr uint32_t kTestCID = 2;
Garrick Evans7a1a9ee2020-01-28 11:03:57 +090035constexpr uint32_t kArcHostIP = Ipv4Addr(100, 115, 92, 1);
36constexpr uint32_t kArcGuestIP = Ipv4Addr(100, 115, 92, 2);
Hugo Benichiad1bdd92020-06-12 13:48:37 +090037constexpr uint32_t kFirstEthHostIP = Ipv4Addr(100, 115, 92, 5);
38constexpr uint32_t kFirstEthGuestIP = Ipv4Addr(100, 115, 92, 6);
Garrick Evans86c7d9c2020-03-17 09:25:48 +090039constexpr uint32_t kSecondEthHostIP = Ipv4Addr(100, 115, 92, 9);
40constexpr uint32_t kFirstWifiHostIP = Ipv4Addr(100, 115, 92, 13);
41constexpr uint32_t kSecondWifiHostIP = Ipv4Addr(100, 115, 92, 17);
42constexpr uint32_t kFirstCellHostIP = Ipv4Addr(100, 115, 92, 21);
Garrick Evansc7071122020-04-17 12:31:57 +090043constexpr MacAddress kArcVmArc0MacAddr = {0x42, 0x37, 0x05, 0x13, 0x17, 0x01};
Garrick Evans54861622019-07-19 09:05:09 +090044
Garrick Evans2e5c9ab2020-03-05 14:33:58 +090045class MockTrafficForwarder : public TrafficForwarder {
46 public:
47 MockTrafficForwarder() = default;
48 ~MockTrafficForwarder() = default;
49
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +090050 MOCK_METHOD4(StartForwarding,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +090051 void(const std::string& ifname_physical,
52 const std::string& ifname_virtual,
Garrick Evans2e5c9ab2020-03-05 14:33:58 +090053 bool ipv6,
54 bool multicast));
55
56 MOCK_METHOD4(StopForwarding,
57 void(const std::string& ifname_physical,
58 const std::string& ifname_virtual,
59 bool ipv6,
60 bool multicast));
61};
62
Garrick Evans54861622019-07-19 09:05:09 +090063} // namespace
64
65class ArcServiceTest : public testing::Test {
66 public:
Garrick Evans4ee5ce22020-03-18 07:05:17 +090067 ArcServiceTest() : testing::Test() {}
Garrick Evans54861622019-07-19 09:05:09 +090068
69 protected:
70 void SetUp() override {
Taoyu Li179dcc62019-10-17 11:21:08 +090071 runner_ = std::make_unique<FakeProcessRunner>();
Garrick Evans54861622019-07-19 09:05:09 +090072 runner_->Capture(false);
Taoyu Li179dcc62019-10-17 11:21:08 +090073 datapath_ = std::make_unique<MockDatapath>(runner_.get());
Garrick Evans69b85872020-02-04 11:40:26 +090074 shill_client_ = shill_helper_.Client();
Garrick Evans4ee5ce22020-03-18 07:05:17 +090075 addr_mgr_ = std::make_unique<AddressManager>();
Garrick Evans54861622019-07-19 09:05:09 +090076 }
77
Hugo Benichiad1bdd92020-06-12 13:48:37 +090078 std::unique_ptr<ArcService> NewService(GuestMessage::GuestType guest) {
Garrick Evans6e4eb3b2020-03-09 07:18:31 +090079 return std::make_unique<ArcService>(shill_client_.get(), datapath_.get(),
Hugo Benichiad1bdd92020-06-12 13:48:37 +090080 addr_mgr_.get(), &forwarder_, guest);
Garrick Evans54861622019-07-19 09:05:09 +090081 }
82
Garrick Evans69b85872020-02-04 11:40:26 +090083 FakeShillClientHelper shill_helper_;
84 std::unique_ptr<ShillClient> shill_client_;
Garrick Evans4ee5ce22020-03-18 07:05:17 +090085 std::unique_ptr<AddressManager> addr_mgr_;
Garrick Evans2e5c9ab2020-03-05 14:33:58 +090086 MockTrafficForwarder forwarder_;
Taoyu Li179dcc62019-10-17 11:21:08 +090087 std::unique_ptr<MockDatapath> datapath_;
88 std::unique_ptr<FakeProcessRunner> runner_;
Garrick Evans54861622019-07-19 09:05:09 +090089};
90
Hugo Benichiad1bdd92020-06-12 13:48:37 +090091TEST_F(ArcServiceTest, NotStarted_AddDevice) {
92 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), _, _)).Times(0);
93 EXPECT_CALL(*datapath_, AddInboundIPv4DNAT(StrEq("eth0"), _)).Times(0);
94 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0"))).Times(0);
Garrick Evans54861622019-07-19 09:05:09 +090095
Hugo Benichiad1bdd92020-06-12 13:48:37 +090096 auto svc = NewService(GuestMessage::ARC);
Hugo Benichif0f10c72020-07-09 10:42:45 +090097 svc->OnDevicesChanged({"eth0"}, {});
98 EXPECT_TRUE(svc->devices_.find("eth0") == svc->devices_.end());
99 EXPECT_FALSE(svc->shill_devices_.find("eth0") == svc->shill_devices_.end());
Garrick Evans54861622019-07-19 09:05:09 +0900100}
101
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900102TEST_F(ArcServiceTest, NotStarted_AddRemoveDevice) {
103 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), _, _)).Times(0);
104 EXPECT_CALL(*datapath_, AddInboundIPv4DNAT(StrEq("eth0"), _)).Times(0);
105 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0"))).Times(0);
106 EXPECT_CALL(*datapath_, RemoveOutboundIPv4(StrEq("arc_eth0"))).Times(0);
107 EXPECT_CALL(*datapath_, RemoveInboundIPv4DNAT(StrEq("eth0"), _)).Times(0);
108 EXPECT_CALL(*datapath_, RemoveBridge(StrEq("arc_eth0"))).Times(0);
Garrick Evans54861622019-07-19 09:05:09 +0900109
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900110 auto svc = NewService(GuestMessage::ARC);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900111 svc->OnDevicesChanged({"eth0"}, {});
112 svc->OnDevicesChanged({}, {"eth0"});
Garrick Evans6e4eb3b2020-03-09 07:18:31 +0900113 EXPECT_TRUE(svc->devices_.find("eth0") == svc->devices_.end());
Hugo Benichif0f10c72020-07-09 10:42:45 +0900114 EXPECT_TRUE(svc->shill_devices_.find("eth0") == svc->shill_devices_.end());
Garrick Evans54861622019-07-19 09:05:09 +0900115}
116
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900117TEST_F(ArcServiceTest, VerifyAddrConfigs) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900118 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
119 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900120 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
121 .WillOnce(Return(true));
122 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900123 .WillOnce(Return(true));
124 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth1"), kSecondEthHostIP, 30))
125 .WillOnce(Return(true));
126 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_wlan0"), kFirstWifiHostIP, 30))
127 .WillOnce(Return(true));
128 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_wlan1"), kSecondWifiHostIP, 30))
129 .WillOnce(Return(true));
130 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_wwan0"), kFirstCellHostIP, 30))
131 .WillOnce(Return(true));
132 EXPECT_CALL(*datapath_, AddInboundIPv4DNAT(_, _))
133 .WillRepeatedly(Return(true));
Hugo Benichif0f10c72020-07-09 10:42:45 +0900134 EXPECT_CALL(*datapath_, AddOutboundIPv4(_)).WillRepeatedly(Return(true));
135 EXPECT_CALL(*datapath_, AddVirtualInterfacePair(StrEq("arc_netns"), _, _))
136 .WillRepeatedly(Return(true));
137 EXPECT_CALL(*datapath_, ToggleInterface(_, true))
138 .WillRepeatedly(Return(true));
139 EXPECT_CALL(*datapath_, ConfigureInterface(_, _, _, _, _, _))
140 .WillRepeatedly(Return(true));
141 EXPECT_CALL(*datapath_, AddToBridge(_, _)).WillRepeatedly(Return(true));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900142
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900143 auto svc = NewService(GuestMessage::ARC);
144 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900145 svc->OnDevicesChanged({"eth0", "eth1", "wlan0", "wlan1", "wwan0"}, {});
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900146}
147
148TEST_F(ArcServiceTest, VerifyAddrOrder) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900149 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
150 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900151 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
152 .WillOnce(Return(true));
153 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900154 .Times(2)
155 .WillRepeatedly(Return(true));
156 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_wlan0"), kFirstWifiHostIP, 30))
157 .WillOnce(Return(true));
158 EXPECT_CALL(*datapath_, AddInboundIPv4DNAT(_, _))
159 .WillRepeatedly(Return(true));
160 EXPECT_CALL(*datapath_, AddOutboundIPv4(_)).WillRepeatedly(Return(true));
Hugo Benichif0f10c72020-07-09 10:42:45 +0900161 EXPECT_CALL(*datapath_, AddVirtualInterfacePair(StrEq("arc_netns"), _, _))
162 .WillRepeatedly(Return(true));
163 EXPECT_CALL(*datapath_, ToggleInterface(_, true))
164 .WillRepeatedly(Return(true));
165 EXPECT_CALL(*datapath_, ConfigureInterface(_, _, _, _, _, _))
166 .WillRepeatedly(Return(true));
167 EXPECT_CALL(*datapath_, AddToBridge(_, _)).WillRepeatedly(Return(true));
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900168
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900169 auto svc = NewService(GuestMessage::ARC);
170 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900171 svc->OnDevicesChanged({"wlan0"}, {});
172 svc->OnDevicesChanged({"eth0"}, {});
173 svc->OnDevicesChanged({}, {"eth0"});
174 svc->OnDevicesChanged({"eth0"}, {});
Garrick Evans86c7d9c2020-03-17 09:25:48 +0900175}
176
Garrick Evansc7071122020-04-17 12:31:57 +0900177TEST_F(ArcServiceTest, StableArcVmMacAddrs) {
178 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
179 .WillRepeatedly(Return("vmtap"));
180 EXPECT_CALL(*datapath_, AddBridge(_, _, 30)).WillRepeatedly(Return(true));
181 EXPECT_CALL(*datapath_, AddToBridge(_, _)).WillRepeatedly(Return(true));
182
183 auto svc = NewService(GuestMessage::ARC_VM);
184 svc->Start(kTestCID);
185 auto configs = svc->GetDeviceConfigs();
186 EXPECT_EQ(configs.size(), 6);
187 auto mac_addr = kArcVmArc0MacAddr;
188 for (const auto* config : configs) {
189 EXPECT_EQ(config->mac_addr(), mac_addr);
190 mac_addr[5]++;
191 }
192}
193
Garrick Evansb4eb3892019-11-13 12:07:07 +0900194// ContainerImpl
195
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900196TEST_F(ArcServiceTest, ContainerImpl_Start) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900197 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
198 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900199 // Expectations for arc0 setup.
Garrick Evanse94b6de2020-02-20 09:19:13 +0900200 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
201 .WillOnce(Return(true));
Garrick Evansb4eb3892019-11-13 12:07:07 +0900202 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900203 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
204 StrEq("arc0")))
Garrick Evansb4eb3892019-11-13 12:07:07 +0900205 .WillOnce(Return(true));
Garrick Evans2470caa2020-03-04 14:15:41 +0900206 EXPECT_CALL(*datapath_,
207 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
208 .WillOnce(Return(true));
Garrick Evans2f581a02020-05-11 10:43:35 +0900209 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
Garrick Evans2470caa2020-03-04 14:15:41 +0900210 .WillOnce(Return(true));
Garrick Evans2f581a02020-05-11 10:43:35 +0900211 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
Garrick Evans2470caa2020-03-04 14:15:41 +0900212 .WillOnce(Return(true));
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900213 EXPECT_CALL(forwarder_, StartForwarding(_, _, _, _)).Times(0);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900214
215 auto svc = NewService(GuestMessage::ARC);
216 svc->Start(kTestPID);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900217}
218
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900219TEST_F(ArcServiceTest, ContainerImpl_FailsToCreateInterface) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900220 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
221 .WillOnce(Return(true));
Garrick Evans63378b32020-01-14 10:36:16 +0900222 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900223 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
224 StrEq("arc0")))
Garrick Evans2470caa2020-03-04 14:15:41 +0900225 .WillOnce(Return(false));
Hugo Benichif0f10c72020-07-09 10:42:45 +0900226
Garrick Evans2470caa2020-03-04 14:15:41 +0900227 EXPECT_CALL(*datapath_, ConfigureInterface(_, _, _, _, _, _)).Times(0);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900228 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true)).Times(0);
229 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30)).Times(0);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900230 EXPECT_CALL(*datapath_, RemoveBridge(_)).Times(0);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900231
232 auto svc = NewService(GuestMessage::ARC);
233 svc->Start(kTestPID);
Garrick Evans63378b32020-01-14 10:36:16 +0900234}
235
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900236TEST_F(ArcServiceTest, ContainerImpl_FailsToConfigureInterface) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900237 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
238 .WillOnce(Return(true));
Garrick Evansb4eb3892019-11-13 12:07:07 +0900239 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900240 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
241 StrEq("arc0")))
Garrick Evans63378b32020-01-14 10:36:16 +0900242 .WillOnce(Return(true));
Garrick Evans63378b32020-01-14 10:36:16 +0900243 EXPECT_CALL(*datapath_,
Garrick Evans2470caa2020-03-04 14:15:41 +0900244 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
Garrick Evans63378b32020-01-14 10:36:16 +0900245 .WillOnce(Return(false));
Hugo Benichif0f10c72020-07-09 10:42:45 +0900246
Garrick Evans2f581a02020-05-11 10:43:35 +0900247 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true)).Times(0);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900248 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30)).Times(0);
Garrick Evans63378b32020-01-14 10:36:16 +0900249 EXPECT_CALL(*datapath_, RemoveBridge(_)).Times(0);
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900250
251 auto svc = NewService(GuestMessage::ARC);
252 svc->Start(kTestPID);
Garrick Evans63378b32020-01-14 10:36:16 +0900253}
254
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900255TEST_F(ArcServiceTest, ContainerImpl_FailsToAddInterfaceToBridge) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900256 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
257 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900258 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
259 .WillOnce(Return(true));
260 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900261 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
262 StrEq("arc0")))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900263 .WillOnce(Return(true));
264 EXPECT_CALL(*datapath_,
265 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
266 .WillOnce(Return(true));
267 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
268 .WillOnce(Return(true));
269 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
270 .WillOnce(Return(false));
271
272 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vetharc0")));
273 EXPECT_CALL(*datapath_, RemoveBridge(_)).Times(0);
274
275 auto svc = NewService(GuestMessage::ARC);
276 svc->Start(kTestPID);
277}
278
279TEST_F(ArcServiceTest, ContainerImpl_OnStartDevice) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900280 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
281 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900282 // Expectations for arc0 setup.
283 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
284 .WillOnce(Return(true));
285 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900286 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
287 StrEq("arc0")))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900288 .WillOnce(Return(true));
289 EXPECT_CALL(*datapath_,
290 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
291 .WillOnce(Return(true));
292 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
293 .WillOnce(Return(true));
294 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
295 .WillOnce(Return(true));
296 // Expectations for eth0 setup.
297 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
298 .WillOnce(Return(true));
Garrick Evansb4eb3892019-11-13 12:07:07 +0900299 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900300 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetheth0"),
301 StrEq("eth0")))
Garrick Evansb4eb3892019-11-13 12:07:07 +0900302 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900303 EXPECT_CALL(*datapath_, ConfigureInterface(StrEq("eth0"), _, kFirstEthGuestIP,
304 30, true, _))
Garrick Evans2470caa2020-03-04 14:15:41 +0900305 .WillOnce(Return(true));
Garrick Evans2f581a02020-05-11 10:43:35 +0900306 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetheth0"), true))
Garrick Evans2470caa2020-03-04 14:15:41 +0900307 .WillOnce(Return(true));
Garrick Evans2f581a02020-05-11 10:43:35 +0900308 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vetheth0")))
Garrick Evans2470caa2020-03-04 14:15:41 +0900309 .WillOnce(Return(true));
Jason Jeremy Iman0e9f8262020-03-06 14:50:49 +0900310 EXPECT_CALL(forwarder_,
311 StartForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900312 EXPECT_CALL(
313 *datapath_,
314 AddInboundIPv4DNAT(StrEq("eth0"), IPv4AddressToString(kFirstEthGuestIP)))
315 .WillOnce(Return(true));
316 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0")))
317 .WillOnce(Return(true));
318
319 auto svc = NewService(GuestMessage::ARC);
320 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900321 svc->OnDevicesChanged({"eth0"}, {});
322}
323
324TEST_F(ArcServiceTest, ContainerImpl_StartAfterDevice) {
325 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
326 .WillOnce(Return(true));
327 // Expectations for arc0 setup.
328 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
329 .WillOnce(Return(true));
330 EXPECT_CALL(*datapath_,
331 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
332 StrEq("arc0")))
333 .WillOnce(Return(true));
334 EXPECT_CALL(*datapath_,
335 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
336 .WillOnce(Return(true));
337 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
338 .WillOnce(Return(true));
339 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
340 .WillOnce(Return(true));
341 // Expectations for eth0 setup.
342 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
343 .WillOnce(Return(true));
344 EXPECT_CALL(*datapath_,
345 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetheth0"),
346 StrEq("eth0")))
347 .WillOnce(Return(true));
348 EXPECT_CALL(*datapath_, ConfigureInterface(StrEq("eth0"), _, kFirstEthGuestIP,
349 30, true, _))
350 .WillOnce(Return(true));
351 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetheth0"), true))
352 .WillOnce(Return(true));
353 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vetheth0")))
354 .WillOnce(Return(true));
355 EXPECT_CALL(forwarder_,
356 StartForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
357 EXPECT_CALL(
358 *datapath_,
359 AddInboundIPv4DNAT(StrEq("eth0"), IPv4AddressToString(kFirstEthGuestIP)))
360 .WillOnce(Return(true));
361 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0")))
362 .WillOnce(Return(true));
363
364 auto svc = NewService(GuestMessage::ARC);
365 svc->OnDevicesChanged({"eth0"}, {});
366 svc->Start(kTestPID);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900367}
368
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900369TEST_F(ArcServiceTest, ContainerImpl_Stop) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900370 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
371 .WillOnce(Return(true));
372 EXPECT_CALL(*datapath_, NetnsDeleteName(StrEq("arc_netns")))
373 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900374 // Expectations for arc0 setup.
375 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
376 .WillOnce(Return(true));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900377 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900378 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
379 StrEq("arc0")))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900380 .WillOnce(Return(true));
381 EXPECT_CALL(*datapath_,
382 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
383 .WillOnce(Return(true));
384 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
385 .WillOnce(Return(true));
386 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
387 .WillOnce(Return(true));
388 // Expectations for arc0 teardown.
389 EXPECT_CALL(*datapath_,
390 MaskInterfaceFlags(StrEq("arcbr0"), IFF_DEBUG, IFF_UP))
391 .WillOnce(Return(true));
Garrick Evans2f581a02020-05-11 10:43:35 +0900392 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vetharc0")));
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900393 EXPECT_CALL(forwarder_, StopForwarding(_, _, _, _)).Times(0);
Garrick Evanse94b6de2020-02-20 09:19:13 +0900394
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900395 auto svc = NewService(GuestMessage::ARC);
396 svc->Start(kTestPID);
397 svc->Stop(kTestPID);
Garrick Evansb4eb3892019-11-13 12:07:07 +0900398}
399
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900400TEST_F(ArcServiceTest, ContainerImpl_OnStopDevice) {
Hugo Benichi33860d72020-07-09 16:34:01 +0900401 EXPECT_CALL(*datapath_, NetnsAttachName(StrEq("arc_netns"), kTestPID))
402 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900403 // Expectations for arc0 setup.
404 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
405 .WillOnce(Return(true));
406 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900407 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetharc0"),
408 StrEq("arc0")))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900409 .WillOnce(Return(true));
410 EXPECT_CALL(*datapath_,
411 ConfigureInterface(StrEq("arc0"), _, kArcGuestIP, 30, true, _))
412 .WillOnce(Return(true));
413 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetharc0"), true))
414 .WillOnce(Return(true));
415 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vetharc0")))
416 .WillOnce(Return(true));
417 // Expectations for eth0 setup.
418 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
419 .WillOnce(Return(true));
420 EXPECT_CALL(*datapath_,
Hugo Benichi33860d72020-07-09 16:34:01 +0900421 AddVirtualInterfacePair(StrEq("arc_netns"), StrEq("vetheth0"),
422 StrEq("eth0")))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900423 .WillOnce(Return(true));
424 EXPECT_CALL(*datapath_, ConfigureInterface(StrEq("eth0"), _, kFirstEthGuestIP,
425 30, true, _))
426 .WillOnce(Return(true));
427 EXPECT_CALL(*datapath_, ToggleInterface(StrEq("vetheth0"), true))
428 .WillOnce(Return(true));
429 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vetheth0")))
430 .WillOnce(Return(true));
431 // Expectations for eth0 teardown.
Garrick Evans2e5c9ab2020-03-05 14:33:58 +0900432 EXPECT_CALL(forwarder_,
433 StopForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900434 EXPECT_CALL(*datapath_, RemoveOutboundIPv4(StrEq("arc_eth0")));
435 EXPECT_CALL(*datapath_,
436 RemoveInboundIPv4DNAT(StrEq("eth0"), StrEq("100.115.92.6")));
437 EXPECT_CALL(*datapath_, RemoveBridge(StrEq("arc_eth0")));
Garrick Evanse94b6de2020-02-20 09:19:13 +0900438
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900439 auto svc = NewService(GuestMessage::ARC);
440 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900441 svc->OnDevicesChanged({"eth0"}, {});
442 svc->OnDevicesChanged({}, {"eth0"});
Garrick Evansb4eb3892019-11-13 12:07:07 +0900443}
444
Garrick Evansb4eb3892019-11-13 12:07:07 +0900445// VM Impl
446
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900447TEST_F(ArcServiceTest, VmImpl_Start) {
448 // Expectations for tap devices pre-creation.
Garrick Evansc7071122020-04-17 12:31:57 +0900449 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900450 .WillOnce(Return("vmtap0"))
451 .WillOnce(Return("vmtap1"))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900452 .WillOnce(Return("vmtap2"))
453 .WillOnce(Return("vmtap3"))
454 .WillOnce(Return("vmtap4"))
455 .WillOnce(Return("vmtap5"));
456 // Expectations for "arc0" setup.
457 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900458 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900459 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vmtap0")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900460 .WillOnce(Return(true));
461
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900462 auto svc = NewService(GuestMessage::ARC_VM);
463 svc->Start(kTestPID);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900464}
465
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900466TEST_F(ArcServiceTest, VmImpl_StartDevice) {
467 // Expectations for tap devices pre-creation.
Garrick Evansc7071122020-04-17 12:31:57 +0900468 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900469 .WillOnce(Return("vmtap0"))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900470 .WillOnce(Return("vmtap1"))
471 .WillOnce(Return("vmtap2"))
472 .WillOnce(Return("vmtap3"))
473 .WillOnce(Return("vmtap4"))
474 .WillOnce(Return("vmtap5"));
475 // Expectations for "arc0" setup.
476 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900477 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900478 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vmtap0")))
479 .WillOnce(Return(true));
480 // Expectations for eth0 setup.
481 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900482 .WillOnce(Return(true));
483 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vmtap1")))
484 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900485 EXPECT_CALL(*datapath_,
486 AddInboundIPv4DNAT(StrEq("eth0"), StrEq("100.115.92.6")));
487 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0")));
Garrick Evans2961c7c2020-04-03 11:34:40 +0900488 EXPECT_CALL(forwarder_,
489 StartForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
490
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900491 auto svc = NewService(GuestMessage::ARC_VM);
492 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900493 svc->OnDevicesChanged({"eth0"}, {});
Garrick Evans2961c7c2020-04-03 11:34:40 +0900494}
495
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900496TEST_F(ArcServiceTest, VmImpl_StartMultipleDevices) {
497 // Expectations for tap devices pre-creation.
Garrick Evansc7071122020-04-17 12:31:57 +0900498 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900499 .WillOnce(Return("vmtap0"))
500 .WillOnce(Return("vmtap1"))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900501 .WillOnce(Return("vmtap2"))
502 .WillOnce(Return("vmtap3"))
503 .WillOnce(Return("vmtap4"))
504 .WillOnce(Return("vmtap5"));
505 // Expectations for "arc0" setup.
506 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900507 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900508 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vmtap0")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900509 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900510 // Expectations for eth0 setup.
511 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
512 .WillOnce(Return(true));
513 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vmtap1")))
514 .WillOnce(Return(true));
515 EXPECT_CALL(*datapath_,
516 AddInboundIPv4DNAT(StrEq("eth0"), StrEq("100.115.92.6")));
517 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0")));
518 EXPECT_CALL(forwarder_,
519 StartForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
520 // Expectations for wlan0 setup.
521 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_wlan0"), kFirstWifiHostIP, 30))
522 .WillOnce(Return(true));
523 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_wlan0"), StrEq("vmtap3")))
524 .WillOnce(Return(true));
525 EXPECT_CALL(*datapath_,
526 AddInboundIPv4DNAT(StrEq("wlan0"), StrEq("100.115.92.14")));
527 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_wlan0")));
528 EXPECT_CALL(forwarder_,
529 StartForwarding(StrEq("wlan0"), StrEq("arc_wlan0"), _, _));
530 // Expectations for eth1 setup.
531 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth1"), kSecondEthHostIP, 30))
532 .WillOnce(Return(true));
533 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth1"), StrEq("vmtap2")))
534 .WillOnce(Return(true));
535 EXPECT_CALL(*datapath_,
536 AddInboundIPv4DNAT(StrEq("eth1"), StrEq("100.115.92.10")));
537 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth1")));
538 EXPECT_CALL(forwarder_,
539 StartForwarding(StrEq("eth1"), StrEq("arc_eth1"), _, _));
540
541 auto svc = NewService(GuestMessage::ARC_VM);
542 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900543 svc->OnDevicesChanged({"eth0"}, {});
544 svc->OnDevicesChanged({"wlan0"}, {});
545 svc->OnDevicesChanged({"eth1"}, {});
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900546}
547
548TEST_F(ArcServiceTest, VmImpl_Stop) {
549 // Expectations for tap devices pre-creation.
550 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
551 .WillOnce(Return("vmtap0"))
552 .WillOnce(Return("vmtap1"))
553 .WillOnce(Return("vmtap2"))
554 .WillOnce(Return("vmtap3"))
555 .WillOnce(Return("vmtap4"))
556 .WillOnce(Return("vmtap5"));
557 // Expectations for "arc0" setup.
558 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
559 .WillOnce(Return(true));
560 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vmtap0")))
561 .WillOnce(Return(true));
562 // Expectations for "arc0" teardown.
563 EXPECT_CALL(*datapath_,
564 MaskInterfaceFlags(StrEq("arcbr0"), IFF_DEBUG, IFF_UP))
565 .WillOnce(Return(true));
566 // Expectations for tap devices teardown
Garrick Evans2961c7c2020-04-03 11:34:40 +0900567 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap0")));
568 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap1")));
569 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap2")));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900570 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap3")));
571 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap4")));
572 EXPECT_CALL(*datapath_, RemoveInterface(StrEq("vmtap5")));
Garrick Evans2961c7c2020-04-03 11:34:40 +0900573
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900574 auto svc = NewService(GuestMessage::ARC_VM);
575 svc->Start(kTestPID);
576 svc->Stop(kTestPID);
Garrick Evans2961c7c2020-04-03 11:34:40 +0900577}
578
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900579TEST_F(ArcServiceTest, VmImpl_StopDevice) {
580 // Expectations for tap devices pre-creation.
Garrick Evansc7071122020-04-17 12:31:57 +0900581 EXPECT_CALL(*datapath_, AddTAP(StrEq(""), _, nullptr, StrEq("crosvm")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900582 .WillOnce(Return("vmtap0"))
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900583 .WillOnce(Return("vmtap1"))
584 .WillOnce(Return("vmtap2"))
585 .WillOnce(Return("vmtap3"))
586 .WillOnce(Return("vmtap4"))
587 .WillOnce(Return("vmtap5"));
588 // Expectations for "arc0" setup.
589 EXPECT_CALL(*datapath_, AddBridge(StrEq("arcbr0"), kArcHostIP, 30))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900590 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900591 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arcbr0"), StrEq("vmtap0")))
Garrick Evans2961c7c2020-04-03 11:34:40 +0900592 .WillOnce(Return(true));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900593 // Expectations for eth0 setup.
594 EXPECT_CALL(*datapath_, AddBridge(StrEq("arc_eth0"), kFirstEthHostIP, 30))
595 .WillOnce(Return(true));
596 EXPECT_CALL(*datapath_, AddToBridge(StrEq("arc_eth0"), StrEq("vmtap1")))
597 .WillOnce(Return(true));
598 EXPECT_CALL(*datapath_,
599 AddInboundIPv4DNAT(StrEq("eth0"), StrEq("100.115.92.6")));
600 EXPECT_CALL(*datapath_, AddOutboundIPv4(StrEq("arc_eth0")));
601 EXPECT_CALL(forwarder_,
602 StartForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
603 // Expectations for eth0 teardown.
Garrick Evans2961c7c2020-04-03 11:34:40 +0900604 EXPECT_CALL(forwarder_,
605 StopForwarding(StrEq("eth0"), StrEq("arc_eth0"), _, _));
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900606 EXPECT_CALL(*datapath_, RemoveOutboundIPv4(StrEq("arc_eth0")));
607 EXPECT_CALL(*datapath_,
608 RemoveInboundIPv4DNAT(StrEq("eth0"), StrEq("100.115.92.6")));
609 EXPECT_CALL(*datapath_, RemoveBridge(StrEq("arc_eth0")));
Garrick Evans2961c7c2020-04-03 11:34:40 +0900610
Hugo Benichiad1bdd92020-06-12 13:48:37 +0900611 auto svc = NewService(GuestMessage::ARC_VM);
612 svc->Start(kTestPID);
Hugo Benichif0f10c72020-07-09 10:42:45 +0900613 svc->OnDevicesChanged({"eth0"}, {});
614 svc->OnDevicesChanged({}, {"eth0"});
Garrick Evans2961c7c2020-04-03 11:34:40 +0900615}
Garrick Evans3388a032020-03-24 11:25:55 +0900616
617} // namespace patchpanel