blob: da9ae5597a7b847087b57ef6182a0fdc8096cee5 [file] [log] [blame]
jaegonkim185299e2018-04-29 20:15:25 +09001/*
2 * Copyright 2015-present Open Networking Foundation
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 */
16package org.onosproject.cli.net;
17
18import com.google.common.base.MoreObjects;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.SetMultimap;
21import com.google.common.collect.Streams;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070022import org.apache.karaf.shell.api.action.Argument;
23import org.apache.karaf.shell.api.action.Command;
Ray Milkey0068fd02018-10-11 15:45:39 -070024import org.apache.karaf.shell.api.action.Completion;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070025import org.apache.karaf.shell.api.action.lifecycle.Service;
26import org.apache.karaf.shell.api.action.Option;
jaegonkim185299e2018-04-29 20:15:25 +090027import org.onosproject.cli.AbstractShellCommand;
28import org.onosproject.net.AnnotationKeys;
29import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.DefaultDevice;
31import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Link;
34import org.onosproject.net.LinkKey;
35import org.onosproject.net.Port;
36import org.onosproject.net.device.DeviceService;
37import org.onosproject.net.device.PortStatistics;
38import org.onosproject.net.flow.FlowEntry;
39import org.onosproject.net.flow.FlowRule;
40import org.onosproject.net.flow.FlowRuleService;
41import org.onosproject.net.intent.FlowRuleIntent;
42import org.onosproject.net.intent.Intent;
43import org.onosproject.net.intent.IntentService;
44import org.onosproject.net.intent.Key;
45import org.onosproject.net.intent.ObjectiveTrackerService;
46import org.onosproject.net.intent.PointToPointIntent;
47import org.onosproject.net.intent.WorkPartitionService;
48import org.onosproject.net.statistic.FlowStatisticService;
49
50import java.lang.reflect.Field;
51import java.util.ArrayList;
52import java.util.Collection;
53import java.util.HashMap;
54import java.util.HashSet;
55import java.util.List;
56import java.util.Map;
57import java.util.Objects;
58import java.util.Set;
59import java.util.stream.Stream;
60
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061@Service
jaegonkim185299e2018-04-29 20:15:25 +090062@Command(scope = "onos", name = "intents-diagnosis",
63 description = "Diagnosis intents")
64public class IntentsDiagnosisCommand extends AbstractShellCommand {
65
66 @Argument(index = 0, name = "key",
67 description = "Intent key",
68 required = false, multiValued = false)
Ray Milkey0068fd02018-10-11 15:45:39 -070069 @Completion(IntentKeyCompleter.class)
jaegonkim185299e2018-04-29 20:15:25 +090070 String key = null;
71
72 @Option(name = "-d", aliases = "--details", description = "printing intent details",
73 required = false, multiValued = false)
74 private boolean dump = false;
75
76 @Option(name = "-l", aliases = "--link", description = "printing local intentsByLink",
77 required = false, multiValued = false)
78 private boolean dumpIntentByLink = false;
79
80 private static final int MAX_INTENT_PATH = 100;
81 private static final String FIELD_INTENTS_BY_LINK = "intentsByLink";
82
83 @Override
Ray Milkeyd84f89b2018-08-17 14:54:17 -070084 protected void doExecute() {
jaegonkim185299e2018-04-29 20:15:25 +090085
86 print("intents-diagnosis");
87 ServiceRefs svcRefs = buildServiceRefs();
88 if (svcRefs == null) {
89 return;
90 }
91 try {
92 for (Intent intent : svcRefs.intentsService().getIntents()) {
93 if (key != null && !intent.key().toString().equals(key)) {
94 continue;
95 }
96 print("");
97 printIntentHdr(intent, svcRefs);
98 if (intent instanceof PointToPointIntent) {
99 diagnosisP2Pintent((PointToPointIntent) intent, svcRefs);
100 } else {
101 // TODO : it needs to implement other types of intent
102 print(" It doesn't support %s intent.", intent.getClass().getSimpleName());
103 }
104 }
105 if (dumpIntentByLink) {
106 dumpIntentsByLink(svcRefs);
107 }
108 } catch (Exception e) {
109 print("error: " + e);
110 }
111
112 }
113
114 private void printIntentHdr(Intent intent, ServiceRefs svcRefs) {
115 print("* intent key: %s", intent.key());
116 print(" - state: %s", svcRefs.intentsService().getIntentState(intent.key()));
117 dump(" - leader: %s %s", svcRefs.getWorkPartitionService().getLeader(intent.key(), Key::hash),
118 svcRefs.workPartitionService.isMine(intent.key(), Key::hash) ? "(Mine)" : "");
119 }
120
Ray Milkey30ab5152018-05-08 09:29:28 -0700121 private void dumpIntentsByLink(ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900122 Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);
123
124 print("* intentsbylink:");
125 for (Map.Entry<LinkKey, Key> entry : intentsByLink) {
126 print(" - %s, Intents: %s ", entry.getKey(), entry.getValue());
127 }
128 }
129
Ray Milkey30ab5152018-05-08 09:29:28 -0700130 private Set<Map.Entry<LinkKey, Key>> getIntentsByLinkSet(ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900131
Ray Milkey30ab5152018-05-08 09:29:28 -0700132 try {
jaegonkim185299e2018-04-29 20:15:25 +0900133
Ray Milkey30ab5152018-05-08 09:29:28 -0700134 ObjectiveTrackerService objTracker = svcRefs.getObjectiveTrackerService();
jaegonkim185299e2018-04-29 20:15:25 +0900135
Ray Milkey30ab5152018-05-08 09:29:28 -0700136 // Utilizing reflection instead of adding new interface for getting intentsByLink
137 Field f = objTracker.getClass().getDeclaredField(FIELD_INTENTS_BY_LINK);
138 f.setAccessible(true);
139 SetMultimap<LinkKey, Key> intentsByLink = (SetMultimap<LinkKey, Key>) f.get(objTracker);
140
141 return ImmutableSet.copyOf(intentsByLink.entries());
142 } catch (NoSuchFieldException | IllegalAccessException ex) {
143 error("error: " + ex);
144 return ImmutableSet.of();
145 }
jaegonkim185299e2018-04-29 20:15:25 +0900146 }
147
Ray Milkey30ab5152018-05-08 09:29:28 -0700148 private void diagnosisP2Pintent(PointToPointIntent intent, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900149
150 List<Intent> installableIntents = svcRefs.intentsService().getInstallableIntents(intent.key());
151
152 if (installableIntents.size() == 0) {
153 error("NO INSTALLABLE INTENTS");
154 return;
155 }
156
157 Set<String> notSupport = new HashSet<>();
158 for (Intent installable: installableIntents) {
159 if (installable instanceof FlowRuleIntent) {
160 checkP2PFlowRuleIntent(intent, (FlowRuleIntent) installable, svcRefs);
161 } else {
162 // TODO : it needs to implement other types of installables
163 notSupport.add(installable.getClass().getSimpleName());
164 }
165 }
166
167 if (notSupport.size() > 0) {
168 print(" It doesn't support %s.", notSupport);
169 }
170 }
171
Ray Milkey30ab5152018-05-08 09:29:28 -0700172 private void checkP2PFlowRuleIntent(PointToPointIntent intent, FlowRuleIntent installable, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900173
174 final Map<DeviceId, DeviceOnIntent> devs = createDevicesOnP2PIntent(intent, installable);
175
176 boolean errorOccurred = false;
177 // checking the number of links & CPs in P2P intent
178 for (DeviceOnIntent dev: devs.values()) {
179 if (dev.getIngressLinks().size() > 1) {
180 error("MULTIPLE NUMBER OF INGRESS LINKs on " + dev.deviceId()
181 + ": " + dev.getIngressLinks());
182 errorOccurred = true;
183 }
184 if (dev.getIngressCps().size() > 1) {
185 error("MULTIPLE NUMBER OF INGRESS CONNECT POINTs on " + dev.deviceId()
186 + ": " + dev.getIngressCps());
187 errorOccurred = true;
188 }
189 if (dev.getEgressLinks().size() > 1) {
190 error("MULTIPLE NUMBER OF EGRESS LINKs: on " + dev.deviceId()
191 + ": " + dev.getEgressLinks());
192 errorOccurred = true;
193 }
194 if (dev.getEgressCps().size() > 1) {
195 error("MULTIPLE NUMBER OF EGRESS CONNECT POINTs: on " + dev.deviceId()
196 + ": " + dev.getEgressCps());
197 errorOccurred = true;
198 }
199 }
200
201 ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
202 DeviceOnIntent startDev = devs.get(startCp.deviceId());
203 if (startDev == null) {
204 error("STARTING CONNECT POINT DEVICE: " + startCp.deviceId() + " is not on intent");
205 errorOccurred = true;
206 }
207
208 ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
209 DeviceOnIntent endDev = devs.get(endCp.deviceId());
210 if (endDev == null) {
211 error("END CONNECT POINT DEVICE: " + endCp.deviceId() + " is not on intent");
212 errorOccurred = true;
213 }
214
215 if (!errorOccurred) {
216 // Per device checking with path-order
217 DeviceOnIntent dev = startDev;
218 int i = 0;
219 for (; i < MAX_INTENT_PATH; i++) {
220 perDeviceChecking(dev, svcRefs);
221
222 // P2P intent has only 1 egress CP
223 ConnectPoint egressCp = dev.getEgressCps().stream().findFirst().orElse(null);
224 if (egressCp != null && Objects.equals(endCp, egressCp)) {
225 break;
226 }
227
228 // P2P intent has only 1 egress link
229 Link egressLink = dev.getEgressLinks().stream().findFirst().orElse(null);
230 if (egressLink == null) {
231 error("INVALID EGRESS LINK & CONNECT POINT for: " + dev);
232 errorOccurred = true;
233 break;
234 }
235 if (Objects.equals(egressLink.dst(), endCp)) {
236 break;
237 }
238
239 // P2P intent only 1 ingress link
240 dev = devs.values().stream()
241 .filter(nextDev -> Objects.equals(
242 egressLink, nextDev.getIngressLinks().stream().findFirst().orElse(null)))
243 .findAny().orElse(null);
244 if (dev == null) {
245 error("FAILED TO FIND NEXT DEV for: " + dev + ", LINK: " + egressLink);
246 errorOccurred = true;
247 break;
248 }
249 }
250 if (i == MAX_INTENT_PATH) {
251 error("MAX INTENT PATH WAS EXCEEDED");
252 errorOccurred = true;
253 }
254 }
255
256 if (errorOccurred) {
257 // Installable checking
258 dump("");
259 dump("ERROR OCCURRED. DO PER FLOW CHECKING");
260 perFlowRuleChecking(installable, svcRefs);
261 }
262
263 if (svcRefs.workPartitionService.isMine(intent.key(), Key::hash)) {
264 checkIntentsByLink(installable, svcRefs);
265 }
266 }
267
Ray Milkey30ab5152018-05-08 09:29:28 -0700268 private void checkIntentsByLink(FlowRuleIntent installable, ServiceRefs svcRefs) {
jaegonkim185299e2018-04-29 20:15:25 +0900269
270 Set<Map.Entry<LinkKey, Key>> intentsByLink = getIntentsByLinkSet(svcRefs);
271
272 installable.resources().forEach(
273 rsrc -> {
274 if (rsrc instanceof Link) {
275 Link link = (Link) rsrc;
276 LinkKey linkKey = LinkKey.linkKey(link);
277 intentsByLink.stream()
278 .filter(entry -> Objects.equals(entry.getKey(), linkKey)
279 && Objects.equals(entry.getValue(), installable.key()))
280 .findAny()
281 .orElseGet(() -> {
282 error("FAILED TO FIND LINK(" + link + ") for intents: " + installable.key());
283 return null;
284 });
285 }
286 }
287 );
288 }
289
290 // TODO: It needs to consider FLowObjectiveIntent case
291 private void perDeviceChecking(DeviceOnIntent devOnIntent, ServiceRefs svcRefs) {
292
293 Collection<PortStatistics> portStats =
294 svcRefs.deviceService().getPortStatistics(devOnIntent.deviceId());
295 Collection<PortStatistics> portDeltaStats =
296 svcRefs.deviceService().getPortDeltaStatistics(devOnIntent.deviceId());
297
298 dump("");
299 dump(" ------------------------------------------------------------------------------------------");
300
301 Device device = svcRefs.deviceService.getDevice(devOnIntent.deviceId());
302 if (device == null) {
303 error("INVALID DEVICE for " + devOnIntent.deviceId());
304 return;
305 }
306
307 dump(" %s", getDeviceString(device));
308 dump(" %s", device.annotations());
309
310 devOnIntent.getIngressCps().stream()
311 .forEach(cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "INGRESS", svcRefs));
312
313 Stream<FlowEntry> flowEntries = Streams.stream(svcRefs.flowService.getFlowEntries(devOnIntent.deviceId()));
314
315 devOnIntent.getFlowRules().stream()
316 .forEach(
317 intentFlowRule -> {
318 FlowEntry matchedEntry = flowEntries
319 .filter(entry -> Objects.equals(intentFlowRule.id(), entry.id()))
320 .findFirst().orElse(null);
321
322 if (matchedEntry == null) {
323 error("FAILED TO FIND FLOW ENTRY: for " + intentFlowRule);
324 return;
325 }
326
327 if (Objects.equals(intentFlowRule.selector(), matchedEntry.selector()) &&
328 Objects.equals(intentFlowRule.treatment(), matchedEntry.treatment())) {
329 dumpFlowEntry(matchedEntry, "FLOW ENTRY");
330 return;
331 }
332
333 error("INSTALLABLE-FLOW ENTRY mismatch");
334 dumpFlowRule(intentFlowRule, "INSTALLABLE");
335 dumpFlowEntry(matchedEntry, "FLOW ENTRY");
336 }
337 );
338
339 devOnIntent.getEgressCps().stream()
340 .forEach(
341 cp -> dumpCpStatistics(cp, portStats, portDeltaStats, "EGRESS", svcRefs)
342 );
343 }
344
345 // TODO: It needs to consider FLowObjectiveIntent case
346 private void perFlowRuleChecking(FlowRuleIntent installable, ServiceRefs svcRefs) {
347
348 installable.flowRules().forEach(
349 flowrule -> {
350 DeviceId devId = flowrule.deviceId();
351 if (devId == null) {
352 error("INVALID DEVICE ID for " + flowrule);
353 return;
354 }
355
356 Device dev = svcRefs.deviceService.getDevice(devId);
357 if (dev == null) {
358 error("INVALID DEVICE for " + flowrule);
359 return;
360 }
361
362 dump("");
363 dump(
364 " ------------------------------------------------------------------------------------------");
365 dump(" %s", getDeviceString(dev));
366 dump(" %s", dev.annotations());
367
368 svcRefs.flowService().getFlowEntries(devId)
369 .forEach(
370 entry -> {
371 dumpFlowRule(flowrule, "INSTALLABLE");
372 dumpFlowEntry(entry, "FLOW ENTRY");
373
374 if (!flowrule.selector().equals(entry.selector())) {
375 return;
376 }
377 if (flowrule.id().equals(entry.id()) &&
378 flowrule.treatment().equals(entry.treatment())) {
379 dumpFlowEntry(entry, "FLOW ENTRY");
380 return;
381 }
382 error("INSTALLABLE-FLOW ENTRY mismatch");
383 }
384 );
385 }
386 );
387 }
388
389 private Map<DeviceId, DeviceOnIntent> createDevicesOnP2PIntent(
390 PointToPointIntent intent, FlowRuleIntent flowRuleIntent) {
391
392 final Map<DeviceId, DeviceOnIntent> devMap = new HashMap<>();
393
394 flowRuleIntent.resources().forEach(
395 rsrc -> {
396 if (rsrc instanceof Link) {
397 Link link = (Link) rsrc;
398 ConnectPoint srcCp = link.src();
399 ConnectPoint dstCp = link.dst();
400 try {
401 DeviceOnIntent dev = devMap.computeIfAbsent(srcCp.deviceId(), DeviceOnIntent::new);
Ray Milkey30ab5152018-05-08 09:29:28 -0700402 dev.addEgressLink(link);
403
jaegonkim185299e2018-04-29 20:15:25 +0900404 dev = devMap.computeIfAbsent(dstCp.deviceId(), DeviceOnIntent::new);
Ray Milkey30ab5152018-05-08 09:29:28 -0700405 dev.addIngressLink(link);
jaegonkim185299e2018-04-29 20:15:25 +0900406 } catch (IllegalStateException e) {
407 print("error: " + e);
408 }
409 }
410 }
411 );
412
413 ConnectPoint startCp = intent.filteredIngressPoint().connectPoint();
414 DeviceOnIntent startDev = devMap.computeIfAbsent(startCp.deviceId(), DeviceOnIntent::new);
415 if (!startDev.hasIngressCp(startCp)) {
416 startDev.addIngressCp(startCp);
417 }
418
419 ConnectPoint endCp = intent.filteredEgressPoint().connectPoint();
420 DeviceOnIntent endDev = devMap.computeIfAbsent(endCp.deviceId(), DeviceOnIntent::new);
421 if (!endDev.hasEgressCp(endCp)) {
422 endDev.addEgessCp(endCp);
423 }
424
425 flowRuleIntent.flowRules().forEach(
426 flowRule -> {
427 DeviceId devId = flowRule.deviceId();
428 if (devId == null) {
429 error("INVALID DEVICE ID for " + flowRule);
430 return;
431 }
432 DeviceOnIntent dev = devMap.get(devId);
433 if (dev == null) {
434 error("DEVICE(" + devId + ") IS NOT ON INTENTS LINKS");
435 return;
436 }
437
438 dev.addFlowRule(flowRule);
439 }
440 );
441
442 return devMap;
443 }
444
445 private String getDeviceString(Device dev) {
446
447 StringBuilder buf = new StringBuilder();
448 if (dev != null) {
449 buf.append(String.format("Device: %s, ", dev.id()));
450 buf.append(String.format("%s, ", dev.type()));
451 buf.append(String.format("%s, ", dev.manufacturer()));
452 buf.append(String.format("%s, ", dev.hwVersion()));
453 buf.append(String.format("%s, ", dev.swVersion()));
454 if (dev instanceof DefaultDevice) {
455 DefaultDevice dfltDev = (DefaultDevice) dev;
456 if (dfltDev.driver() != null) {
457 buf.append(String.format("%s, ", dfltDev.driver().name()));
458 }
459 String channelId = dfltDev.annotations().value("channelId");
460 if (channelId != null) {
461 buf.append(String.format("%s, ", channelId));
462 }
463 }
464 }
465
466 return buf.toString();
467 }
468
469 private void dumpFlowRule(FlowRule rule, String hdr) {
470 dump(" " + hdr + ":");
471 dump(" - id=%s, priority=%d", rule.id(), rule.priority());
472 dump(" - %s", rule.selector());
473 dump(" - %s", rule.treatment());
474 }
475
476 private void dumpFlowEntry(FlowEntry entry, String hdr) {
477 dumpFlowRule(entry, hdr);
478 dump(" - packets=%d", entry.packets());
479 }
480
481
482 private void dumpCpStatistics(ConnectPoint cp, Collection<PortStatistics> devPortStats,
483 Collection<PortStatistics> devPortDeltaStats, String direction, ServiceRefs svcs) {
484 if (cp == null) {
485 return;
486 }
487
488 dump(" %s:", direction);
489
490 if (cp.port().isLogical()) {
491 dump(" - logical: device: %s, port: %s", cp.deviceId(), cp.port());
492 return;
493 }
494
495 Port port = svcs.deviceService.getPort(cp.deviceId(), cp.port());
496 if (port == null) {
497 return;
498 }
499
500 try {
501 devPortStats.stream()
502 .filter(stat -> stat.portNumber().equals(cp.port()))
503 .forEach(stat -> dump(" - stat : %s:", getPortStatStr(stat, port)));
504 } catch (IllegalStateException e) {
505 error("error: " + e);
506 return;
507 }
508
509 try {
510 devPortDeltaStats.stream()
511 .filter(stat -> stat.portNumber().equals(cp.port()))
512 .forEach(stat -> dump(" - delta : %s:", getPortStatStr(stat, port)));
513 } catch (IllegalStateException e) {
514 error("error: " + e);
515 }
516 }
517
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700518 private void dump(String format, Object... args) {
jaegonkim185299e2018-04-29 20:15:25 +0900519 if (dump) {
520 print(format, args);
521 }
522 }
523
524 private String getPortStatStr(PortStatistics stat, Port port) {
525
526 final String portName = port.annotations().value(AnnotationKeys.PORT_NAME);
527
528 return String.format("port: %s(%s), ", stat.portNumber(), portName) +
529 String.format("enabled: %b, ", port.isEnabled()) +
530 String.format("pktRx: %d, ", stat.packetsReceived()) +
531 String.format("pktTx: %d, ", stat.packetsSent()) +
532 String.format("pktRxErr: %d, ", stat.packetsRxErrors()) +
533 String.format("pktTxErr: %d, ", stat.packetsTxErrors()) +
534 String.format("pktRxDrp: %d, ", stat.packetsRxDropped()) +
535 String.format("pktTxDrp: %d", stat.packetsTxDropped());
536 }
537
538 private static class DeviceOnIntent {
539
540 private final DeviceId devId;
541
542 private Collection<Link> ingressLinks = new ArrayList<>();
543
544 private Collection<Link> egressLinks = new ArrayList<>();
545
546 private Collection<ConnectPoint> ingressCps = new ArrayList<>();
547
548 private Collection<ConnectPoint> egressCps = new ArrayList<>();
549
550 private Collection<FlowRule> flowRules = new ArrayList<>();
551
552 public DeviceOnIntent(DeviceId devId) {
553 this.devId = devId;
554 }
555
556 public DeviceId deviceId() {
557 return devId;
558 }
559
560 public Collection<Link> getIngressLinks() {
561 return ingressLinks;
562 }
563
564 public Collection<Link> getEgressLinks() {
565 return egressLinks;
566 }
567
568 public void addIngressLink(Link link) {
569 ingressLinks.add(link);
570 addIngressCp(link.dst());
571 }
572
573 public void addEgressLink(Link link) {
574 egressLinks.add(link);
575 addEgessCp(link.src());
576 }
577
578 public void addIngressCp(ConnectPoint cp) {
579 ingressCps.add(cp);
580 }
581
582 public void addEgessCp(ConnectPoint cp) {
583 egressCps.add(cp);
584 }
585
586 public boolean hasIngressCp(final ConnectPoint cp) {
587 return ingressCps.stream().anyMatch(icp -> Objects.equals(icp, cp));
588 }
589
590 public boolean hasEgressCp(ConnectPoint cp) {
591 return egressCps.stream().anyMatch(ecp -> Objects.equals(ecp, cp));
592 }
593
594 public Collection<ConnectPoint> getIngressCps() {
595 return ingressCps;
596 }
597
598 public Collection<ConnectPoint> getEgressCps() {
599 return egressCps;
600 }
601
602 public Collection<FlowRule> getFlowRules() {
603 return flowRules;
604 }
605
606 public void addFlowRule(FlowRule flowRule) {
607 flowRules.add(flowRule);
608 }
609
Yuta HIGUCHIe7e71a82018-05-18 16:36:43 -0700610 @Override
jaegonkim185299e2018-04-29 20:15:25 +0900611 public String toString() {
612 return MoreObjects.toStringHelper(getClass())
613 .omitNullValues()
614 .add("devId", devId)
615 .add("ingressLinks", ingressLinks)
616 .add("egressLinks", egressLinks)
617 .add("flowRules", flowRules)
618 .toString();
619 }
620 }
621
622
623 private ServiceRefs buildServiceRefs() {
624 IntentService intentsService = get(IntentService.class);
625 if (intentsService == null) {
626 return null;
627 }
628 DeviceService deviceService = get(DeviceService.class);
629 if (deviceService == null) {
630 return null;
631 }
632 FlowStatisticService flowStatsService = get(FlowStatisticService.class);
633 if (flowStatsService == null) {
634 return null;
635 }
636 FlowRuleService flowService = get(FlowRuleService.class);
637 if (flowService == null) {
638 return null;
639 }
640 WorkPartitionService workPartitionService = get(WorkPartitionService.class);
641 if (workPartitionService == null) {
642 return null;
643 }
644 ObjectiveTrackerService objectiveTrackerService = get(ObjectiveTrackerService.class);
645 if (objectiveTrackerService == null) {
646 return null;
647 }
648
649 return new ServiceRefs(
650 intentsService,
651 deviceService,
652 flowService,
653 workPartitionService,
654 objectiveTrackerService
655 );
656 }
657
658 private static final class ServiceRefs {
659
660 private IntentService intentsService;
661 private DeviceService deviceService;
662 private FlowRuleService flowService;
663 private WorkPartitionService workPartitionService;
664 private ObjectiveTrackerService objectiveTrackerService;
665
666 private ServiceRefs(
667 IntentService intentsService,
668 DeviceService deviceService,
669 FlowRuleService flowService,
670 WorkPartitionService workPartitionService,
671 ObjectiveTrackerService objectiveTrackerService
672 ) {
673 this.intentsService = intentsService;
674 this.deviceService = deviceService;
675 this.flowService = flowService;
676 this.workPartitionService = workPartitionService;
677 this.objectiveTrackerService = objectiveTrackerService;
678 }
679
680 public IntentService intentsService() {
681 return intentsService;
682 }
683
684 public DeviceService deviceService() {
685 return deviceService;
686 }
687
688 public FlowRuleService flowService() {
689 return flowService;
690 }
691
692 public WorkPartitionService getWorkPartitionService() {
693 return workPartitionService;
694 }
695
696 public ObjectiveTrackerService getObjectiveTrackerService() {
697 return objectiveTrackerService;
698 }
699 }
700
701}