blob: d4ea1d8fe7ff14b5366f57344322df407ee0784a [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
19import org.apache.karaf.shell.commands.Command;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
22import org.onlab.packet.MacAddress;
23import org.onlab.packet.VlanId;
Yi Tseng13a41a12017-07-26 13:45:01 -070024import org.onlab.util.Tools;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070025import org.onosproject.cli.AbstractShellCommand;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070028import org.onosproject.dhcprelay.config.DefaultDhcpRelayConfig;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070029import org.onosproject.dhcprelay.DhcpRelayManager;
Yi Tseng51301292017-07-28 13:02:59 -070030import org.onosproject.dhcprelay.api.DhcpRelayService;
Yi Tseng483ac6f2017-08-02 15:03:31 -070031import org.onosproject.dhcprelay.config.DhcpServerConfig;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070032import org.onosproject.dhcprelay.store.DhcpRecord;
33import org.onosproject.net.ConnectPoint;
34import org.onosproject.net.Host;
35import org.onosproject.net.HostId;
36import org.onosproject.net.config.NetworkConfigRegistry;
37import org.onosproject.net.host.HostService;
38
Yi Tseng2e5d99e2017-06-06 10:58:46 -070039import java.util.Collection;
Yi Tseng13a41a12017-07-26 13:45:01 -070040import java.util.function.Predicate;
Yi Tseng2e5d99e2017-06-06 10:58:46 -070041
42/**
43 * Prints DHCP server and DHCP relay status.
44 */
45@Command(scope = "onos", name = "dhcp-relay", description = "DHCP relay app cli.")
46public class DhcpRelayCommand extends AbstractShellCommand {
47 private static final String HEADER = "DHCP relay records ([D]: Directly connected):";
48 private static final String NO_RECORDS = "No DHCP relay record found";
Yi Tseng13a41a12017-07-26 13:45:01 -070049 private static final String HOST = "id=%s/%s, locations=%s%s, last-seen=%s, IPv4=%s, IPv6=%s";
50 private static final String DHCP_SERVER_GW = "DHCP Server: %s, %s via %s (Mac: %s)";
51 private static final String DHCP_SERVER = "DHCP Server: %s, %s (Mac: %s)";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070052 private static final String MISSING_SERVER_CFG = "DHCP Server info not available";
Yi Tseng13a41a12017-07-26 13:45:01 -070053 private static final String DIRECTLY = "[D]";
54 private static final String EMPTY = "";
55 private static final String NA = "N/A";
56 private static final String STATUS_FMT = "[%s, %s]";
57 private static final String STATUS_FMT_NH = "[%s via %s, %s]";
Yi Tseng2e5d99e2017-06-06 10:58:46 -070058
59 private static final DhcpRelayService DHCP_RELAY_SERVICE = get(DhcpRelayService.class);
60 private static final NetworkConfigRegistry CFG_SERVICE = get(NetworkConfigRegistry.class);
61 private static final HostService HOST_SERVICE = get(HostService.class);
62 private static final CoreService CORE_SERVICE = get(CoreService.class);
63 private static final ApplicationId APP_ID =
64 CORE_SERVICE.getAppId(DhcpRelayManager.DHCP_RELAY_APP);
65
Yi Tseng13a41a12017-07-26 13:45:01 -070066
Yi Tseng2e5d99e2017-06-06 10:58:46 -070067 @Override
68 protected void execute() {
Yi Tseng4f2a0462017-08-31 11:21:00 -070069 // TODO: add indirect config
Yi Tseng483ac6f2017-08-02 15:03:31 -070070 DefaultDhcpRelayConfig cfg = CFG_SERVICE.getConfig(APP_ID, DefaultDhcpRelayConfig.class);
71 if (cfg == null || cfg.dhcpServerConfigs().size() == 0) {
Yi Tseng2e5d99e2017-06-06 10:58:46 -070072 print(MISSING_SERVER_CFG);
73 return;
74 }
75
76 // DHCP server information
Yi Tseng483ac6f2017-08-02 15:03:31 -070077 // TODO: currently we pick up first DHCP server config.
78 // Will use other server configs in the future.
79 DhcpServerConfig serverConfig = cfg.dhcpServerConfigs().get(0);
80
81 ConnectPoint connectPoint = serverConfig.getDhcpServerConnectPoint().orElse(null);
82 Ip4Address gatewayAddress = serverConfig.getDhcpGatewayIp4().orElse(null);
83 Ip4Address serverIp = serverConfig.getDhcpServerIp4().orElse(null);
Yi Tseng13a41a12017-07-26 13:45:01 -070084 String serverMac = DHCP_RELAY_SERVICE.getDhcpServerMacAddress()
85 .map(MacAddress::toString).orElse(NA);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070086 if (gatewayAddress != null) {
Yi Tseng13a41a12017-07-26 13:45:01 -070087 print(DHCP_SERVER_GW, connectPoint, serverIp, gatewayAddress, serverMac);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070088 } else {
Yi Tseng13a41a12017-07-26 13:45:01 -070089 print(DHCP_SERVER, connectPoint, serverIp, serverMac);
Yi Tseng2e5d99e2017-06-06 10:58:46 -070090 }
91
92 // DHCP records
93 Collection<DhcpRecord> records = DHCP_RELAY_SERVICE.getDhcpRecords();
94 if (records.isEmpty()) {
95 print(NO_RECORDS);
96 return;
97 }
98 print(HEADER);
Yi Tseng13a41a12017-07-26 13:45:01 -070099 records.forEach(record -> print(HOST,
100 record.macAddress(),
101 record.vlanId(),
102 record.locations(),
103 record.directlyConnected() ? DIRECTLY : EMPTY,
104 Tools.timeAgo(record.lastSeen()),
105 ip4State(record),
106 ip6State(record)));
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700107 }
108
Yi Tseng13a41a12017-07-26 13:45:01 -0700109 private String ip4State(DhcpRecord record) {
110 String nextHopIp = findNextHopIp(IpAddress::isIp4,
111 record.nextHop().orElse(null),
112 record.vlanId());
113 return ipState(record.ip4Address().map(Object::toString).orElse(NA),
114 record.ip4Status().map(Object::toString).orElse(NA),
115 record.directlyConnected(),
116 nextHopIp);
117 }
118
119 private String ip6State(DhcpRecord record) {
120 String nextHopIp = findNextHopIp(IpAddress::isIp6,
121 record.nextHop().orElse(null),
122 record.vlanId());
123 return ipState(record.ip6Address().map(Object::toString).orElse(NA),
124 record.ip6Status().map(Object::toString).orElse(NA),
125 record.directlyConnected(),
126 nextHopIp);
127 }
128
129 private String ipState(String ipAddress, String status,
130 boolean directlyConnected,
131 String nextHopIp) {
132 if (directlyConnected) {
133 return String.format(STATUS_FMT, ipAddress, status);
134 } else {
135 return String.format(STATUS_FMT_NH, ipAddress, nextHopIp, status);
136 }
137 }
138
139 private String findNextHopIp(Predicate<IpAddress> ipFilter, MacAddress nextHopMac, VlanId vlanId) {
140 if (ipFilter == null || nextHopMac == null || vlanId == null) {
141 return NA;
142 }
143 Host host = HOST_SERVICE.getHost(HostId.hostId(nextHopMac, vlanId));
144 if (host == null) {
145 return NA;
146 }
147 return host.ipAddresses().stream()
148 .filter(ipFilter)
149 .filter(ip -> !ip.isLinkLocal())
150 .map(Object::toString)
151 .findFirst()
152 .orElse(NA);
Yi Tseng2e5d99e2017-06-06 10:58:46 -0700153 }
154}