Thomas Vachuska
Committed by Gerrit Code Review

Adding a grid topology simulator to the null provider.

Change-Id: Ie655840febc11d3986f1c8ec5c8ef2374014794c
...@@ -20,9 +20,7 @@ package org.onosproject.provider.nil; ...@@ -20,9 +20,7 @@ package org.onosproject.provider.nil;
20 */ 20 */
21 public class CentipedeTopologySimulator extends LinearTopologySimulator { 21 public class CentipedeTopologySimulator extends LinearTopologySimulator {
22 22
23 - /** 23 + @Override
24 - * Creates simulated hosts.
25 - */
26 protected void createHosts() { 24 protected void createHosts() {
27 deviceIds.forEach(id -> createHosts(id, infrastructurePorts)); 25 deviceIds.forEach(id -> createHosts(id, infrastructurePorts));
28 } 26 }
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.provider.nil;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +
20 +/**
21 + * Rectangular grid topology with hosts at each device.
22 + */
23 +public class GridTopologySimulator extends TopologySimulator {
24 +
25 + private int cols;
26 + private int rows;
27 +
28 + @Override
29 + protected void processTopoShape(String shape) {
30 + super.processTopoShape(shape);
31 + rows = topoShape.length > 1 ? Integer.parseInt(topoShape[1]) : 10;
32 + cols = topoShape.length > 2 ? Integer.parseInt(topoShape[2]) : rows;
33 + hostCount = topoShape.length > 3 ? Integer.parseInt(topoShape[3]) : 1;
34 + infrastructurePorts = 4;
35 + deviceCount = rows * cols;
36 + }
37 +
38 + @Override
39 + public void setUpTopology() {
40 + checkArgument(rows > 1, "There must be at least 2 rows");
41 + checkArgument(cols > 1, "There must be at least 2 columns");
42 + super.setUpTopology();
43 + }
44 +
45 + @Override
46 + protected void createLinks() {
47 + for (int r = 0; r < rows; r++) {
48 + for (int c = 0; c < cols; c++) {
49 + int i = r * cols + c;
50 + if (c < cols - 1) {
51 + createLink(i, i + 1, 3, 1);
52 + }
53 + if (r < rows - 1) {
54 + createLink(i, (r + 1) * cols + c, 4, 2);
55 + }
56 + }
57 + }
58 + }
59 +
60 + @Override
61 + protected void createHosts() {
62 + deviceIds.forEach(id -> createHosts(id, infrastructurePorts));
63 + }
64 +
65 +}
...@@ -54,6 +54,7 @@ import org.osgi.service.component.ComponentContext; ...@@ -54,6 +54,7 @@ import org.osgi.service.component.ComponentContext;
54 import org.slf4j.Logger; 54 import org.slf4j.Logger;
55 55
56 import java.util.Dictionary; 56 import java.util.Dictionary;
57 +import java.util.Objects;
57 import java.util.Properties; 58 import java.util.Properties;
58 59
59 import static com.google.common.base.Strings.isNullOrEmpty; 60 import static com.google.common.base.Strings.isNullOrEmpty;
...@@ -116,7 +117,6 @@ public class NullProviders { ...@@ -116,7 +117,6 @@ public class NullProviders {
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected PacketProviderRegistry packetProviderRegistry; 118 protected PacketProviderRegistry packetProviderRegistry;
118 119
119 -
120 private final NullDeviceProvider deviceProvider = new NullDeviceProvider(); 120 private final NullDeviceProvider deviceProvider = new NullDeviceProvider();
121 private final NullLinkProvider linkProvider = new NullLinkProvider(); 121 private final NullLinkProvider linkProvider = new NullLinkProvider();
122 private final NullHostProvider hostProvider = new NullHostProvider(); 122 private final NullHostProvider hostProvider = new NullHostProvider();
...@@ -138,7 +138,7 @@ public class NullProviders { ...@@ -138,7 +138,7 @@ public class NullProviders {
138 138
139 private static final String DEFAULT_TOPO_SHAPE = "configured"; 139 private static final String DEFAULT_TOPO_SHAPE = "configured";
140 @Property(name = "topoShape", value = DEFAULT_TOPO_SHAPE, 140 @Property(name = "topoShape", value = DEFAULT_TOPO_SHAPE,
141 - label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh") 141 + label = "Topology shape: configured, linear, reroute, tree, spineleaf, mesh, grid")
142 private String topoShape = DEFAULT_TOPO_SHAPE; 142 private String topoShape = DEFAULT_TOPO_SHAPE;
143 143
144 private static final int DEFAULT_DEVICE_COUNT = 10; 144 private static final int DEFAULT_DEVICE_COUNT = 10;
...@@ -238,7 +238,7 @@ public class NullProviders { ...@@ -238,7 +238,7 @@ public class NullProviders {
238 } 238 }
239 239
240 // Any change in the following parameters implies hard restart 240 // Any change in the following parameters implies hard restart
241 - if (newEnabled != enabled || !newTopoShape.equals(topoShape) || 241 + if (newEnabled != enabled || !Objects.equals(newTopoShape, topoShape) ||
242 newDeviceCount != deviceCount || newHostCount != hostCount) { 242 newDeviceCount != deviceCount || newHostCount != hostCount) {
243 enabled = newEnabled; 243 enabled = newEnabled;
244 topoShape = newTopoShape; 244 topoShape = newTopoShape;
...@@ -257,7 +257,7 @@ public class NullProviders { ...@@ -257,7 +257,7 @@ public class NullProviders {
257 } 257 }
258 258
259 // Any change in mastership implies just reassignments. 259 // Any change in mastership implies just reassignments.
260 - if (!newMastership.equals(mastership)) { 260 + if (!Objects.equals(newMastership, mastership)) {
261 mastership = newMastership; 261 mastership = newMastership;
262 reassignMastership(); 262 reassignMastership();
263 } 263 }
...@@ -290,6 +290,29 @@ public class NullProviders { ...@@ -290,6 +290,29 @@ public class NullProviders {
290 } 290 }
291 } 291 }
292 292
293 + /**
294 + * Fails the specified device.
295 + *
296 + * @param deviceId device identifier
297 + */
298 + public void failDevice(DeviceId deviceId) {
299 + if (enabled) {
300 + topologyMutationDriver.failDevice(deviceId);
301 + }
302 + }
303 +
304 + /**
305 + * Repairs the specified device.
306 + *
307 + * @param deviceId device identifier
308 + */
309 + public void repairDevice(DeviceId deviceId) {
310 + if (enabled) {
311 + topologyMutationDriver.repairDevice(deviceId);
312 + }
313 + }
314 +
315 +
293 // Resets simulation based on the current configuration parameters. 316 // Resets simulation based on the current configuration parameters.
294 private void restartSimulation() { 317 private void restartSimulation() {
295 tearDown(); 318 tearDown();
...@@ -310,7 +333,8 @@ public class NullProviders { ...@@ -310,7 +333,8 @@ public class NullProviders {
310 packetProvider.start(packetRate, hostService, deviceService, 333 packetProvider.start(packetRate, hostService, deviceService,
311 packetProviderService); 334 packetProviderService);
312 topologyMutationDriver.start(mutationRate, linkService, deviceService, 335 topologyMutationDriver.start(mutationRate, linkService, deviceService,
313 - linkProviderService); 336 + linkProviderService, deviceProviderService,
337 + simulator);
314 } 338 }
315 339
316 // Selects the simulator based on the specified name. 340 // Selects the simulator based on the specified name.
...@@ -329,6 +353,8 @@ public class NullProviders { ...@@ -329,6 +353,8 @@ public class NullProviders {
329 return new SpineLeafTopologySimulator(); 353 return new SpineLeafTopologySimulator();
330 } else if (topoShape.matches("mesh([,].*|$)")) { 354 } else if (topoShape.matches("mesh([,].*|$)")) {
331 return new MeshTopologySimulator(); 355 return new MeshTopologySimulator();
356 + } else if (topoShape.matches("grid([,].*|$)")) {
357 + return new GridTopologySimulator();
332 } else { 358 } else {
333 return new ConfiguredTopologySimulator(); 359 return new ConfiguredTopologySimulator();
334 } 360 }
...@@ -398,7 +424,8 @@ public class NullProviders { ...@@ -398,7 +424,8 @@ public class NullProviders {
398 @Override 424 @Override
399 public boolean isReachable(DeviceId deviceId) { 425 public boolean isReachable(DeviceId deviceId) {
400 return topoShape.equals("configured") || 426 return topoShape.equals("configured") ||
401 - (simulator != null && simulator.contains(deviceId)); 427 + (simulator != null && simulator.contains(deviceId) &&
428 + topologyMutationDriver.isReachable(deviceId));
402 } 429 }
403 430
404 @Override 431 @Override
......
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
16 package org.onosproject.provider.nil; 16 package org.onosproject.provider.nil;
17 17
18 import com.google.common.collect.Lists; 18 import com.google.common.collect.Lists;
19 +import com.google.common.collect.Maps;
19 import org.onosproject.net.ConnectPoint; 20 import org.onosproject.net.ConnectPoint;
21 +import org.onosproject.net.DeviceId;
22 +import org.onosproject.net.Link;
23 +import org.onosproject.net.device.DeviceProviderService;
20 import org.onosproject.net.device.DeviceService; 24 import org.onosproject.net.device.DeviceService;
21 import org.onosproject.net.link.DefaultLinkDescription; 25 import org.onosproject.net.link.DefaultLinkDescription;
22 import org.onosproject.net.link.LinkDescription; 26 import org.onosproject.net.link.LinkDescription;
...@@ -26,7 +30,9 @@ import org.slf4j.Logger; ...@@ -26,7 +30,9 @@ import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory; 30 import org.slf4j.LoggerFactory;
27 31
28 import java.util.List; 32 import java.util.List;
33 +import java.util.Map;
29 import java.util.Random; 34 import java.util.Random;
35 +import java.util.Set;
30 import java.util.concurrent.ExecutorService; 36 import java.util.concurrent.ExecutorService;
31 import java.util.stream.Collectors; 37 import java.util.stream.Collectors;
32 38
...@@ -57,6 +63,8 @@ class TopologyMutationDriver implements Runnable { ...@@ -57,6 +63,8 @@ class TopologyMutationDriver implements Runnable {
57 private LinkService linkService; 63 private LinkService linkService;
58 private DeviceService deviceService; 64 private DeviceService deviceService;
59 private LinkProviderService linkProviderService; 65 private LinkProviderService linkProviderService;
66 + private DeviceProviderService deviceProviderService;
67 + private TopologySimulator simulator;
60 68
61 private List<LinkDescription> activeLinks; 69 private List<LinkDescription> activeLinks;
62 private List<LinkDescription> inactiveLinks; 70 private List<LinkDescription> inactiveLinks;
...@@ -64,21 +72,30 @@ class TopologyMutationDriver implements Runnable { ...@@ -64,21 +72,30 @@ class TopologyMutationDriver implements Runnable {
64 private final ExecutorService executor = 72 private final ExecutorService executor =
65 newSingleThreadScheduledExecutor(groupedThreads("onos/null", "topo-mutator")); 73 newSingleThreadScheduledExecutor(groupedThreads("onos/null", "topo-mutator"));
66 74
75 + private Map<DeviceId, Set<Link>> savedLinks = Maps.newConcurrentMap();
76 +
67 /** 77 /**
68 * Starts the mutation process. 78 * Starts the mutation process.
69 * 79 *
70 - * @param mutationRate link events per second 80 + * @param mutationRate link events per second
71 - * @param linkService link service 81 + * @param linkService link service
72 - * @param deviceService device service 82 + * @param deviceService device service
73 - * @param linkProviderService link provider service 83 + * @param linkProviderService link provider service
84 + * @param deviceProviderService device provider service
85 + * @param simulator topology simulator
74 */ 86 */
75 void start(double mutationRate, 87 void start(double mutationRate,
76 LinkService linkService, DeviceService deviceService, 88 LinkService linkService, DeviceService deviceService,
77 - LinkProviderService linkProviderService) { 89 + LinkProviderService linkProviderService,
90 + DeviceProviderService deviceProviderService,
91 + TopologySimulator simulator) {
92 + savedLinks.clear();
78 stopped = false; 93 stopped = false;
79 this.linkService = linkService; 94 this.linkService = linkService;
80 this.deviceService = deviceService; 95 this.deviceService = deviceService;
81 this.linkProviderService = linkProviderService; 96 this.linkProviderService = linkProviderService;
97 + this.deviceProviderService = deviceProviderService;
98 + this.simulator = simulator;
82 activeLinks = reduceLinks(); 99 activeLinks = reduceLinks();
83 inactiveLinks = Lists.newArrayList(); 100 inactiveLinks = Lists.newArrayList();
84 adjustRate(mutationRate); 101 adjustRate(mutationRate);
...@@ -134,6 +151,41 @@ class TopologyMutationDriver implements Runnable { ...@@ -134,6 +151,41 @@ class TopologyMutationDriver implements Runnable {
134 linkProviderService.linkDetected(reverse(link)); 151 linkProviderService.linkDetected(reverse(link));
135 } 152 }
136 153
154 + /**
155 + * Fails the specified device.
156 + *
157 + * @param deviceId device identifier
158 + */
159 + void failDevice(DeviceId deviceId) {
160 + savedLinks.put(deviceId, linkService.getDeviceLinks(deviceId));
161 + deviceProviderService.deviceDisconnected(deviceId);
162 + }
163 +
164 + /**
165 + * Repairs the specified device.
166 + *
167 + * @param deviceId device identifier
168 + */
169 + void repairDevice(DeviceId deviceId) {
170 + int chassisId = Integer.parseInt(deviceId.uri().getSchemeSpecificPart());
171 + simulator.createDevice(deviceId, chassisId);
172 + Set<Link> links = savedLinks.remove(deviceId);
173 + if (links != null) {
174 + links.forEach(l -> linkProviderService
175 + .linkDetected(new DefaultLinkDescription(l.src(), l.dst(), DIRECT)));
176 + }
177 + }
178 +
179 + /**
180 + * Returns whether the given device is considered reachable or not.
181 + *
182 + * @param deviceId device identifier
183 + * @return true if device is reachable
184 + */
185 + boolean isReachable(DeviceId deviceId) {
186 + return !savedLinks.containsKey(deviceId);
187 + }
188 +
137 @Override 189 @Override
138 public void run() { 190 public void run() {
139 delay(WAIT_DELAY); 191 delay(WAIT_DELAY);
......
...@@ -172,31 +172,31 @@ public abstract class TopologySimulator { ...@@ -172,31 +172,31 @@ public abstract class TopologySimulator {
172 protected abstract void createHosts(); 172 protected abstract void createHosts();
173 173
174 /** 174 /**
175 - * Creates simulated device. 175 + * Creates simulated device and adds its id to the list of devices ids.
176 * 176 *
177 * @param i index of the device id in the list. 177 * @param i index of the device id in the list.
178 */ 178 */
179 protected void createDevice(int i) { 179 protected void createDevice(int i) {
180 DeviceId id = DeviceId.deviceId(SCHEME + ":" + toHex(i)); 180 DeviceId id = DeviceId.deviceId(SCHEME + ":" + toHex(i));
181 + deviceIds.add(id);
182 + createDevice(id, i);
183 + }
184 +
185 + /**
186 + * Creates simulated device.
187 + *
188 + * @param id device identifier
189 + * @param chassisId chassis identifier number
190 + */
191 + protected void createDevice(DeviceId id, int chassisId) {
181 DeviceDescription desc = 192 DeviceDescription desc =
182 new DefaultDeviceDescription(id.uri(), Device.Type.SWITCH, 193 new DefaultDeviceDescription(id.uri(), Device.Type.SWITCH,
183 "ON.Lab", "0.1", "0.1", "1234", 194 "ON.Lab", "0.1", "0.1", "1234",
184 - new ChassisId(i)); 195 + new ChassisId(chassisId));
185 - deviceIds.add(id);
186 deviceProviderService.deviceConnected(id, desc); 196 deviceProviderService.deviceConnected(id, desc);
187 deviceProviderService.updatePorts(id, buildPorts(hostCount + infrastructurePorts)); 197 deviceProviderService.updatePorts(id, buildPorts(hostCount + infrastructurePorts));
188 } 198 }
189 199
190 -// /**
191 -// * Creates simulated link between two devices on port 1 and port 2.
192 -// *
193 -// * @param i index of one simulated device
194 -// * @param j index of another simulated device
195 -// */
196 -// protected void createLink(int i, int j) {
197 -// createLink(i, j, 1, 2);
198 -// }
199 -
200 /** 200 /**
201 * Creates simulated link between two devices. 201 * Creates simulated link between two devices.
202 * 202 *
...@@ -208,6 +208,16 @@ public abstract class TopologySimulator { ...@@ -208,6 +208,16 @@ public abstract class TopologySimulator {
208 protected void createLink(int i, int j, int pi, int pj) { 208 protected void createLink(int i, int j, int pi, int pj) {
209 ConnectPoint one = new ConnectPoint(deviceIds.get(i), PortNumber.portNumber(pi)); 209 ConnectPoint one = new ConnectPoint(deviceIds.get(i), PortNumber.portNumber(pi));
210 ConnectPoint two = new ConnectPoint(deviceIds.get(j), PortNumber.portNumber(pj)); 210 ConnectPoint two = new ConnectPoint(deviceIds.get(j), PortNumber.portNumber(pj));
211 + createLink(one, two);
212 + }
213 +
214 + /**
215 + * Creates simulated link between two connection points.
216 + *
217 + * @param one one connection point
218 + * @param two another connection point
219 + */
220 + protected void createLink(ConnectPoint one, ConnectPoint two) {
211 linkProviderService.linkDetected(new DefaultLinkDescription(one, two, DIRECT)); 221 linkProviderService.linkDetected(new DefaultLinkDescription(one, two, DIRECT));
212 linkProviderService.linkDetected(new DefaultLinkDescription(two, one, DIRECT)); 222 linkProviderService.linkDetected(new DefaultLinkDescription(two, one, DIRECT));
213 } 223 }
...@@ -359,7 +369,7 @@ public abstract class TopologySimulator { ...@@ -359,7 +369,7 @@ public abstract class TopologySimulator {
359 } 369 }
360 370
361 /** 371 /**
362 - * Indicates whether or not the simulation knows of this device. 372 + * Indicates whether or not the simulation deeps the device as available.
363 * 373 *
364 * @param deviceId device identifier 374 * @param deviceId device identifier
365 * @return true if device is known 375 * @return true if device is known
......
...@@ -55,6 +55,7 @@ public class TreeTopologySimulator extends TopologySimulator { ...@@ -55,6 +55,7 @@ public class TreeTopologySimulator extends TopologySimulator {
55 55
56 @Override 56 @Override
57 protected void createLinks() { 57 protected void createLinks() {
58 +
58 int portOffset = 1; 59 int portOffset = 1;
59 for (int t = 1; t < tierOffset.length; t++) { 60 for (int t = 1; t < tierOffset.length; t++) {
60 int child = tierOffset[t]; 61 int child = tierOffset[t];
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
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 + */
16 +package org.onosproject.provider.nil.cli;
17 +
18 +import org.apache.karaf.shell.commands.Argument;
19 +import org.apache.karaf.shell.commands.Command;
20 +import org.onosproject.cli.AbstractShellCommand;
21 +import org.onosproject.net.DeviceId;
22 +import org.onosproject.provider.nil.NullProviders;
23 +
24 +import static org.onosproject.cli.UpDownCompleter.DOWN;
25 +import static org.onosproject.cli.UpDownCompleter.UP;
26 +
27 +/**
28 + * Servers or repairs a simulated link.
29 + */
30 +@Command(scope = "onos", name = "null-device",
31 + description = "Severs or repairs a simulated link")
32 +public class NullDeviceCommand extends AbstractShellCommand {
33 +
34 + @Argument(index = 0, name = "id", description = "Device identifier",
35 + required = true, multiValued = false)
36 + String id = null;
37 +
38 + @Argument(index = 1, name = "cmd", description = "up/down",
39 + required = true, multiValued = false)
40 + String cmd = null;
41 +
42 +
43 + @Override
44 + protected void execute() {
45 + NullProviders service = get(NullProviders.class);
46 + DeviceId deviceId = DeviceId.deviceId(id);
47 +
48 + if (cmd.equals(UP)) {
49 + service.repairDevice(deviceId);
50 + } else if (cmd.equals(DOWN)) {
51 + service.failDevice(deviceId);
52 + } else {
53 + error("Illegal command %s; must be up or down", cmd);
54 + }
55 + }
56 +
57 +}
...@@ -50,7 +50,6 @@ public class NullLinkCommand extends AbstractShellCommand { ...@@ -50,7 +50,6 @@ public class NullLinkCommand extends AbstractShellCommand {
50 50
51 try { 51 try {
52 ConnectPoint onePoint = ConnectPoint.deviceConnectPoint(one); 52 ConnectPoint onePoint = ConnectPoint.deviceConnectPoint(one);
53 -
54 ConnectPoint twoPoint = ConnectPoint.deviceConnectPoint(two); 53 ConnectPoint twoPoint = ConnectPoint.deviceConnectPoint(two);
55 54
56 if (cmd.equals(UP)) { 55 if (cmd.equals(UP)) {
......
...@@ -27,6 +27,6 @@ public class TopologyShapeCompleter extends AbstractChoicesCompleter { ...@@ -27,6 +27,6 @@ public class TopologyShapeCompleter extends AbstractChoicesCompleter {
27 @Override 27 @Override
28 public List<String> choices() { 28 public List<String> choices() {
29 return ImmutableList.of("configured", "linear", "reroute", "centipede", 29 return ImmutableList.of("configured", "linear", "reroute", "centipede",
30 - "tree", "spineleaf", "mesh"); 30 + "tree", "spineleaf", "mesh", "grid");
31 } 31 }
32 } 32 }
......
...@@ -33,6 +33,14 @@ ...@@ -33,6 +33,14 @@
33 <null/> 33 <null/>
34 </completers> 34 </completers>
35 </command> 35 </command>
36 + <command>
37 + <action class="org.onosproject.provider.nil.cli.NullDeviceCommand"/>
38 + <completers>
39 + <ref component-id="deviceIdCompleter"/>
40 + <ref component-id="upDownCompleter"/>
41 + <null/>
42 + </completers>
43 + </command>
36 </command-bundle> 44 </command-bundle>
37 45
38 <bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/> 46 <bean id="startStopCompleter" class="org.onosproject.cli.StartStopCompleter"/>
...@@ -40,5 +48,6 @@ ...@@ -40,5 +48,6 @@
40 <bean id="topoShapeCompleter" class="org.onosproject.provider.nil.cli.TopologyShapeCompleter"/> 48 <bean id="topoShapeCompleter" class="org.onosproject.provider.nil.cli.TopologyShapeCompleter"/>
41 <bean id="linkSrcCompleter" class="org.onosproject.cli.net.LinkSrcCompleter"/> 49 <bean id="linkSrcCompleter" class="org.onosproject.cli.net.LinkSrcCompleter"/>
42 <bean id="linkDstCompleter" class="org.onosproject.cli.net.LinkDstCompleter"/> 50 <bean id="linkDstCompleter" class="org.onosproject.cli.net.LinkDstCompleter"/>
51 + <bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
43 52
44 </blueprint> 53 </blueprint>
......