blob: 76fd015e6190c75180e75d71ea4b1186e70ff351 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.host.impl;
alshabibe1cf87d2014-10-17 09:23:50 -070017
Jonathan Harte8600eb2015-01-12 10:30:45 -080018import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Dictionary;
21import java.util.Set;
22
alshabibe1cf87d2014-10-17 09:23:50 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska33601602014-11-19 03:32:15 -080026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
alshabibe1cf87d2014-10-17 09:23:50 -070028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte8600eb2015-01-12 10:30:45 -080030import org.onlab.packet.ARP;
31import org.onlab.packet.Ethernet;
32import org.onlab.packet.IPacket;
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -080033import org.onlab.packet.ICMP6;
Jonathan Harte8600eb2015-01-12 10:30:45 -080034import org.onlab.packet.IPv6;
35import org.onlab.packet.IpAddress;
36import org.onlab.packet.VlanId;
37import org.onlab.packet.ndp.NeighborAdvertisement;
38import org.onlab.packet.ndp.NeighborSolicitation;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080039import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.ConnectPoint;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080042import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.net.Host;
44import org.onosproject.net.HostId;
45import org.onosproject.net.HostLocation;
46import org.onosproject.net.device.DeviceEvent;
47import org.onosproject.net.device.DeviceListener;
48import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080049import org.onosproject.net.flow.DefaultTrafficSelector;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080050import org.onosproject.net.flow.TrafficSelector;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.host.DefaultHostDescription;
52import org.onosproject.net.host.HostDescription;
53import org.onosproject.net.host.HostProvider;
54import org.onosproject.net.host.HostProviderRegistry;
55import org.onosproject.net.host.HostProviderService;
56import org.onosproject.net.host.HostService;
57import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080058import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080059import org.onosproject.net.packet.PacketProcessor;
60import org.onosproject.net.packet.PacketService;
61import org.onosproject.net.provider.AbstractProvider;
62import org.onosproject.net.provider.ProviderId;
63import org.onosproject.net.topology.Topology;
64import org.onosproject.net.topology.TopologyService;
Thomas Vachuska33601602014-11-19 03:32:15 -080065import org.osgi.service.component.ComponentContext;
alshabibe1cf87d2014-10-17 09:23:50 -070066import org.slf4j.Logger;
67
alshabibe1cf87d2014-10-17 09:23:50 -070068/**
69 * Provider which uses an OpenFlow controller to detect network
70 * end-station hosts.
71 */
72@Component(immediate = true)
73public class HostLocationProvider extends AbstractProvider implements HostProvider {
74
75 private final Logger log = getLogger(getClass());
76
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080077 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
79
80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe1cf87d2014-10-17 09:23:50 -070081 protected HostProviderRegistry providerRegistry;
82
83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -080084 protected PacketService packetService;
alshabibe1cf87d2014-10-17 09:23:50 -070085
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected TopologyService topologyService;
88
Thomas Vachuska33601602014-11-19 03:32:15 -080089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected HostService hostService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DeviceService deviceService;
94
alshabibe1cf87d2014-10-17 09:23:50 -070095 private HostProviderService providerService;
96
97 private final InternalHostProvider processor = new InternalHostProvider();
Thomas Vachuska33601602014-11-19 03:32:15 -080098 private final DeviceListener deviceListener = new InternalDeviceListener();
99
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800100 private ApplicationId appId;
101
Thomas Vachuska33601602014-11-19 03:32:15 -0800102 @Property(name = "hostRemovalEnabled", boolValue = true,
103 label = "Enable host removal on port/device down events")
104 private boolean hostRemovalEnabled = true;
alshabibe1cf87d2014-10-17 09:23:50 -0700105
106
107 /**
108 * Creates an OpenFlow host provider.
109 */
110 public HostLocationProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800111 super(new ProviderId("of", "org.onosproject.provider.host"));
alshabibe1cf87d2014-10-17 09:23:50 -0700112 }
113
114 @Activate
Thomas Vachuska33601602014-11-19 03:32:15 -0800115 public void activate(ComponentContext context) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800116 appId =
117 coreService.registerApplication("org.onosproject.provider.host");
118
Thomas Vachuska33601602014-11-19 03:32:15 -0800119 modified(context);
alshabibe1cf87d2014-10-17 09:23:50 -0700120 providerService = providerRegistry.register(this);
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800121 packetService.addProcessor(processor, 1);
Thomas Vachuska33601602014-11-19 03:32:15 -0800122 deviceService.addListener(deviceListener);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800123
124 TrafficSelector.Builder selectorBuilder =
125 DefaultTrafficSelector.builder();
126 selectorBuilder.matchEthType(Ethernet.TYPE_ARP);
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800127 packetService.requestPackets(selectorBuilder.build(),
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800128 PacketPriority.CONTROL, appId);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800129
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800130 // IPv6 Neighbor Solicitation packet.
131 selectorBuilder = DefaultTrafficSelector.builder();
132 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
133 selectorBuilder.matchIPProtocol(IPv6.PROTOCOL_ICMP6);
134 selectorBuilder.matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION);
135 packetService.requestPackets(selectorBuilder.build(),
136 PacketPriority.CONTROL, appId);
137
138 // IPv6 Neighbor Advertisement packet.
139 selectorBuilder = DefaultTrafficSelector.builder();
140 selectorBuilder.matchEthType(Ethernet.TYPE_IPV6);
141 selectorBuilder.matchIPProtocol(IPv6.PROTOCOL_ICMP6);
142 selectorBuilder.matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT);
143 packetService.requestPackets(selectorBuilder.build(),
144 PacketPriority.CONTROL, appId);
145
146 log.info("Started with Application ID {}", appId.id());
alshabibe1cf87d2014-10-17 09:23:50 -0700147 }
148
149 @Deactivate
150 public void deactivate() {
151 providerRegistry.unregister(this);
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800152 packetService.removeProcessor(processor);
alshabibbfc6b722014-11-29 12:53:48 -0800153 deviceService.removeListener(deviceListener);
alshabibe1cf87d2014-10-17 09:23:50 -0700154 providerService = null;
155 log.info("Stopped");
156 }
157
Thomas Vachuska33601602014-11-19 03:32:15 -0800158 @Modified
159 public void modified(ComponentContext context) {
160 Dictionary properties = context.getProperties();
161 try {
162 String flag = (String) properties.get("hostRemovalEnabled");
163 if (flag != null) {
164 hostRemovalEnabled = flag.equals("true");
165 }
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800166 } catch (ClassCastException e) {
Thomas Vachuska33601602014-11-19 03:32:15 -0800167 hostRemovalEnabled = true;
168 }
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800169 log.info("Host removal is {}",
170 hostRemovalEnabled ? "enabled" : "disabled");
Thomas Vachuska33601602014-11-19 03:32:15 -0800171 }
172
alshabibe1cf87d2014-10-17 09:23:50 -0700173 @Override
174 public void triggerProbe(Host host) {
175 log.info("Triggering probe on device {}", host);
176 }
177
178 private class InternalHostProvider implements PacketProcessor {
179
180 @Override
181 public void process(PacketContext context) {
alshabib4a179dc2014-10-17 17:17:01 -0700182 if (context == null) {
183 return;
184 }
alshabibe1cf87d2014-10-17 09:23:50 -0700185 Ethernet eth = context.inPacket().parsed();
186
Jonathan Harte8600eb2015-01-12 10:30:45 -0800187 if (eth == null) {
188 return;
189 }
190
alshabibe1cf87d2014-10-17 09:23:50 -0700191 VlanId vlan = VlanId.vlanId(eth.getVlanID());
192 ConnectPoint heardOn = context.inPacket().receivedFrom();
193
194 // If this is not an edge port, bail out.
195 Topology topology = topologyService.currentTopology();
196 if (topologyService.isInfrastructure(topology, heardOn)) {
197 return;
198 }
199
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800200 HostLocation hloc =
201 new HostLocation(heardOn, System.currentTimeMillis());
alshabibe1cf87d2014-10-17 09:23:50 -0700202
203 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
204
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800205 // ARP: possible new hosts, update both location and IP
alshabibe1cf87d2014-10-17 09:23:50 -0700206 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
207 ARP arp = (ARP) eth.getPayload();
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800208 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET,
209 arp.getSenderProtocolAddress());
alshabibe1cf87d2014-10-17 09:23:50 -0700210 HostDescription hdescr =
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800211 new DefaultHostDescription(eth.getSourceMAC(), vlan,
212 hloc, ip);
alshabibe1cf87d2014-10-17 09:23:50 -0700213 providerService.hostDetected(hid, hdescr);
214
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800215 // IPv4: update location only
alshabibe1cf87d2014-10-17 09:23:50 -0700216 } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
alshabibe1cf87d2014-10-17 09:23:50 -0700217 HostDescription hdescr =
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800218 new DefaultHostDescription(eth.getSourceMAC(), vlan, hloc);
alshabibe1cf87d2014-10-17 09:23:50 -0700219 providerService.hostDetected(hid, hdescr);
220
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800221 //
222 // NeighborAdvertisement and NeighborSolicitation: possible
223 // new hosts, update both location and IP.
224 //
225 // IPv6: update location only
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800226 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
227 IpAddress ip = null;
228 IPv6 ipv6 = (IPv6) eth.getPayload();
229
230 IPacket iPkt = ipv6;
231 while (iPkt != null) {
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800232 if (iPkt instanceof NeighborAdvertisement ||
233 iPkt instanceof NeighborSolicitation) {
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800234 IpAddress sourceAddress =
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800235 IpAddress.valueOf(IpAddress.Version.INET6,
236 ipv6.getSourceAddress());
237 // Ignore DAD packets, in which source address is zero
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800238 if (!sourceAddress.isZero()) {
239 ip = sourceAddress;
240 break;
241 }
242 }
243 iPkt = iPkt.getPayload();
244 }
245 HostDescription hdescr = (ip == null) ?
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800246 new DefaultHostDescription(eth.getSourceMAC(), vlan,
247 hloc) :
248 new DefaultHostDescription(eth.getSourceMAC(), vlan,
249 hloc, ip);
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800250 providerService.hostDetected(hid, hdescr);
alshabibe1cf87d2014-10-17 09:23:50 -0700251 }
252 }
253 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800254
255 // Auxiliary listener to device events.
256 private class InternalDeviceListener implements DeviceListener {
257 @Override
258 public void event(DeviceEvent event) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800259 Device device = event.subject();
260 switch (event.type()) {
261 case DEVICE_ADDED:
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800262 break;
263 case DEVICE_AVAILABILITY_CHANGED:
264 if (hostRemovalEnabled &&
265 !deviceService.isAvailable(device.id())) {
266 removeHosts(hostService.getConnectedHosts(device.id()));
Thomas Vachuska33601602014-11-19 03:32:15 -0800267 }
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800268 break;
269 case DEVICE_SUSPENDED:
270 case DEVICE_UPDATED:
271 // Nothing to do?
272 break;
273 case DEVICE_REMOVED:
274 if (hostRemovalEnabled) {
275 removeHosts(hostService.getConnectedHosts(device.id()));
276 }
277 break;
278 case PORT_ADDED:
279 break;
280 case PORT_UPDATED:
281 if (hostRemovalEnabled) {
282 ConnectPoint point =
283 new ConnectPoint(device.id(), event.port().number());
284 removeHosts(hostService.getConnectedHosts(point));
285 }
286 break;
287 case PORT_REMOVED:
288 // Nothing to do?
289 break;
290 default:
291 break;
Thomas Vachuska33601602014-11-19 03:32:15 -0800292 }
293 }
294 }
295
296 // Signals host vanish for all specified hosts.
297 private void removeHosts(Set<Host> hosts) {
298 for (Host host : hosts) {
299 providerService.hostVanished(host.id());
300 }
301 }
302
alshabibe1cf87d2014-10-17 09:23:50 -0700303}