blob: 4145cd2aea7346732993f16c46b769e95fbdec0a [file] [log] [blame]
Yi Tseng2e5d99e2017-06-06 10:58:46 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Yi Tseng2e5d99e2017-06-06 10:58:46 -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 */
16
17package org.onosproject.dhcprelay.cli;
18
Kalhee Kimd94ceea2017-11-29 19:03:02 +000019
Ray Milkey86ad7bb2018-09-27 12:32:28 -070020import org.apache.karaf.shell.api.action.Argument;
21import org.apache.karaf.shell.api.action.Command;
Ray Milkey58dd64e2018-10-03 11:30:46 -070022import org.apache.karaf.shell.api.action.Completion;
Ray Milkey7a2dee52018-09-28 10:58:28 -070023import org.apache.karaf.shell.api.action.lifecycle.Service;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070024import org.onlab.packet.IpAddress;
25import org.onlab.packet.MacAddress;
26import org.onlab.packet.VlanId;
Yi Tseng13a41a12017-07-26 13:45:01 -070027import org.onlab.util.Tools;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070028import org.onosproject.cli.AbstractShellCommand;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000029import org.onosproject.dhcprelay.store.DhcpRelayCounters;
Yi Tseng919b2df2017-09-07 16:22:51 -070030import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng51301292017-07-28 13:02:59 -070031import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070032import org.onosproject.dhcprelay.store.DhcpRecord;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070033import org.onosproject.net.Host;
34import org.onosproject.net.HostId;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070035import org.onosproject.net.host.HostService;
36
Yi Tseng2e5d99e2017-06-06 10:58:46 -070037import java.util.Collection;
Yi Tseng919b2df2017-09-07 16:22:51 -070038import java.util.List;
Yi Tseng13a41a12017-07-26 13:45:01 -070039import java.util.function.Predicate;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000040import java.util.Map;
41
Yi Tseng2e5d99e2017-06-06 10:58:46 -070042
43/**
44 * Prints DHCP server and DHCP relay status.
45 */
Ray Milkey7a2dee52018-09-28 10:58:28 -070046@Service
Yi Tseng2e5d99e2017-06-06 10:58:46 -070047@Command(scope = "onos", name = "dhcp-relay", description = "DHCP relay app cli.")
48public class DhcpRelayCommand extends AbstractShellCommand {
Kalhee Kimd94ceea2017-11-29 19:03:02 +000049 @Argument(index = 0, name = "counter",
50 description = "shows counter values",
51 required = false, multiValued = false)
Ray Milkey58dd64e2018-10-03 11:30:46 -070052 @Completion(DhcpRelayCounterCompleter.class)
Kalhee Kimd94ceea2017-11-29 19:03:02 +000053 String counter = null;
54
55 @Argument(index = 1, name = "reset",
56 description = "reset counters or not",
57 required = false, multiValued = false)
Ray Milkey58dd64e2018-10-03 11:30:46 -070058 @Completion(DhcpRelayResetCompleter.class)
Kalhee Kimd94ceea2017-11-29 19:03:02 +000059 String reset = null;
60
61
62
63 private static final String CONUTER_HEADER = "DHCP Relay Counters :";
64 private static final String COUNTER_HOST = "Counters for id=%s/%s, locations=%s%s";
65
66
Yi Tseng2e5d99e2017-06-06 10:58:46 -070067 private static final String HEADER = "DHCP relay records ([D]: Directly connected):";
68 private static final String NO_RECORDS = "No DHCP relay record found";
Yi Tseng13a41a12017-07-26 13:45:01 -070069 private static final String HOST = "id=%s/%s, locations=%s%s, last-seen=%s, IPv4=%s, IPv6=%s";
Yi Tsengbeea16e2017-11-15 13:39:01 -080070 private static final String DHCP_SERVER_GW = "DHCP Server: %s, %s via %s (Mac: %s)";
71 private static final String DHCP_SERVER = "DHCP Server: %s, %s (Mac: %s)";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070072 private static final String MISSING_SERVER_CFG = "DHCP Server info not available";
Yi Tseng13a41a12017-07-26 13:45:01 -070073 private static final String DIRECTLY = "[D]";
74 private static final String EMPTY = "";
75 private static final String NA = "N/A";
76 private static final String STATUS_FMT = "[%s, %s]";
77 private static final String STATUS_FMT_NH = "[%s via %s, %s]";
Kalhee Kimd94ceea2017-11-29 19:03:02 +000078 private static final String STATUS_FMT_V6 = "[%s %d, %d ms %s %d %d ms, %s]";
79 private static final String STATUS_FMT_V6_NH = "[%s %d %d ms, %s %d %d ms via %s, %s]";
Yi Tseng919b2df2017-09-07 16:22:51 -070080 private static final String DEFAULT_SERVERS = "Default DHCP servers:";
81 private static final String INDIRECT_SERVERS = "Indirect DHCP servers:";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070082
83 private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070084 private static final HostService HOST_SERVICE = get(HostService.class);
Yi Tseng13a41a12017-07-26 13:45:01 -070085
Kalhee Kimd94ceea2017-11-29 19:03:02 +000086
Yi Tseng2e5d99e2017-06-06 10:58:46 -070087 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -070088 protected void doExecute() {
Yi Tseng919b2df2017-09-07 16:22:51 -070089 List<DhcpServerInfo> defaultDhcpServerInfoList = DHCP_RELAY_SERVICE.getDefaultDhcpServerInfoList();
90 List<DhcpServerInfo> indirectDhcpServerInfoList = DHCP_RELAY_SERVICE.getIndirectDhcpServerInfoList();
91
92 if (defaultDhcpServerInfoList.isEmpty() && indirectDhcpServerInfoList.isEmpty()) {
Yi Tseng2e5d99e2017-06-06 10:58:46 -070093 print(MISSING_SERVER_CFG);
94 return;
95 }
96
Yi Tseng919b2df2017-09-07 16:22:51 -070097 if (!defaultDhcpServerInfoList.isEmpty()) {
98 print(DEFAULT_SERVERS);
99 listServers(defaultDhcpServerInfoList);
100 }
101 if (!indirectDhcpServerInfoList.isEmpty()) {
102 print(INDIRECT_SERVERS);
103 listServers(indirectDhcpServerInfoList);
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700104 }
105
106 // DHCP records
107 Collection<DhcpRecord> records = DHCP_RELAY_SERVICE.getDhcpRecords();
108 if (records.isEmpty()) {
109 print(NO_RECORDS);
110 return;
111 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000112
113 // Handle display of counters
114 boolean toResetFlag;
115
116 if (counter != null) {
rsahot0362c2c6cc2018-06-22 14:35:07 -0400117 if (counter.equals("counter") || counter.equals("[counter]")) {
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000118 print(CONUTER_HEADER);
119 } else {
120 print("first parameter is [counter]");
121 return;
122 }
123 if (reset != null) {
124 if (reset.equals("reset") || reset.equals("[reset]")) {
125 toResetFlag = true;
126 } else {
127 print("Last parameter is [reset]");
128 return;
129 }
130 } else {
131 toResetFlag = false;
132 }
133
134 records.forEach(record -> {
135 print(COUNTER_HOST, record.macAddress(),
136 record.vlanId(),
137 record.locations(),
138 record.directlyConnected() ? DIRECTLY : EMPTY);
139 DhcpRelayCounters v6Counters = record.getV6Counters();
140 Map<String, Integer> countersMap = v6Counters.getCounters();
141 countersMap.forEach((name, value) -> {
142 print("%-30s ............................ %-4d packets", name, value);
143 });
144 if (toResetFlag) {
145 v6Counters.resetCounters();
146 record.updateLastSeen();
147 DHCP_RELAY_SERVICE.updateDhcpRecord(HostId.hostId(record.macAddress(), record.vlanId()), record);
148 }
149 });
150
151
152 return;
153 }
154
155
156 // Handle display of records
157
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700158 print(HEADER);
Yi Tseng13a41a12017-07-26 13:45:01 -0700159 records.forEach(record -> print(HOST,
160 record.macAddress(),
161 record.vlanId(),
162 record.locations(),
163 record.directlyConnected() ? DIRECTLY : EMPTY,
164 Tools.timeAgo(record.lastSeen()),
165 ip4State(record),
166 ip6State(record)));
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700167 }
168
Yi Tseng919b2df2017-09-07 16:22:51 -0700169 private void listServers(List<DhcpServerInfo> dhcpServerInfoList) {
170 dhcpServerInfoList.forEach(dhcpServerInfo -> {
171 String connectPoint = dhcpServerInfo.getDhcpServerConnectPoint()
172 .map(Object::toString).orElse(NA);
173 String serverMac = dhcpServerInfo.getDhcpConnectMac()
174 .map(Object::toString).orElse(NA);
175 String gatewayAddress;
176 String serverIp;
Yi Tseng919b2df2017-09-07 16:22:51 -0700177
178 switch (dhcpServerInfo.getVersion()) {
179 case DHCP_V4:
180 gatewayAddress = dhcpServerInfo.getDhcpGatewayIp4()
181 .map(Object::toString).orElse(null);
182 serverIp = dhcpServerInfo.getDhcpServerIp4()
183 .map(Object::toString).orElse(NA);
Yi Tseng919b2df2017-09-07 16:22:51 -0700184 break;
185 case DHCP_V6:
186 gatewayAddress = dhcpServerInfo.getDhcpGatewayIp6()
187 .map(Object::toString).orElse(null);
188 serverIp = dhcpServerInfo.getDhcpServerIp6()
189 .map(Object::toString).orElse(NA);
Yi Tseng919b2df2017-09-07 16:22:51 -0700190 break;
191 default:
192 return;
193 }
194 if (gatewayAddress != null) {
Yi Tseng25bfe372017-11-03 16:27:32 -0700195 print(DHCP_SERVER_GW, connectPoint, serverIp, gatewayAddress, serverMac);
Yi Tseng919b2df2017-09-07 16:22:51 -0700196 } else {
Yi Tseng25bfe372017-11-03 16:27:32 -0700197 print(DHCP_SERVER, connectPoint, serverIp, serverMac);
Yi Tseng919b2df2017-09-07 16:22:51 -0700198 }
199 });
200 }
201
Yi Tseng13a41a12017-07-26 13:45:01 -0700202 private String ip4State(DhcpRecord record) {
203 String nextHopIp = findNextHopIp(IpAddress::isIp4,
204 record.nextHop().orElse(null),
205 record.vlanId());
206 return ipState(record.ip4Address().map(Object::toString).orElse(NA),
207 record.ip4Status().map(Object::toString).orElse(NA),
208 record.directlyConnected(),
209 nextHopIp);
210 }
211
212 private String ip6State(DhcpRecord record) {
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000213 String nextHopIp = findNextHopIp6(IpAddress::isIp6,
Yi Tseng13a41a12017-07-26 13:45:01 -0700214 record.nextHop().orElse(null),
215 record.vlanId());
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000216
217 if (record.directlyConnected()) {
218 return String.format(STATUS_FMT_V6,
219 record.ip6Address().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000220 record.addrPrefTime(),
221 record.getLastIp6Update(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000222 record.pdPrefix().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000223 record.pdPrefTime(),
224 record.getLastPdUpdate(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000225 record.ip6Status().map(Object::toString).orElse(NA));
226 } else {
227 return String.format(STATUS_FMT_V6_NH,
228 record.ip6Address().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000229 record.addrPrefTime(),
230 record.getLastIp6Update(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000231 record.pdPrefix().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000232 record.pdPrefTime(),
233 record.getLastPdUpdate(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000234 nextHopIp,
235 record.ip6Status().map(Object::toString).orElse(NA));
236 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700237 }
238
239 private String ipState(String ipAddress, String status,
240 boolean directlyConnected,
241 String nextHopIp) {
242 if (directlyConnected) {
243 return String.format(STATUS_FMT, ipAddress, status);
244 } else {
245 return String.format(STATUS_FMT_NH, ipAddress, nextHopIp, status);
246 }
247 }
248
249 private String findNextHopIp(Predicate<IpAddress> ipFilter, MacAddress nextHopMac, VlanId vlanId) {
250 if (ipFilter == null || nextHopMac == null || vlanId == null) {
251 return NA;
252 }
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000253
Yi Tseng13a41a12017-07-26 13:45:01 -0700254 Host host = HOST_SERVICE.getHost(HostId.hostId(nextHopMac, vlanId));
255 if (host == null) {
256 return NA;
257 }
258 return host.ipAddresses().stream()
259 .filter(ipFilter)
260 .filter(ip -> !ip.isLinkLocal())
261 .map(Object::toString)
262 .findFirst()
263 .orElse(NA);
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700264 }
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000265
266 private String findNextHopIp6(Predicate<IpAddress> ipFilter, MacAddress nextHopMac, VlanId vlanId) {
267 if (ipFilter == null || nextHopMac == null || vlanId == null) {
268 return NA;
269 }
270
271 Host host = HOST_SERVICE.getHost(HostId.hostId(nextHopMac, vlanId));
272 if (host == null) {
273 return NA;
274 }
275 return host.ipAddresses().stream()
276 .filter(ipFilter)
277 .filter(ip -> ip.isLinkLocal())
278 .map(Object::toString)
279 .findFirst()
280 .orElse(NA);
281 }
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700282}