blob: 518263b7e9856f33d33697e69bcc4cd76a1fbf2b [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;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070022import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
24import org.onlab.packet.VlanId;
Yi Tseng13a41a12017-07-26 13:45:01 -070025import org.onlab.util.Tools;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070026import org.onosproject.cli.AbstractShellCommand;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000027import org.onosproject.dhcprelay.store.DhcpRelayCounters;
Yi Tseng919b2df2017-09-07 16:22:51 -070028import org.onosproject.dhcprelay.api.DhcpServerInfo;
Yi Tseng51301292017-07-28 13:02:59 -070029import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070030import org.onosproject.dhcprelay.store.DhcpRecord;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070031import org.onosproject.net.Host;
32import org.onosproject.net.HostId;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070033import org.onosproject.net.host.HostService;
34
Yi Tseng2e5d99e2017-06-06 10:58:46 -070035import java.util.Collection;
Yi Tseng919b2df2017-09-07 16:22:51 -070036import java.util.List;
Yi Tseng13a41a12017-07-26 13:45:01 -070037import java.util.function.Predicate;
Kalhee Kimd94ceea2017-11-29 19:03:02 +000038import java.util.Map;
39
Yi Tseng2e5d99e2017-06-06 10:58:46 -070040
41/**
42 * Prints DHCP server and DHCP relay status.
43 */
44@Command(scope = "onos", name = "dhcp-relay", description = "DHCP relay app cli.")
45public class DhcpRelayCommand extends AbstractShellCommand {
Kalhee Kimd94ceea2017-11-29 19:03:02 +000046 @Argument(index = 0, name = "counter",
47 description = "shows counter values",
48 required = false, multiValued = false)
49 String counter = null;
50
51 @Argument(index = 1, name = "reset",
52 description = "reset counters or not",
53 required = false, multiValued = false)
54 String reset = null;
55
56
57
58 private static final String CONUTER_HEADER = "DHCP Relay Counters :";
59 private static final String COUNTER_HOST = "Counters for id=%s/%s, locations=%s%s";
60
61
Yi Tseng2e5d99e2017-06-06 10:58:46 -070062 private static final String HEADER = "DHCP relay records ([D]: Directly connected):";
63 private static final String NO_RECORDS = "No DHCP relay record found";
Yi Tseng13a41a12017-07-26 13:45:01 -070064 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 -080065 private static final String DHCP_SERVER_GW = "DHCP Server: %s, %s via %s (Mac: %s)";
66 private static final String DHCP_SERVER = "DHCP Server: %s, %s (Mac: %s)";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070067 private static final String MISSING_SERVER_CFG = "DHCP Server info not available";
Yi Tseng13a41a12017-07-26 13:45:01 -070068 private static final String DIRECTLY = "[D]";
69 private static final String EMPTY = "";
70 private static final String NA = "N/A";
71 private static final String STATUS_FMT = "[%s, %s]";
72 private static final String STATUS_FMT_NH = "[%s via %s, %s]";
Kalhee Kimd94ceea2017-11-29 19:03:02 +000073 private static final String STATUS_FMT_V6 = "[%s %d, %d ms %s %d %d ms, %s]";
74 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 -070075 private static final String DEFAULT_SERVERS = "Default DHCP servers:";
76 private static final String INDIRECT_SERVERS = "Indirect DHCP servers:";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070077
78 private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070079 private static final HostService HOST_SERVICE = get(HostService.class);
Yi Tseng13a41a12017-07-26 13:45:01 -070080
Kalhee Kimd94ceea2017-11-29 19:03:02 +000081
Yi Tseng2e5d99e2017-06-06 10:58:46 -070082 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -070083 protected void doExecute() {
Yi Tseng919b2df2017-09-07 16:22:51 -070084 List<DhcpServerInfo> defaultDhcpServerInfoList = DHCP_RELAY_SERVICE.getDefaultDhcpServerInfoList();
85 List<DhcpServerInfo> indirectDhcpServerInfoList = DHCP_RELAY_SERVICE.getIndirectDhcpServerInfoList();
86
87 if (defaultDhcpServerInfoList.isEmpty() && indirectDhcpServerInfoList.isEmpty()) {
Yi Tseng2e5d99e2017-06-06 10:58:46 -070088 print(MISSING_SERVER_CFG);
89 return;
90 }
91
Yi Tseng919b2df2017-09-07 16:22:51 -070092 if (!defaultDhcpServerInfoList.isEmpty()) {
93 print(DEFAULT_SERVERS);
94 listServers(defaultDhcpServerInfoList);
95 }
96 if (!indirectDhcpServerInfoList.isEmpty()) {
97 print(INDIRECT_SERVERS);
98 listServers(indirectDhcpServerInfoList);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070099 }
100
101 // DHCP records
102 Collection<DhcpRecord> records = DHCP_RELAY_SERVICE.getDhcpRecords();
103 if (records.isEmpty()) {
104 print(NO_RECORDS);
105 return;
106 }
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000107
108 // Handle display of counters
109 boolean toResetFlag;
110
111 if (counter != null) {
rsahot0362c2c6cc2018-06-22 14:35:07 -0400112 if (counter.equals("counter") || counter.equals("[counter]")) {
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000113 print(CONUTER_HEADER);
114 } else {
115 print("first parameter is [counter]");
116 return;
117 }
118 if (reset != null) {
119 if (reset.equals("reset") || reset.equals("[reset]")) {
120 toResetFlag = true;
121 } else {
122 print("Last parameter is [reset]");
123 return;
124 }
125 } else {
126 toResetFlag = false;
127 }
128
129 records.forEach(record -> {
130 print(COUNTER_HOST, record.macAddress(),
131 record.vlanId(),
132 record.locations(),
133 record.directlyConnected() ? DIRECTLY : EMPTY);
134 DhcpRelayCounters v6Counters = record.getV6Counters();
135 Map<String, Integer> countersMap = v6Counters.getCounters();
136 countersMap.forEach((name, value) -> {
137 print("%-30s ............................ %-4d packets", name, value);
138 });
139 if (toResetFlag) {
140 v6Counters.resetCounters();
141 record.updateLastSeen();
142 DHCP_RELAY_SERVICE.updateDhcpRecord(HostId.hostId(record.macAddress(), record.vlanId()), record);
143 }
144 });
145
146
147 return;
148 }
149
150
151 // Handle display of records
152
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700153 print(HEADER);
Yi Tseng13a41a12017-07-26 13:45:01 -0700154 records.forEach(record -> print(HOST,
155 record.macAddress(),
156 record.vlanId(),
157 record.locations(),
158 record.directlyConnected() ? DIRECTLY : EMPTY,
159 Tools.timeAgo(record.lastSeen()),
160 ip4State(record),
161 ip6State(record)));
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700162 }
163
Yi Tseng919b2df2017-09-07 16:22:51 -0700164 private void listServers(List<DhcpServerInfo> dhcpServerInfoList) {
165 dhcpServerInfoList.forEach(dhcpServerInfo -> {
166 String connectPoint = dhcpServerInfo.getDhcpServerConnectPoint()
167 .map(Object::toString).orElse(NA);
168 String serverMac = dhcpServerInfo.getDhcpConnectMac()
169 .map(Object::toString).orElse(NA);
170 String gatewayAddress;
171 String serverIp;
Yi Tseng919b2df2017-09-07 16:22:51 -0700172
173 switch (dhcpServerInfo.getVersion()) {
174 case DHCP_V4:
175 gatewayAddress = dhcpServerInfo.getDhcpGatewayIp4()
176 .map(Object::toString).orElse(null);
177 serverIp = dhcpServerInfo.getDhcpServerIp4()
178 .map(Object::toString).orElse(NA);
Yi Tseng919b2df2017-09-07 16:22:51 -0700179 break;
180 case DHCP_V6:
181 gatewayAddress = dhcpServerInfo.getDhcpGatewayIp6()
182 .map(Object::toString).orElse(null);
183 serverIp = dhcpServerInfo.getDhcpServerIp6()
184 .map(Object::toString).orElse(NA);
Yi Tseng919b2df2017-09-07 16:22:51 -0700185 break;
186 default:
187 return;
188 }
189 if (gatewayAddress != null) {
Yi Tseng25bfe372017-11-03 16:27:32 -0700190 print(DHCP_SERVER_GW, connectPoint, serverIp, gatewayAddress, serverMac);
Yi Tseng919b2df2017-09-07 16:22:51 -0700191 } else {
Yi Tseng25bfe372017-11-03 16:27:32 -0700192 print(DHCP_SERVER, connectPoint, serverIp, serverMac);
Yi Tseng919b2df2017-09-07 16:22:51 -0700193 }
194 });
195 }
196
Yi Tseng13a41a12017-07-26 13:45:01 -0700197 private String ip4State(DhcpRecord record) {
198 String nextHopIp = findNextHopIp(IpAddress::isIp4,
199 record.nextHop().orElse(null),
200 record.vlanId());
201 return ipState(record.ip4Address().map(Object::toString).orElse(NA),
202 record.ip4Status().map(Object::toString).orElse(NA),
203 record.directlyConnected(),
204 nextHopIp);
205 }
206
207 private String ip6State(DhcpRecord record) {
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000208 String nextHopIp = findNextHopIp6(IpAddress::isIp6,
Yi Tseng13a41a12017-07-26 13:45:01 -0700209 record.nextHop().orElse(null),
210 record.vlanId());
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000211
212 if (record.directlyConnected()) {
213 return String.format(STATUS_FMT_V6,
214 record.ip6Address().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000215 record.addrPrefTime(),
216 record.getLastIp6Update(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000217 record.pdPrefix().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000218 record.pdPrefTime(),
219 record.getLastPdUpdate(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000220 record.ip6Status().map(Object::toString).orElse(NA));
221 } else {
222 return String.format(STATUS_FMT_V6_NH,
223 record.ip6Address().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000224 record.addrPrefTime(),
225 record.getLastIp6Update(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000226 record.pdPrefix().map(Object::toString).orElse(NA),
Kalhee Kimd94ceea2017-11-29 19:03:02 +0000227 record.pdPrefTime(),
228 record.getLastPdUpdate(),
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000229 nextHopIp,
230 record.ip6Status().map(Object::toString).orElse(NA));
231 }
Yi Tseng13a41a12017-07-26 13:45:01 -0700232 }
233
234 private String ipState(String ipAddress, String status,
235 boolean directlyConnected,
236 String nextHopIp) {
237 if (directlyConnected) {
238 return String.format(STATUS_FMT, ipAddress, status);
239 } else {
240 return String.format(STATUS_FMT_NH, ipAddress, nextHopIp, status);
241 }
242 }
243
244 private String findNextHopIp(Predicate<IpAddress> ipFilter, MacAddress nextHopMac, VlanId vlanId) {
245 if (ipFilter == null || nextHopMac == null || vlanId == null) {
246 return NA;
247 }
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000248
Yi Tseng13a41a12017-07-26 13:45:01 -0700249 Host host = HOST_SERVICE.getHost(HostId.hostId(nextHopMac, vlanId));
250 if (host == null) {
251 return NA;
252 }
253 return host.ipAddresses().stream()
254 .filter(ipFilter)
255 .filter(ip -> !ip.isLinkLocal())
256 .map(Object::toString)
257 .findFirst()
258 .orElse(NA);
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700259 }
Kalhee Kimea4b6c22017-11-09 14:38:37 +0000260
261 private String findNextHopIp6(Predicate<IpAddress> ipFilter, MacAddress nextHopMac, VlanId vlanId) {
262 if (ipFilter == null || nextHopMac == null || vlanId == null) {
263 return NA;
264 }
265
266 Host host = HOST_SERVICE.getHost(HostId.hostId(nextHopMac, vlanId));
267 if (host == null) {
268 return NA;
269 }
270 return host.ipAddresses().stream()
271 .filter(ipFilter)
272 .filter(ip -> ip.isLinkLocal())
273 .map(Object::toString)
274 .findFirst()
275 .orElse(NA);
276 }
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700277}