blob: 4be82206761f915d272f0696a362b7829db74232 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.flow.impl;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070017
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070018import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableMap;
20import com.google.common.collect.Lists;
21import com.google.common.collect.Sets;
22import com.google.common.util.concurrent.ListenableFuture;
23import com.google.common.util.concurrent.MoreExecutors;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070024import org.junit.After;
25import org.junit.Before;
26import org.junit.Test;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080027import org.onlab.junit.TestTools;
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +000028import org.onlab.packet.Ip4Address;
29import org.onlab.packet.IpAddress;
Marc De Leenheerde47caa2015-04-24 11:27:44 -070030import org.onosproject.cfg.ComponentConfigAdapter;
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +000031import org.onosproject.cluster.ClusterService;
32import org.onosproject.cluster.ControllerNode;
33import org.onosproject.cluster.NodeId;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080034import org.onosproject.common.event.impl.TestEventDispatcher;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.core.ApplicationId;
Ray Milkeycc53abd2015-02-19 12:31:33 -080036import org.onosproject.core.CoreServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.core.DefaultApplicationId;
Brian O'Connor72cb19a2015-01-16 16:14:41 -080038import org.onosproject.core.IdGenerator;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080039import org.onosproject.mastership.MastershipServiceAdapter;
40import org.onosproject.net.AnnotationKeys;
41import org.onosproject.net.DefaultAnnotations;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.DefaultDevice;
43import org.onosproject.net.Device;
44import org.onosproject.net.Device.Type;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.MastershipRole;
Carmelo Cascone0761cd32018-08-29 19:22:50 -070047import org.onosproject.net.config.NetworkConfigServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.device.DeviceServiceAdapter;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080049import org.onosproject.net.driver.AbstractHandlerBehaviour;
50import org.onosproject.net.driver.DefaultDriver;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070051import org.onosproject.net.driver.DriverRegistry;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080052import org.onosproject.net.driver.impl.DriverManager;
Thomas Vachuska11b99fc2017-04-27 12:51:04 -070053import org.onosproject.net.driver.impl.DriverRegistryManager;
Brian O'Connorabafb502014-12-02 22:26:20 -080054import org.onosproject.net.flow.CompletedBatchOperation;
55import org.onosproject.net.flow.DefaultFlowEntry;
56import org.onosproject.net.flow.DefaultFlowRule;
57import org.onosproject.net.flow.FlowEntry;
58import org.onosproject.net.flow.FlowEntry.FlowEntryState;
59import org.onosproject.net.flow.FlowRule;
Brian O'Connorabafb502014-12-02 22:26:20 -080060import org.onosproject.net.flow.FlowRuleEvent;
61import org.onosproject.net.flow.FlowRuleListener;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080062import org.onosproject.net.flow.FlowRuleProgrammable;
Brian O'Connorabafb502014-12-02 22:26:20 -080063import org.onosproject.net.flow.FlowRuleProvider;
64import org.onosproject.net.flow.FlowRuleProviderRegistry;
65import org.onosproject.net.flow.FlowRuleProviderService;
66import org.onosproject.net.flow.FlowRuleService;
67import org.onosproject.net.flow.StoredFlowEntry;
68import org.onosproject.net.flow.TrafficSelector;
69import org.onosproject.net.flow.TrafficTreatment;
70import org.onosproject.net.flow.criteria.Criterion;
71import org.onosproject.net.flow.instructions.Instruction;
alshabib346b5b32015-03-06 00:42:16 -080072import org.onosproject.net.flow.instructions.Instructions;
Saurav Das86af8f12015-05-25 23:55:33 -070073import org.onosproject.net.flow.instructions.Instructions.MetadataInstruction;
Carmelo Cascone0761cd32018-08-29 19:22:50 -070074import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation;
75import org.onosproject.net.pi.PiPipeconfServiceAdapter;
Brian O'Connorabafb502014-12-02 22:26:20 -080076import org.onosproject.net.provider.AbstractProvider;
77import org.onosproject.net.provider.ProviderId;
Thomas Vachuskac97aa612015-06-23 16:00:18 -070078import org.onosproject.store.trivial.SimpleFlowRuleStore;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -070079
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070080import java.util.ArrayList;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080081import java.util.Collection;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070082import java.util.Collections;
83import java.util.HashMap;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -080084import java.util.HashSet;
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -070085import java.util.List;
86import java.util.Map;
87import java.util.Set;
88import java.util.concurrent.ExecutionException;
89import java.util.concurrent.Executor;
90import java.util.concurrent.TimeUnit;
91import java.util.concurrent.TimeoutException;
92import java.util.concurrent.atomic.AtomicLong;
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070093
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +000094import static org.easymock.EasyMock.*;
Carmelo Cascone0761cd32018-08-29 19:22:50 -070095import static org.junit.Assert.assertEquals;
96import static org.junit.Assert.assertFalse;
97import static org.junit.Assert.assertNotNull;
98import static org.junit.Assert.assertTrue;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070099import static org.onosproject.net.NetTestTools.injectEventDispatcher;
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700100import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADDED;
101import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_ADD_REQUESTED;
102import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED;
103import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVE_REQUESTED;
104import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_UPDATED;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700105
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700106/**
107 * Test codifying the flow rule service & flow rule provider service contracts.
108 */
tom202175a2014-09-19 19:00:11 -0700109public class FlowRuleManagerTest {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700110
alshabib92c65ad2014-10-08 21:56:05 -0700111
tomf6ab2152014-09-18 12:08:29 -0700112 private static final ProviderId PID = new ProviderId("of", "foo");
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800113 private static final ProviderId FOO_PID = new ProviderId("foo", "foo");
114
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700115 private static final DeviceId DID = DeviceId.deviceId("of:001");
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800116 private static final DeviceId FOO_DID = DeviceId.deviceId("foo:002");
alshabibba5ac482014-10-02 17:15:20 -0700117 private static final int TIMEOUT = 10;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800118
119 private static final DefaultAnnotations ANNOTATIONS =
120 DefaultAnnotations.builder().set(AnnotationKeys.DRIVER, "foo").build();
121
122 private static final Device DEV =
123 new DefaultDevice(PID, DID, Type.SWITCH, "", "", "", "", null);
124 private static final Device FOO_DEV =
125 new DefaultDevice(FOO_PID, FOO_DID, Type.SWITCH, "", "", "", "", null, ANNOTATIONS);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700126
tom202175a2014-09-19 19:00:11 -0700127 private FlowRuleManager mgr;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700128
129 protected FlowRuleService service;
130 protected FlowRuleProviderRegistry registry;
alshabibbb8b1282014-09-22 17:00:18 -0700131 protected FlowRuleProviderService providerService;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700132 protected TestProvider provider;
133 protected TestListener listener = new TestListener();
alshabiba68eb962014-09-24 20:34:13 -0700134 private ApplicationId appId;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700135
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800136 private TestDriverManager driverService;
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +0000137 private static final String NODE_ID = "1";
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800138
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700139 @Before
140 public void setUp() {
tom202175a2014-09-19 19:00:11 -0700141 mgr = new FlowRuleManager();
tombe988312014-09-19 18:38:47 -0700142 mgr.store = new SimpleFlowRuleStore();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700143 injectEventDispatcher(mgr, new TestEventDispatcher());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700144 mgr.deviceService = new TestDeviceService();
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800145 mgr.mastershipService = new TestMastershipService();
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800146 mgr.coreService = new TestCoreService();
147 mgr.operationsService = MoreExecutors.newDirectExecutorService();
148 mgr.deviceInstallers = MoreExecutors.newDirectExecutorService();
Marc De Leenheerde47caa2015-04-24 11:27:44 -0700149 mgr.cfgService = new ComponentConfigAdapter();
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +0000150
151 ClusterService mockClusterService = createMock(ClusterService.class);
152 NodeId nodeId = new NodeId(NODE_ID);
153 MockControllerNode mockControllerNode = new MockControllerNode(nodeId);
154 expect(mockClusterService.getLocalNode())
155 .andReturn(mockControllerNode).anyTimes();
156 replay(mockClusterService);
157 mgr.clusterService = mockClusterService;
158
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700159 service = mgr;
160 registry = mgr;
161
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700162 DriverRegistryManager driverRegistry = new DriverRegistryManager();
163 driverService = new TestDriverManager(driverRegistry);
164 driverRegistry.addDriver(new DefaultDriver("foo", ImmutableList.of(), "", "", "",
165 ImmutableMap.of(FlowRuleProgrammable.class,
166 TestFlowRuleProgrammable.class),
167 ImmutableMap.of()));
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800168
Marc De Leenheerde47caa2015-04-24 11:27:44 -0700169 mgr.activate(null);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700170 mgr.addListener(listener);
171 provider = new TestProvider(PID);
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700172 providerService = this.registry.register(provider);
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800173 appId = new TestApplicationId(0, "FlowRuleManagerTest");
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700174 assertTrue("provider should be registered",
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700175 this.registry.getProviders().contains(provider.id()));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700176 }
177
178 @After
179 public void tearDown() {
180 registry.unregister(provider);
181 assertFalse("provider should not be registered",
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700182 registry.getProviders().contains(provider.id()));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700183 service.removeListener(listener);
184 mgr.deactivate();
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700185 injectEventDispatcher(mgr, null);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700186 mgr.deviceService = null;
187 }
188
189 private FlowRule flowRule(int tsval, int trval) {
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800190 return flowRule(DID, tsval, trval);
191 }
192
193 private FlowRule flowRule(DeviceId did, int tsval, int trval) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700194 TestSelector ts = new TestSelector(tsval);
195 TestTreatment tr = new TestTreatment(trval);
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700196 return DefaultFlowRule.builder()
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800197 .forDevice(did)
Ray Milkeyd13a37b2015-06-12 11:55:17 -0700198 .withSelector(ts)
199 .withTreatment(tr)
200 .withPriority(10)
201 .fromApp(appId)
202 .makeTemporary(TIMEOUT)
203 .build();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700204 }
205
alshabibbb8b1282014-09-22 17:00:18 -0700206 private FlowRule addFlowRule(int hval) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700207 FlowRule rule = flowRule(hval, hval);
alshabibba5ac482014-10-02 17:15:20 -0700208 service.applyFlowRules(rule);
209
David Glantz5c7fe3a2021-09-22 14:34:14 -0500210 assertNotNull("rule should be found", service.getFlowEntry(rule));
alshabibbb8b1282014-09-22 17:00:18 -0700211 return rule;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700212 }
213
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700214 private void validateEvents(FlowRuleEvent.Type... events) {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700215 if (events == null) {
216 assertTrue("events generated", listener.events.isEmpty());
217 }
218
219 int i = 0;
alshabibbb42cad2014-09-25 11:43:05 -0700220 System.err.println("events :" + listener.events);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700221 for (FlowRuleEvent e : listener.events) {
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800222 assertEquals("unexpected event", events[i], e.type());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700223 i++;
224 }
225
226 assertEquals("mispredicted number of events",
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700227 events.length, listener.events.size());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700228
229 listener.events.clear();
230 }
231
232 private int flowCount() {
233 return Sets.newHashSet(service.getFlowEntries(DID)).size();
234 }
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700235
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700236 @Test
David Glantz5c7fe3a2021-09-22 14:34:14 -0500237 public void getFlowEntry() {
238 assertTrue("store should be empty",
239 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
240 FlowRule f1 = addFlowRule(1);
241 FlowRule f2 = addFlowRule(2);
242
243 FlowEntry fe1 = new DefaultFlowEntry(f1);
244 FlowEntry fe2 = new DefaultFlowEntry(f2);
245 assertEquals("2 rules should exist", 2, flowCount());
246
247 FlowEntry actual1 = service.getFlowEntry(f1);
248 FlowEntry actual2 = service.getFlowEntry(f2);
249
250 assertEquals(fe1, actual1);
251 assertEquals(fe2, actual2);
252 }
253
254 @Test
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700255 public void getFlowEntries() {
256 assertTrue("store should be empty",
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700257 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabibba5ac482014-10-02 17:15:20 -0700258 FlowRule f1 = addFlowRule(1);
259 FlowRule f2 = addFlowRule(2);
260
alshabib1c319ff2014-10-04 20:29:09 -0700261 FlowEntry fe1 = new DefaultFlowEntry(f1);
262 FlowEntry fe2 = new DefaultFlowEntry(f2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700263 assertEquals("2 rules should exist", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700264
alshabib1c319ff2014-10-04 20:29:09 -0700265 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
alshabib3d643ec2014-10-22 18:33:00 -0700266 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
267 RULE_ADDED, RULE_ADDED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700268
269 addFlowRule(1);
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800270 System.err.println("events :" + listener.events);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700271 assertEquals("should still be 2 rules", 2, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700272
alshabib1c319ff2014-10-04 20:29:09 -0700273 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1));
Charles Chan93fa7272016-01-26 22:27:02 -0800274 validateEvents(RULE_UPDATED, RULE_UPDATED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700275 }
276
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700277 private boolean validateState(Map<FlowRule, FlowEntryState> expected) {
278 Map<FlowRule, FlowEntryState> expectedToCheck = new HashMap<>(expected);
alshabib1c319ff2014-10-04 20:29:09 -0700279 Iterable<FlowEntry> rules = service.getFlowEntries(DID);
alshabib1c319ff2014-10-04 20:29:09 -0700280 for (FlowEntry f : rules) {
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700281 assertTrue("Unexpected FlowRule " + f, expectedToCheck.containsKey(f));
282 assertEquals("FlowEntry" + f, expectedToCheck.get(f), f.state());
283 expectedToCheck.remove(f);
alshabibbb8b1282014-09-22 17:00:18 -0700284 }
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700285 assertEquals(Collections.emptySet(), expectedToCheck.entrySet());
alshabibbb8b1282014-09-22 17:00:18 -0700286 return true;
287 }
288
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700289 @Test
290 public void applyFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700291
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700292 FlowRule r1 = flowRule(1, 1);
alshabiba68eb962014-09-24 20:34:13 -0700293 FlowRule r2 = flowRule(2, 2);
294 FlowRule r3 = flowRule(3, 3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700295
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700296 assertTrue("store should be empty",
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800297 Sets.newHashSet(service.getFlowEntries(DID)).isEmpty());
alshabib219ebaa2014-09-22 15:41:24 -0700298 mgr.applyFlowRules(r1, r2, r3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700299 assertEquals("3 rules should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700300 assertTrue("Entries should be pending add.",
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800301 validateState(ImmutableMap.of(
302 r1, FlowEntryState.PENDING_ADD,
303 r2, FlowEntryState.PENDING_ADD,
304 r3, FlowEntryState.PENDING_ADD)));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700305 }
306
307 @Test
Kavitha Alagesanc69c66a2016-06-15 14:26:04 +0530308 public void purgeFlowRules() {
309 FlowRule f1 = addFlowRule(1);
310 FlowRule f2 = addFlowRule(2);
311 FlowRule f3 = addFlowRule(3);
312 assertEquals("3 rules should exist", 3, flowCount());
313 FlowEntry fe1 = new DefaultFlowEntry(f1);
314 FlowEntry fe2 = new DefaultFlowEntry(f2);
315 FlowEntry fe3 = new DefaultFlowEntry(f3);
316 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2, fe3));
317 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700318 RULE_ADDED, RULE_ADDED, RULE_ADDED);
Kavitha Alagesanc69c66a2016-06-15 14:26:04 +0530319 mgr.purgeFlowRules(DID);
320 assertEquals("0 rule should exist", 0, flowCount());
321 }
322
323 @Test
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700324 public void removeFlowRules() {
alshabibbb8b1282014-09-22 17:00:18 -0700325 FlowRule f1 = addFlowRule(1);
326 FlowRule f2 = addFlowRule(2);
alshabibba5ac482014-10-02 17:15:20 -0700327 FlowRule f3 = addFlowRule(3);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700328 assertEquals("3 rules should exist", 3, flowCount());
alshabibba5ac482014-10-02 17:15:20 -0700329
alshabib1c319ff2014-10-04 20:29:09 -0700330 FlowEntry fe1 = new DefaultFlowEntry(f1);
331 FlowEntry fe2 = new DefaultFlowEntry(f2);
332 FlowEntry fe3 = new DefaultFlowEntry(f3);
333 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2, fe3));
alshabib3d643ec2014-10-22 18:33:00 -0700334 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
335 RULE_ADDED, RULE_ADDED, RULE_ADDED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700336
alshabib1c319ff2014-10-04 20:29:09 -0700337 mgr.removeFlowRules(f1, f2);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700338 //removing from north, so no events generated
alshabib3d643ec2014-10-22 18:33:00 -0700339 validateEvents(RULE_REMOVE_REQUESTED, RULE_REMOVE_REQUESTED);
alshabib219ebaa2014-09-22 15:41:24 -0700340 assertEquals("3 rule should exist", 3, flowCount());
alshabibbb8b1282014-09-22 17:00:18 -0700341 assertTrue("Entries should be pending remove.",
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800342 validateState(ImmutableMap.of(
343 f1, FlowEntryState.PENDING_REMOVE,
344 f2, FlowEntryState.PENDING_REMOVE,
345 f3, FlowEntryState.ADDED)));
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700346
alshabib1c319ff2014-10-04 20:29:09 -0700347 mgr.removeFlowRules(f1);
alshabib219ebaa2014-09-22 15:41:24 -0700348 assertEquals("3 rule should still exist", 3, flowCount());
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700349 }
350
351 @Test
352 public void flowRemoved() {
alshabibbb8b1282014-09-22 17:00:18 -0700353 FlowRule f1 = addFlowRule(1);
alshabibba5ac482014-10-02 17:15:20 -0700354 FlowRule f2 = addFlowRule(2);
Yuta HIGUCHIf6f50a62014-10-19 15:58:49 -0700355 StoredFlowEntry fe1 = new DefaultFlowEntry(f1);
alshabib1c319ff2014-10-04 20:29:09 -0700356 FlowEntry fe2 = new DefaultFlowEntry(f2);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800357
alshabib1c319ff2014-10-04 20:29:09 -0700358 providerService.pushFlowMetrics(DID, ImmutableList.of(fe1, fe2));
alshabiba68eb962014-09-24 20:34:13 -0700359 service.removeFlowRules(f1);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800360
Brian O'Connora3e5cd52015-12-05 15:59:19 -0800361 //FIXME modification of "stored" flow entry outside of store
alshabib1c319ff2014-10-04 20:29:09 -0700362 fe1.setState(FlowEntryState.REMOVED);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800363
alshabib1c319ff2014-10-04 20:29:09 -0700364 providerService.flowRemoved(fe1);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800365
alshabib3d643ec2014-10-22 18:33:00 -0700366 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED,
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800367 RULE_ADDED, RULE_REMOVE_REQUESTED, RULE_REMOVED);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700368
alshabib1c319ff2014-10-04 20:29:09 -0700369 providerService.flowRemoved(fe1);
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700370 validateEvents();
alshabibbb42cad2014-09-25 11:43:05 -0700371
alshabibba5ac482014-10-02 17:15:20 -0700372 FlowRule f3 = flowRule(3, 3);
alshabib1c319ff2014-10-04 20:29:09 -0700373 FlowEntry fe3 = new DefaultFlowEntry(f3);
alshabibba5ac482014-10-02 17:15:20 -0700374 service.applyFlowRules(f3);
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800375
alshabib1c319ff2014-10-04 20:29:09 -0700376 providerService.pushFlowMetrics(DID, Collections.singletonList(fe3));
Charles Chan93fa7272016-01-26 22:27:02 -0800377 validateEvents(RULE_ADD_REQUESTED, RULE_ADDED, RULE_UPDATED);
alshabibba5ac482014-10-02 17:15:20 -0700378
alshabib1c319ff2014-10-04 20:29:09 -0700379 providerService.flowRemoved(fe3);
alshabibbb42cad2014-09-25 11:43:05 -0700380 validateEvents();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700381 }
382
alshabibbb8b1282014-09-22 17:00:18 -0700383 @Test
384 public void flowMetrics() {
385 FlowRule f1 = flowRule(1, 1);
386 FlowRule f2 = flowRule(2, 2);
387 FlowRule f3 = flowRule(3, 3);
388
alshabibba5ac482014-10-02 17:15:20 -0700389 mgr.applyFlowRules(f1, f2, f3);
alshabibbb8b1282014-09-22 17:00:18 -0700390
alshabib1c319ff2014-10-04 20:29:09 -0700391 FlowEntry fe1 = new DefaultFlowEntry(f1);
392 FlowEntry fe2 = new DefaultFlowEntry(f2);
393
alshabib1c319ff2014-10-04 20:29:09 -0700394 //FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
395 //FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
396
397 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
alshabibbb8b1282014-09-22 17:00:18 -0700398
399 assertTrue("Entries should be added.",
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700400 validateState(ImmutableMap.of(
401 f1, FlowEntryState.ADDED,
402 f2, FlowEntryState.ADDED,
403 f3, FlowEntryState.PENDING_ADD)));
alshabibbb42cad2014-09-25 11:43:05 -0700404
alshabib3d643ec2014-10-22 18:33:00 -0700405 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
Sivachidambaram Subramanian605104e2017-06-21 07:40:04 +0530406 RULE_ADDED, RULE_ADDED, RULE_ADD_REQUESTED);
alshabibbb42cad2014-09-25 11:43:05 -0700407 }
408
409 @Test
410 public void extraneousFlow() {
411 FlowRule f1 = flowRule(1, 1);
412 FlowRule f2 = flowRule(2, 2);
413 FlowRule f3 = flowRule(3, 3);
alshabibba5ac482014-10-02 17:15:20 -0700414 mgr.applyFlowRules(f1, f2);
alshabibbb42cad2014-09-25 11:43:05 -0700415
alshabib1c319ff2014-10-04 20:29:09 -0700416// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
417// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
418// FlowRule updatedF3 = flowRule(f3, FlowRuleState.ADDED);
419 FlowEntry fe1 = new DefaultFlowEntry(f1);
420 FlowEntry fe2 = new DefaultFlowEntry(f2);
421 FlowEntry fe3 = new DefaultFlowEntry(f3);
alshabibbb42cad2014-09-25 11:43:05 -0700422
alshabib1c319ff2014-10-04 20:29:09 -0700423
424 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2, fe3));
alshabibbb42cad2014-09-25 11:43:05 -0700425
alshabib3d643ec2014-10-22 18:33:00 -0700426 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADDED, RULE_ADDED);
alshabibbb42cad2014-09-25 11:43:05 -0700427
428 }
429
430 /*
431 * Tests whether a rule that was marked for removal but no flowRemoved was received
432 * is indeed removed at the next stats update.
433 */
434 @Test
435 public void flowMissingRemove() {
436 FlowRule f1 = flowRule(1, 1);
437 FlowRule f2 = flowRule(2, 2);
438 FlowRule f3 = flowRule(3, 3);
439
alshabib1c319ff2014-10-04 20:29:09 -0700440// FlowRule updatedF1 = flowRule(f1, FlowRuleState.ADDED);
441// FlowRule updatedF2 = flowRule(f2, FlowRuleState.ADDED);
442
443 FlowEntry fe1 = new DefaultFlowEntry(f1);
444 FlowEntry fe2 = new DefaultFlowEntry(f2);
alshabibbb42cad2014-09-25 11:43:05 -0700445 mgr.applyFlowRules(f1, f2, f3);
446
447 mgr.removeFlowRules(f3);
448
alshabib1c319ff2014-10-04 20:29:09 -0700449 providerService.pushFlowMetrics(DID, Lists.newArrayList(fe1, fe2));
alshabibbb42cad2014-09-25 11:43:05 -0700450
alshabib3d643ec2014-10-22 18:33:00 -0700451 validateEvents(RULE_ADD_REQUESTED, RULE_ADD_REQUESTED, RULE_ADD_REQUESTED,
452 RULE_REMOVE_REQUESTED, RULE_ADDED, RULE_ADDED, RULE_REMOVED);
alshabibbb42cad2014-09-25 11:43:05 -0700453
454 }
455
456 @Test
alshabibbb42cad2014-09-25 11:43:05 -0700457 public void removeByAppId() {
458 FlowRule f1 = flowRule(1, 1);
459 FlowRule f2 = flowRule(2, 2);
460 mgr.applyFlowRules(f1, f2);
461
462
463 mgr.removeFlowRulesById(appId);
464
465 //only check that we are in pending remove. Events and actual remove state will
466 // be set by flowRemoved call.
Yuta HIGUCHI605347c2014-10-17 21:05:23 -0700467 validateState(ImmutableMap.of(
Thomas Vachuskae0f804a2014-10-27 23:40:48 -0700468 f1, FlowEntryState.PENDING_REMOVE,
469 f2, FlowEntryState.PENDING_REMOVE));
alshabibbb8b1282014-09-22 17:00:18 -0700470 }
471
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800472 @Test
473 public void fallbackBasics() {
474 FlowRule f1 = flowRule(FOO_DID, 1, 1);
475 flowRules.clear();
476 mgr.applyFlowRules(f1);
477 assertTrue("flow rule not applied", flowRules.contains(f1));
478
479 flowRules.clear();
480 mgr.removeFlowRules(f1);
481 assertTrue("flow rule not removed", flowRules.contains(f1));
482 }
483
484 @Test
485 public void fallbackFlowRemoved() {
486 FlowRule f1 = flowRule(FOO_DID, 1, 1);
487 mgr.applyFlowRules(f1);
488 flowRules.clear();
489 providerService.flowRemoved(new DefaultFlowEntry(f1));
490 assertTrue("flow rule not reapplied", flowRules.contains(f1));
491 }
492
493 @Test
494 public void fallbackExtraFlow() {
495 FlowRule f1 = flowRule(FOO_DID, 1, 1);
496 flowRules.clear();
497 providerService.pushFlowMetrics(FOO_DID, ImmutableList.of(new DefaultFlowEntry(f1)));
498 assertTrue("flow rule not removed", flowRules.contains(f1));
499 }
500
501 @Test
502 public void fallbackPoll() {
503 FlowRuleDriverProvider fallback = (FlowRuleDriverProvider) mgr.defaultProvider();
504 FlowRule f1 = flowRule(FOO_DID, 1, 1);
505 mgr.applyFlowRules(f1);
506 FlowEntry fe = mgr.getFlowEntries(FOO_DID).iterator().next();
507 assertEquals("incorrect state", FlowEntryState.PENDING_ADD, fe.state());
508
509 fallback.init(fallback.providerService, mgr.deviceService, mgr.mastershipService, 1);
510 TestTools.assertAfter(2000, () -> {
511 FlowEntry e = mgr.getFlowEntries(FOO_DID).iterator().next();
512 assertEquals("incorrect state", FlowEntryState.ADDED, e.state());
513 });
514 }
515
516
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700517 private static class TestListener implements FlowRuleListener {
518 final List<FlowRuleEvent> events = new ArrayList<>();
519
520 @Override
521 public void event(FlowRuleEvent event) {
522 events.add(event);
523 }
524 }
525
Yuta HIGUCHIf1f2ac02014-11-26 14:02:22 -0800526 private static class TestDeviceService extends DeviceServiceAdapter {
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700527 @Override
528 public int getDeviceCount() {
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800529 return 2;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700530 }
531
532 @Override
533 public Iterable<Device> getDevices() {
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800534 return ImmutableList.of(DEV, FOO_DEV);
535 }
536
537 @Override
538 public Iterable<Device> getAvailableDevices() {
539 return getDevices();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700540 }
541
542 @Override
543 public Device getDevice(DeviceId deviceId) {
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800544 return deviceId.equals(FOO_DID) ? FOO_DEV : DEV;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700545 }
pierventre2ad220f2022-02-18 15:12:33 -0800546
547 @Override
548 public boolean isAvailable(DeviceId deviceId) {
549 if (deviceId.equals(DID) || deviceId.equals(FOO_DID)) {
550 return true;
551 }
552 return false;
553 }
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700554 }
555
556 private class TestProvider extends AbstractProvider implements FlowRuleProvider {
557
558 protected TestProvider(ProviderId id) {
559 super(PID);
560 }
561
562 @Override
563 public void applyFlowRule(FlowRule... flowRules) {
564 }
565
566 @Override
567 public void removeFlowRule(FlowRule... flowRules) {
568 }
569
alshabiba68eb962014-09-24 20:34:13 -0700570 @Override
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800571 public void executeBatch(FlowRuleBatchOperation batch) {
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800572 // TODO: need to call batchOperationComplete
alshabib902d41b2014-10-07 16:52:05 -0700573 }
574
alshabibcf369912014-10-13 14:16:42 -0700575 private class TestInstallationFuture
Madan Jampani117aaae2014-10-23 10:04:05 -0700576 implements ListenableFuture<CompletedBatchOperation> {
alshabibcf369912014-10-13 14:16:42 -0700577
578 @Override
579 public boolean cancel(boolean mayInterruptIfRunning) {
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800580 return false;
alshabibcf369912014-10-13 14:16:42 -0700581 }
582
583 @Override
584 public boolean isCancelled() {
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800585 return false;
alshabibcf369912014-10-13 14:16:42 -0700586 }
587
588 @Override
589 public boolean isDone() {
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800590 return true;
alshabibcf369912014-10-13 14:16:42 -0700591 }
592
593 @Override
594 public CompletedBatchOperation get()
595 throws InterruptedException, ExecutionException {
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700596 return new CompletedBatchOperation(true, Collections.emptySet(), null);
alshabibcf369912014-10-13 14:16:42 -0700597 }
598
599 @Override
600 public CompletedBatchOperation get(long timeout, TimeUnit unit)
601 throws InterruptedException,
602 ExecutionException, TimeoutException {
Sho SHIMIZU21d00692016-08-15 11:15:28 -0700603 return new CompletedBatchOperation(true, Collections.emptySet(), null);
alshabibcf369912014-10-13 14:16:42 -0700604 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700605
606 @Override
607 public void addListener(Runnable task, Executor executor) {
Yuta HIGUCHI2fcb40c2014-11-03 14:39:10 -0800608 if (isDone()) {
609 executor.execute(task);
610 }
Madan Jampani117aaae2014-10-23 10:04:05 -0700611 }
alshabibcf369912014-10-13 14:16:42 -0700612 }
alshabiba68eb962014-09-24 20:34:13 -0700613
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700614 }
615
616 private class TestSelector implements TrafficSelector {
617
618 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700619 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700620
621 public TestSelector(int val) {
622 testval = val;
623 }
624
625 @Override
alshabibba5ac482014-10-02 17:15:20 -0700626 public Set<Criterion> criteria() {
Hyunsun Moon7bfbc1c2016-04-05 16:40:43 -0700627 return Collections.emptySet();
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700628 }
629
630 @Override
Jonathan Hart936c49d2014-10-23 16:38:59 -0700631 public Criterion getCriterion(
Brian O'Connorabafb502014-12-02 22:26:20 -0800632 org.onosproject.net.flow.criteria.Criterion.Type type) {
Jonathan Hart936c49d2014-10-23 16:38:59 -0700633 return null;
634 }
635
636 @Override
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700637 public int hashCode() {
638 return testval;
639 }
640
641 @Override
642 public boolean equals(Object o) {
643 if (o instanceof TestSelector) {
644 return this.testval == ((TestSelector) o).testval;
645 }
646 return false;
647 }
Jonathan Hart936c49d2014-10-23 16:38:59 -0700648
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700649 }
650
651 private class TestTreatment implements TrafficTreatment {
652
653 //for controlling hashcode uniqueness;
alshabib97044902014-09-18 14:52:16 -0700654 private final int testval;
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700655
656 public TestTreatment(int val) {
657 testval = val;
658 }
659
660 @Override
alshabib346b5b32015-03-06 00:42:16 -0800661 public List<Instruction> deferred() {
662 return null;
663 }
664
665 @Override
666 public List<Instruction> immediate() {
667 return null;
668 }
669
670 @Override
Jonathan Hart8ef6d3b2015-03-08 21:21:27 -0700671 public List<Instruction> allInstructions() {
672 return null;
673 }
674
675 @Override
alshabib346b5b32015-03-06 00:42:16 -0800676 public Instructions.TableTypeTransition tableTransition() {
677 return null;
678 }
679
680 @Override
Jonathan Hart4a0ba562015-03-23 17:23:33 -0700681 public boolean clearedDeferred() {
682 return false;
alshabib346b5b32015-03-06 00:42:16 -0800683 }
684
685 @Override
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700686 public int hashCode() {
687 return testval;
688 }
689
690 @Override
691 public boolean equals(Object o) {
692 if (o instanceof TestTreatment) {
693 return this.testval == ((TestTreatment) o).testval;
694 }
695 return false;
696 }
697
Saurav Das86af8f12015-05-25 23:55:33 -0700698 @Override
699 public MetadataInstruction writeMetadata() {
700 return null;
701 }
702
alshabib10c810b2015-08-18 16:59:04 -0700703 @Override
Cem Türker3baff672017-10-12 15:09:01 +0300704 public Instructions.StatTriggerInstruction statTrigger() {
705 return null;
706 }
707
708 @Override
alshabib10c810b2015-08-18 16:59:04 -0700709 public Instructions.MeterInstruction metered() {
710 return null;
711 }
712
cansu.toprak409289d2017-10-27 10:04:05 +0300713 @Override
714 public Set<Instructions.MeterInstruction> meters() {
715 return Sets.newHashSet();
716 }
717
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700718 }
719
alshabib92c65ad2014-10-08 21:56:05 -0700720 public class TestApplicationId extends DefaultApplicationId {
Thomas Vachuska02aeb032015-01-06 22:36:30 -0800721 public TestApplicationId(int id, String name) {
alshabib92c65ad2014-10-08 21:56:05 -0700722 super(id, name);
723 }
724 }
725
Ray Milkeycc53abd2015-02-19 12:31:33 -0800726 private class TestCoreService extends CoreServiceAdapter {
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800727
728 @Override
729 public IdGenerator getIdGenerator(String topic) {
730 return new IdGenerator() {
731 private AtomicLong counter = new AtomicLong(0);
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800732
Brian O'Connor72cb19a2015-01-16 16:14:41 -0800733 @Override
734 public long getNewId() {
735 return counter.getAndIncrement();
736 }
737 };
738 }
739 }
740
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800741 private class TestMastershipService extends MastershipServiceAdapter {
742 @Override
743 public MastershipRole getLocalRole(DeviceId deviceId) {
744 return MastershipRole.MASTER;
745 }
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +0000746
747 @Override
748 public NodeId getMasterFor(DeviceId deviceId) {
749 return new NodeId(NODE_ID);
750 }
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800751 }
752
753 private class TestDriverManager extends DriverManager {
Thomas Vachuska11b99fc2017-04-27 12:51:04 -0700754 TestDriverManager(DriverRegistry registry) {
755 this.registry = registry;
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800756 this.deviceService = mgr.deviceService;
Carmelo Cascone0761cd32018-08-29 19:22:50 -0700757 this.pipeconfService = new PiPipeconfServiceAdapter();
758 this.networkConfigService = new NetworkConfigServiceAdapter();
Thomas Vachuskac4ee7372016-02-02 16:10:09 -0800759 activate();
760 }
761 }
762
763 static Collection<FlowRule> flowRules = new HashSet<>();
764
765 public static class TestFlowRuleProgrammable extends AbstractHandlerBehaviour implements FlowRuleProgrammable {
766
767 @Override
768 public Collection<FlowEntry> getFlowEntries() {
769 ImmutableList.Builder<FlowEntry> builder = ImmutableList.builder();
770 flowRules.stream().map(DefaultFlowEntry::new).forEach(builder::add);
771 return builder.build();
772 }
773
774 @Override
775 public Collection<FlowRule> applyFlowRules(Collection<FlowRule> rules) {
776 flowRules.addAll(rules);
777 return rules;
778 }
779
780 @Override
781 public Collection<FlowRule> removeFlowRules(Collection<FlowRule> rules) {
782 flowRules.addAll(rules);
783 return rules;
784 }
785 }
Pier Luigi Ventred8a923c2020-02-20 11:25:31 +0000786
787 private static class MockControllerNode implements ControllerNode {
788 final NodeId id;
789
790 public MockControllerNode(NodeId id) {
791 this.id = id;
792 }
793
794 @Override
795 public NodeId id() {
796 return this.id;
797 }
798
799 @Override
800 public Ip4Address ip() {
801 return Ip4Address.valueOf("127.0.0.1");
802 }
803
804 @Override
805 public IpAddress ip(boolean resolve) {
806 return null;
807 }
808
809 @Override
810 public String host() {
811 return null;
812 }
813
814 @Override
815 public int tcpPort() {
816 return 0;
817 }
818 }
Ayaka Koshibeb55524f2014-09-18 09:59:24 -0700819}