blob: 8d4ac949fcf904c68a752517792b0fb6de9b8653 [file] [log] [blame]
Jian Li0b93b002018-07-31 13:41:08 +09001/*
2 * Copyright 2018-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.openstacktroubleshoot.cli;
17
Jian Lie189c1c2018-08-08 15:55:08 +090018import com.google.common.collect.Sets;
Ray Milkey86ad7bb2018-09-27 12:32:28 -070019import org.apache.karaf.shell.api.action.Argument;
20import org.apache.karaf.shell.api.action.Command;
21import org.apache.karaf.shell.api.action.Option;
Ray Milkey7a2dee52018-09-28 10:58:28 -070022import org.apache.karaf.shell.api.action.lifecycle.Service;
Jian Lie189c1c2018-08-08 15:55:08 +090023import org.onlab.packet.IpAddress;
Jian Li0b93b002018-07-31 13:41:08 +090024import org.onosproject.cli.AbstractShellCommand;
Jian Li43d04282018-08-22 14:31:21 +090025import org.onosproject.cluster.ClusterService;
26import org.onosproject.cluster.NodeId;
27import org.onosproject.mastership.MastershipService;
Jian Lie189c1c2018-08-08 15:55:08 +090028import org.onosproject.openstacknetworking.api.InstancePort;
29import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li43d04282018-08-22 14:31:21 +090030import org.onosproject.openstacknode.api.OpenstackNode;
31import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li0b93b002018-07-31 13:41:08 +090032import org.onosproject.openstacktroubleshoot.api.OpenstackTroubleshootService;
33import org.onosproject.openstacktroubleshoot.api.Reachability;
34
Jian Lie189c1c2018-08-08 15:55:08 +090035import java.util.Optional;
36import java.util.Set;
Jian Li9171c002018-08-19 22:58:40 +090037import java.util.concurrent.ExecutorService;
Jian Lie189c1c2018-08-08 15:55:08 +090038import java.util.stream.Collectors;
Jian Li0b93b002018-07-31 13:41:08 +090039
Jian Li9171c002018-08-19 22:58:40 +090040import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
41import static org.onlab.util.Tools.groupedThreads;
Jian Lic38e9032018-08-09 17:08:38 +090042import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Jian Li43d04282018-08-22 14:31:21 +090043import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lic38e9032018-08-09 17:08:38 +090044
Jian Li0b93b002018-07-31 13:41:08 +090045/**
46 * Checks the east-west VMs connectivity.
47 */
Ray Milkey7a2dee52018-09-28 10:58:28 -070048@Service
Jian Li0b93b002018-07-31 13:41:08 +090049@Command(scope = "onos", name = "openstack-check-east-west",
50 description = "Checks the east-west VMs connectivity")
51public class OpenstackEastWestProbeCommand extends AbstractShellCommand {
52
53 private static final String REACHABLE = "Reachable :)";
54 private static final String UNREACHABLE = "Unreachable :(";
55 private static final String ARROW = "->";
56
57 private static final String FORMAT = "%-20s%-5s%-20s%-20s";
58
Jian Lie189c1c2018-08-08 15:55:08 +090059 @Option(name = "-a", aliases = "--all", description = "Apply this command to all VMs",
60 required = false, multiValued = false)
61 private boolean isAll = false;
62
63 @Argument(index = 0, name = "vmIps", description = "VMs' IP addresses",
64 required = false, multiValued = true)
65 private String[] vmIps = null;
66
Jian Li9171c002018-08-19 22:58:40 +090067 private final ExecutorService probeExecutor = newSingleThreadScheduledExecutor(
68 groupedThreads(this.getClass().getSimpleName(), "probe-handler", log));
69
Jian Li0b93b002018-07-31 13:41:08 +090070 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -070071 protected void doExecute() {
Jian Li43d04282018-08-22 14:31:21 +090072 OpenstackTroubleshootService tsService = get(OpenstackTroubleshootService.class);
Jian Lic38e9032018-08-09 17:08:38 +090073 InstancePortService instPortService = get(InstancePortService.class);
Jian Li43d04282018-08-22 14:31:21 +090074 MastershipService mastershipService = get(MastershipService.class);
75 ClusterService clusterService = get(ClusterService.class);
76 OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
Jian Lie189c1c2018-08-08 15:55:08 +090077
78 if (tsService == null) {
Jian Li0b93b002018-07-31 13:41:08 +090079 error("Failed to troubleshoot openstack networking.");
80 return;
81 }
82
Jian Lie189c1c2018-08-08 15:55:08 +090083 if ((!isAll && vmIps == null) || (isAll && vmIps != null)) {
84 print("Please specify one of VM IP address or -a option.");
85 return;
86 }
87
Jian Li43d04282018-08-22 14:31:21 +090088 NodeId localNodeId = clusterService.getLocalNode().id();
89
90 for (OpenstackNode node : osNodeService.completeNodes(COMPUTE)) {
91 if (!localNodeId.equals(mastershipService.getMasterFor(node.intgBridge()))) {
92 error("Current node is not the master for all compute nodes. " +
93 "Please enforce mastership first using openstack-reset-mastership -c !");
94 return;
95 }
96 }
97
Jian Lie189c1c2018-08-08 15:55:08 +090098 if (isAll) {
99 printHeader();
Jian Lic38e9032018-08-09 17:08:38 +0900100 // send ICMP PACKET_OUT to all connect VMs whose instance port state is ACTIVE
101 Set<InstancePort> activePorts = instPortService.instancePorts().stream()
102 .filter(p -> p.state() == ACTIVE)
103 .collect(Collectors.toSet());
104
105 activePorts.forEach(srcPort ->
106 activePorts.forEach(dstPort ->
107 printReachability(tsService.probeEastWest(srcPort, dstPort))
108 )
109 );
Jian Lie189c1c2018-08-08 15:55:08 +0900110 } else {
111 if (vmIps.length > 2) {
112 print("Too many VM IPs. The number of IP should be limited to 2.");
113 return;
114 }
115
Jian Lic38e9032018-08-09 17:08:38 +0900116 IpAddress srcIp = getIpAddress(vmIps[0]);
117
118 if (srcIp == null) {
119 return;
120 }
121
Jian Lie189c1c2018-08-08 15:55:08 +0900122 InstancePort srcPort = instPort(instPortService, srcIp);
123
124 if (srcPort == null) {
125 print("Specified source IP is not existing.");
126 return;
127 }
128
129 final Set<IpAddress> dstIps = Sets.newConcurrentHashSet();
130
131 if (vmIps.length == 2) {
Jian Lic38e9032018-08-09 17:08:38 +0900132 IpAddress dstIp = getIpAddress(vmIps[1]);
133
134 if (dstIp == null) {
135 return;
136 }
137
138 dstIps.add(dstIp);
Jian Lie189c1c2018-08-08 15:55:08 +0900139 }
140
141 if (vmIps.length == 1) {
142 dstIps.addAll(instPortService.instancePorts().stream()
143 .filter(p -> !p.ipAddress().equals(srcIp))
144 .filter(p -> p.state().equals(InstancePort.State.ACTIVE))
145 .map(InstancePort::ipAddress)
146 .collect(Collectors.toSet()));
147 }
148
149 printHeader();
150 dstIps.stream()
151 .filter(ip -> instPort(instPortService, ip) != null)
152 .map(ip -> instPort(instPortService, ip))
Jian Li9171c002018-08-19 22:58:40 +0900153 .forEach(port -> probeExecutor.execute(() ->
154 printReachability(tsService.probeEastWest(srcPort, port))));
Jian Lie189c1c2018-08-08 15:55:08 +0900155 }
156 }
157
158 private InstancePort instPort(InstancePortService service, IpAddress ip) {
159 Optional<InstancePort> port = service.instancePorts().stream()
160 .filter(p -> p.ipAddress().equals(ip)).findFirst();
161
162 if (port.isPresent()) {
163 return port.get();
164 } else {
165 print("Specified destination IP is not existing.");
166 return null;
167 }
168 }
169
170 private void printHeader() {
Jian Li0b93b002018-07-31 13:41:08 +0900171 print(FORMAT, "Source IP", "", "Destination IP", "Reachability");
Jian Lie189c1c2018-08-08 15:55:08 +0900172 }
Jian Li0b93b002018-07-31 13:41:08 +0900173
Jian Lie189c1c2018-08-08 15:55:08 +0900174 private void printReachability(Reachability r) {
175 String result = r.isReachable() ? REACHABLE : UNREACHABLE;
176 print(FORMAT, r.srcIp().toString(), ARROW, r.dstIp().toString(), result);
Jian Li0b93b002018-07-31 13:41:08 +0900177 }
Jian Lic38e9032018-08-09 17:08:38 +0900178
179 private IpAddress getIpAddress(String ipString) {
180 try {
181 return IpAddress.valueOf(vmIps[0]);
182 } catch (IllegalArgumentException e) {
183 error("Invalid IP address string.");
184 return null;
185 }
186 }
Jian Li0b93b002018-07-31 13:41:08 +0900187}