blob: d91d437e7f28169b193992c6c043dacfdf88375c [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present 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
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
Thomas Vachuska33601602014-11-19 03:32:15 -080021import org.apache.felix.scr.annotations.Modified;
22import org.apache.felix.scr.annotations.Property;
alshabibe1cf87d2014-10-17 09:23:50 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harte8600eb2015-01-12 10:30:45 -080025import org.onlab.packet.ARP;
26import org.onlab.packet.Ethernet;
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -080027import org.onlab.packet.ICMP6;
Thomas Vachuskaf845cf62015-03-24 10:13:09 -070028import org.onlab.packet.IPacket;
Jonathan Harte8600eb2015-01-12 10:30:45 -080029import org.onlab.packet.IPv6;
30import org.onlab.packet.IpAddress;
Charles M.C. Chan956cb692015-04-26 18:49:39 +080031import org.onlab.packet.MacAddress;
Jonathan Harte8600eb2015-01-12 10:30:45 -080032import org.onlab.packet.VlanId;
Charles M.C. Chan956cb692015-04-26 18:49:39 +080033import org.onlab.packet.ipv6.IExtensionHeader;
Jonathan Harte8600eb2015-01-12 10:30:45 -080034import org.onlab.packet.ndp.NeighborAdvertisement;
35import org.onlab.packet.ndp.NeighborSolicitation;
Charles M.C. Chan441d7da2015-03-17 21:03:39 +080036import org.onlab.packet.ndp.RouterAdvertisement;
37import org.onlab.packet.ndp.RouterSolicitation;
Jian Lid9b5f552016-03-11 18:15:31 -080038import org.onlab.util.Tools;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070039import org.onosproject.cfg.ComponentConfigService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080042import org.onosproject.net.ConnectPoint;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080043import org.onosproject.net.Device;
Brian O'Connorabafb502014-12-02 22:26:20 -080044import org.onosproject.net.Host;
45import org.onosproject.net.HostId;
46import org.onosproject.net.HostLocation;
47import org.onosproject.net.device.DeviceEvent;
48import org.onosproject.net.device.DeviceListener;
49import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080050import org.onosproject.net.flow.DefaultTrafficSelector;
sdn94b00152016-08-30 02:12:32 -070051import org.onosproject.net.flow.DefaultTrafficTreatment;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080052import org.onosproject.net.flow.TrafficSelector;
sdn94b00152016-08-30 02:12:32 -070053import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080054import org.onosproject.net.host.DefaultHostDescription;
55import org.onosproject.net.host.HostDescription;
56import org.onosproject.net.host.HostProvider;
57import org.onosproject.net.host.HostProviderRegistry;
58import org.onosproject.net.host.HostProviderService;
59import org.onosproject.net.host.HostService;
sdn94b00152016-08-30 02:12:32 -070060import org.onosproject.net.packet.DefaultOutboundPacket;
61import org.onosproject.net.packet.OutboundPacket;
Brian O'Connorabafb502014-12-02 22:26:20 -080062import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080063import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080064import org.onosproject.net.packet.PacketProcessor;
65import org.onosproject.net.packet.PacketService;
66import org.onosproject.net.provider.AbstractProvider;
67import org.onosproject.net.provider.ProviderId;
68import org.onosproject.net.topology.Topology;
69import org.onosproject.net.topology.TopologyService;
Thomas Vachuska33601602014-11-19 03:32:15 -080070import org.osgi.service.component.ComponentContext;
alshabibe1cf87d2014-10-17 09:23:50 -070071import org.slf4j.Logger;
72
sdn94b00152016-08-30 02:12:32 -070073import java.nio.ByteBuffer;
Thomas Vachuskaf845cf62015-03-24 10:13:09 -070074import java.util.Dictionary;
75import java.util.Set;
Madan Jampania3770c32015-12-11 12:07:41 -080076import java.util.concurrent.ExecutorService;
Thomas Vachuskaf845cf62015-03-24 10:13:09 -070077
Madan Jampania3770c32015-12-11 12:07:41 -080078import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
79import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuskaf845cf62015-03-24 10:13:09 -070080import static org.slf4j.LoggerFactory.getLogger;
81
alshabibe1cf87d2014-10-17 09:23:50 -070082/**
Thomas Vachuskaec9c7dd2015-09-03 18:30:04 -070083 * Provider which uses an OpenFlow controller to detect network end-station
84 * hosts.
alshabibe1cf87d2014-10-17 09:23:50 -070085 */
86@Component(immediate = true)
87public class HostLocationProvider extends AbstractProvider implements HostProvider {
88
89 private final Logger log = getLogger(getClass());
90
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080091 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibe1cf87d2014-10-17 09:23:50 -070095 protected HostProviderRegistry providerRegistry;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -080098 protected PacketService packetService;
alshabibe1cf87d2014-10-17 09:23:50 -070099
100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected TopologyService topologyService;
102
Thomas Vachuska33601602014-11-19 03:32:15 -0800103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected HostService hostService;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected DeviceService deviceService;
108
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
110 protected ComponentConfigService cfgService;
111
alshabibe1cf87d2014-10-17 09:23:50 -0700112 private HostProviderService providerService;
113
114 private final InternalHostProvider processor = new InternalHostProvider();
Thomas Vachuska33601602014-11-19 03:32:15 -0800115 private final DeviceListener deviceListener = new InternalDeviceListener();
116
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800117 private ApplicationId appId;
118
Thomas Vachuska33601602014-11-19 03:32:15 -0800119 @Property(name = "hostRemovalEnabled", boolValue = true,
120 label = "Enable host removal on port/device down events")
121 private boolean hostRemovalEnabled = true;
alshabibe1cf87d2014-10-17 09:23:50 -0700122
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800123 @Property(name = "ipv6NeighborDiscovery", boolValue = false,
Thomas Vachuska27bee092015-06-23 19:03:10 -0700124 label = "Enable using IPv6 Neighbor Discovery by the " +
125 "Host Location Provider; default is false")
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800126 private boolean ipv6NeighborDiscovery = false;
alshabibe1cf87d2014-10-17 09:23:50 -0700127
Jonathan Hart9af322d2016-01-06 17:42:04 -0800128 @Property(name = "requestInterceptsEnabled", boolValue = true,
129 label = "Enable requesting packet intercepts")
130 private boolean requestInterceptsEnabled = true;
131
Madan Jampania3770c32015-12-11 12:07:41 -0800132 protected ExecutorService eventHandler;
133
sdn94b00152016-08-30 02:12:32 -0700134 private static final byte[] SENDER_ADDRESS = IpAddress.valueOf("0.0.0.0").toOctets();
135
alshabibe1cf87d2014-10-17 09:23:50 -0700136 /**
137 * Creates an OpenFlow host provider.
138 */
139 public HostLocationProvider() {
Brian O'Connorabafb502014-12-02 22:26:20 -0800140 super(new ProviderId("of", "org.onosproject.provider.host"));
alshabibe1cf87d2014-10-17 09:23:50 -0700141 }
142
143 @Activate
Thomas Vachuska33601602014-11-19 03:32:15 -0800144 public void activate(ComponentContext context) {
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700145 cfgService.registerProperties(getClass());
146 appId = coreService.registerApplication("org.onosproject.provider.host");
Jonathan Hart9af322d2016-01-06 17:42:04 -0800147 eventHandler = newSingleThreadScheduledExecutor(
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700148 groupedThreads("onos/host-loc-provider", "event-handler", log));
alshabibe1cf87d2014-10-17 09:23:50 -0700149 providerService = providerRegistry.register(this);
Brian O'Connor3b783262015-07-29 17:49:24 -0700150 packetService.addProcessor(processor, PacketProcessor.advisor(1));
Thomas Vachuska33601602014-11-19 03:32:15 -0800151 deviceService.addListener(deviceListener);
Jonathan Hart9af322d2016-01-06 17:42:04 -0800152
153 modified(context);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800154
Charles M.C. Chane148de82015-05-06 12:38:21 +0800155 log.info("Started with Application ID {}", appId.id());
156 }
157
158 @Deactivate
159 public void deactivate() {
Charles M.C. Chane148de82015-05-06 12:38:21 +0800160 cfgService.unregisterProperties(getClass(), false);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700161
162 withdrawIntercepts();
163
Charles M.C. Chane148de82015-05-06 12:38:21 +0800164 providerRegistry.unregister(this);
165 packetService.removeProcessor(processor);
166 deviceService.removeListener(deviceListener);
Madan Jampania3770c32015-12-11 12:07:41 -0800167 eventHandler.shutdown();
Charles M.C. Chane148de82015-05-06 12:38:21 +0800168 providerService = null;
169 log.info("Stopped");
170 }
171
172 @Modified
173 public void modified(ComponentContext context) {
Charles M.C. Chane148de82015-05-06 12:38:21 +0800174 readComponentConfiguration(context);
Jonathan Hart9af322d2016-01-06 17:42:04 -0800175
176 if (requestInterceptsEnabled) {
177 requestIntercepts();
178 } else {
179 withdrawIntercepts();
180 }
Charles M.C. Chane148de82015-05-06 12:38:21 +0800181 }
182
183 /**
Thomas Vachuska27bee092015-06-23 19:03:10 -0700184 * Request packet intercepts.
Charles M.C. Chane148de82015-05-06 12:38:21 +0800185 */
Thomas Vachuska27bee092015-06-23 19:03:10 -0700186 private void requestIntercepts() {
187 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
188 selector.matchEthType(Ethernet.TYPE_ARP);
189 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800190
Thomas Vachuska27bee092015-06-23 19:03:10 -0700191 // IPv6 Neighbor Solicitation packet.
192 selector.matchEthType(Ethernet.TYPE_IPV6);
193 selector.matchIPProtocol(IPv6.PROTOCOL_ICMP6);
194 selector.matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800195 if (ipv6NeighborDiscovery) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700196 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
197 } else {
198 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800199 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700200
201 // IPv6 Neighbor Advertisement packet.
202 selector.matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT);
203 if (ipv6NeighborDiscovery) {
204 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
205 } else {
206 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
207 }
208 }
209
210 /**
211 * Withdraw packet intercepts.
212 */
213 private void withdrawIntercepts() {
214 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
215 selector.matchEthType(Ethernet.TYPE_ARP);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700216 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700217
218 // IPv6 Neighbor Solicitation packet.
219 selector.matchEthType(Ethernet.TYPE_IPV6);
220 selector.matchIPProtocol(IPv6.PROTOCOL_ICMP6);
221 selector.matchIcmpv6Type(ICMP6.NEIGHBOR_SOLICITATION);
222 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
223
224 // IPv6 Neighbor Advertisement packet.
225 selector.matchIcmpv6Type(ICMP6.NEIGHBOR_ADVERTISEMENT);
226 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800227 }
228
229 /**
230 * Extracts properties from the component configuration context.
231 *
232 * @param context the component context
233 */
234 private void readComponentConfiguration(ComponentContext context) {
235 Dictionary<?, ?> properties = context.getProperties();
236 Boolean flag;
237
Jian Lid9b5f552016-03-11 18:15:31 -0800238 flag = Tools.isPropertyEnabled(properties, "hostRemovalEnabled");
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800239 if (flag == null) {
240 log.info("Host removal on port/device down events is not configured, " +
Thomas Vachuska27bee092015-06-23 19:03:10 -0700241 "using current value of {}", hostRemovalEnabled);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800242 } else {
243 hostRemovalEnabled = flag;
244 log.info("Configured. Host removal on port/device down events is {}",
245 hostRemovalEnabled ? "enabled" : "disabled");
Thomas Vachuska33601602014-11-19 03:32:15 -0800246 }
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800247
Jian Lid9b5f552016-03-11 18:15:31 -0800248 flag = Tools.isPropertyEnabled(properties, "ipv6NeighborDiscovery");
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800249 if (flag == null) {
250 log.info("Using IPv6 Neighbor Discovery is not configured, " +
Thomas Vachuska27bee092015-06-23 19:03:10 -0700251 "using current value of {}", ipv6NeighborDiscovery);
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800252 } else {
253 ipv6NeighborDiscovery = flag;
254 log.info("Configured. Using IPv6 Neighbor Discovery is {}",
255 ipv6NeighborDiscovery ? "enabled" : "disabled");
256 }
Jonathan Hart9af322d2016-01-06 17:42:04 -0800257
Jian Lid9b5f552016-03-11 18:15:31 -0800258 flag = Tools.isPropertyEnabled(properties, "requestInterceptsEnabled");
Jonathan Hart9af322d2016-01-06 17:42:04 -0800259 if (flag == null) {
260 log.info("Request intercepts is not configured, " +
261 "using current value of {}", requestInterceptsEnabled);
262 } else {
263 requestInterceptsEnabled = flag;
264 log.info("Configured. Request intercepts is {}",
265 requestInterceptsEnabled ? "enabled" : "disabled");
266 }
Pavlin Radoslavov93b606b2015-02-25 17:28:39 -0800267 }
268
alshabibe1cf87d2014-10-17 09:23:50 -0700269 @Override
270 public void triggerProbe(Host host) {
sdn94b00152016-08-30 02:12:32 -0700271 log.info("Triggering probe on device {} ", host);
Jonathan Hartf353e402016-09-23 09:27:36 -0700272
273 // FIXME Disabling host probing for now, because sending packets from a
274 // broadcast MAC address caused problems when two ONOS networks were
275 // interconnected. Host probing should take into account the interface
276 // configuration when determining which source address to use.
277
278 //MastershipRole role = deviceService.getRole(host.location().deviceId());
279 //if (role.equals(MastershipRole.MASTER)) {
280 // host.ipAddresses().forEach(ip -> {
281 // sendProbe(host, ip);
282 // });
283 //} else {
284 // log.info("not the master, master will probe {}");
285 //}
sdn94b00152016-08-30 02:12:32 -0700286 }
287
288 private void sendProbe(Host host, IpAddress targetIp) {
289 Ethernet probePacket = null;
290 if (targetIp.isIp4()) {
291 // IPv4: Use ARP
292 probePacket = buildArpRequest(targetIp, host);
293 } else {
294 // IPv6: Use Neighbor Discovery
Jonathan Hartf353e402016-09-23 09:27:36 -0700295 //TODO need to implement ndp probe
sdn94b00152016-08-30 02:12:32 -0700296 log.info("Triggering probe on device {} ", host);
297 }
298
299 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(host.location().port()).build();
300
301 OutboundPacket outboundPacket = new DefaultOutboundPacket(host.location().deviceId(), treatment,
302 ByteBuffer.wrap(probePacket.serialize()));
303
304 packetService.emit(outboundPacket);
305 }
306
307 /*
308 * This method is using source ip as 0.0.0.0 , to receive the reply even from the sub net hosts.
309 */
310 private Ethernet buildArpRequest(IpAddress targetIp, Host host) {
311
312 ARP arp = new ARP();
313 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
314 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
315 .setProtocolType(ARP.PROTO_TYPE_IP)
316 .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
317 .setOpCode(ARP.OP_REQUEST);
318
319 arp.setSenderHardwareAddress(MacAddress.BROADCAST.toBytes())
320 .setSenderProtocolAddress(SENDER_ADDRESS)
321 .setTargetHardwareAddress(MacAddress.BROADCAST.toBytes())
322 .setTargetProtocolAddress(targetIp.toOctets());
323
324 Ethernet ethernet = new Ethernet();
325 ethernet.setEtherType(Ethernet.TYPE_ARP)
326 .setDestinationMACAddress(MacAddress.BROADCAST)
327 .setSourceMACAddress(MacAddress.BROADCAST).setPayload(arp);
328
329 ethernet.setPad(true);
330 return ethernet;
alshabibe1cf87d2014-10-17 09:23:50 -0700331 }
332
333 private class InternalHostProvider implements PacketProcessor {
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800334 /**
335 * Update host location only.
336 *
Thomas Vachuska27bee092015-06-23 19:03:10 -0700337 * @param hid host ID
338 * @param mac source Mac address
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800339 * @param vlan VLAN ID
340 * @param hloc host location
341 */
342 private void updateLocation(HostId hid, MacAddress mac,
Thomas Vachuska27bee092015-06-23 19:03:10 -0700343 VlanId vlan, HostLocation hloc) {
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800344 HostDescription desc = new DefaultHostDescription(mac, vlan, hloc);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700345 try {
Ray Milkeydc083442016-02-22 11:27:57 -0800346 providerService.hostDetected(hid, desc, false);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700347 } catch (IllegalStateException e) {
348 log.debug("Host {} suppressed", hid);
349 }
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800350 }
Thomas Vachuska27bee092015-06-23 19:03:10 -0700351
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800352 /**
353 * Update host location and IP address.
354 *
Thomas Vachuska27bee092015-06-23 19:03:10 -0700355 * @param hid host ID
356 * @param mac source Mac address
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800357 * @param vlan VLAN ID
358 * @param hloc host location
Thomas Vachuska27bee092015-06-23 19:03:10 -0700359 * @param ip source IP address
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800360 */
361 private void updateLocationIP(HostId hid, MacAddress mac,
362 VlanId vlan, HostLocation hloc,
363 IpAddress ip) {
Thomas Vachuskae7966102015-09-09 17:33:33 -0700364 HostDescription desc = ip.isZero() || ip.isSelfAssigned() ?
Thomas Vachuskaec9c7dd2015-09-03 18:30:04 -0700365 new DefaultHostDescription(mac, vlan, hloc) :
366 new DefaultHostDescription(mac, vlan, hloc, ip);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700367 try {
Ray Milkeydc083442016-02-22 11:27:57 -0800368 providerService.hostDetected(hid, desc, false);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700369 } catch (IllegalStateException e) {
370 log.debug("Host {} suppressed", hid);
371 }
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800372 }
alshabibe1cf87d2014-10-17 09:23:50 -0700373
374 @Override
375 public void process(PacketContext context) {
alshabib4a179dc2014-10-17 17:17:01 -0700376 if (context == null) {
377 return;
378 }
alshabibe1cf87d2014-10-17 09:23:50 -0700379
Thomas Vachuskaf845cf62015-03-24 10:13:09 -0700380 Ethernet eth = context.inPacket().parsed();
Jonathan Harte8600eb2015-01-12 10:30:45 -0800381 if (eth == null) {
382 return;
383 }
Jonathan Hartf353e402016-09-23 09:27:36 -0700384
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800385 MacAddress srcMac = eth.getSourceMAC();
Jonathan Hartf353e402016-09-23 09:27:36 -0700386 if (srcMac.isBroadcast() || srcMac.isMulticast()) {
387 return;
388 }
Jonathan Harte8600eb2015-01-12 10:30:45 -0800389
alshabibe1cf87d2014-10-17 09:23:50 -0700390 VlanId vlan = VlanId.vlanId(eth.getVlanID());
391 ConnectPoint heardOn = context.inPacket().receivedFrom();
392
Thomas Vachuskaf845cf62015-03-24 10:13:09 -0700393 // If this arrived on control port, bail out.
394 if (heardOn.port().isLogical()) {
395 return;
396 }
397
alshabibe1cf87d2014-10-17 09:23:50 -0700398 // If this is not an edge port, bail out.
399 Topology topology = topologyService.currentTopology();
400 if (topologyService.isInfrastructure(topology, heardOn)) {
401 return;
402 }
403
Thomas Vachuskaec9c7dd2015-09-03 18:30:04 -0700404 HostLocation hloc = new HostLocation(heardOn, System.currentTimeMillis());
alshabibe1cf87d2014-10-17 09:23:50 -0700405 HostId hid = HostId.hostId(eth.getSourceMAC(), vlan);
406
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800407 // ARP: possible new hosts, update both location and IP
alshabibe1cf87d2014-10-17 09:23:50 -0700408 if (eth.getEtherType() == Ethernet.TYPE_ARP) {
409 ARP arp = (ARP) eth.getPayload();
Pavlin Radoslavovd6612f92015-02-23 13:53:32 -0800410 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET,
411 arp.getSenderProtocolAddress());
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800412 updateLocationIP(hid, srcMac, vlan, hloc, ip);
alshabibe1cf87d2014-10-17 09:23:50 -0700413
Charles Chan5d5e0622015-09-25 13:00:06 -0700414 // IPv4: update location only
alshabibe1cf87d2014-10-17 09:23:50 -0700415 } else if (eth.getEtherType() == Ethernet.TYPE_IPV4) {
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800416 updateLocation(hid, srcMac, vlan, hloc);
alshabibe1cf87d2014-10-17 09:23:50 -0700417
Charles Chan5d5e0622015-09-25 13:00:06 -0700418 //
419 // NeighborAdvertisement and NeighborSolicitation: possible
420 // new hosts, update both location and IP.
421 //
422 // IPv6: update location only
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800423 } else if (eth.getEtherType() == Ethernet.TYPE_IPV6) {
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800424 IPv6 ipv6 = (IPv6) eth.getPayload();
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800425 IpAddress ip = IpAddress.valueOf(IpAddress.Version.INET6,
Thomas Vachuska27bee092015-06-23 19:03:10 -0700426 ipv6.getSourceAddress());
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800427
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800428 // skip extension headers
429 IPacket pkt = ipv6;
430 while (pkt.getPayload() != null &&
431 pkt.getPayload() instanceof IExtensionHeader) {
432 pkt = pkt.getPayload();
433 }
434
435 // Neighbor Discovery Protocol
Charles M.C. Chan9148d2d2015-04-27 03:36:39 +0800436 pkt = pkt.getPayload();
437 if (pkt != null && pkt instanceof ICMP6) {
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800438 pkt = pkt.getPayload();
439 // RouterSolicitation, RouterAdvertisement
Charles M.C. Chan9148d2d2015-04-27 03:36:39 +0800440 if (pkt != null && (pkt instanceof RouterAdvertisement ||
Thomas Vachuska27bee092015-06-23 19:03:10 -0700441 pkt instanceof RouterSolicitation)) {
Charles M.C. Chan441d7da2015-03-17 21:03:39 +0800442 return;
443 }
Charles M.C. Chan9148d2d2015-04-27 03:36:39 +0800444 if (pkt != null && (pkt instanceof NeighborSolicitation ||
Thomas Vachuska27bee092015-06-23 19:03:10 -0700445 pkt instanceof NeighborAdvertisement)) {
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800446 // Duplicate Address Detection
447 if (ip.isZero()) {
Charles M.C. Chan441d7da2015-03-17 21:03:39 +0800448 return;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800449 }
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800450 // NeighborSolicitation, NeighborAdvertisement
451 updateLocationIP(hid, srcMac, vlan, hloc, ip);
452 return;
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800453 }
Charles M.C. Chan7fee36a2014-12-31 00:19:59 +0800454 }
Charles M.C. Chan956cb692015-04-26 18:49:39 +0800455
456 // multicast
457 if (eth.isMulticast()) {
458 return;
459 }
460
461 // normal IPv6 packets
462 updateLocation(hid, srcMac, vlan, hloc);
alshabibe1cf87d2014-10-17 09:23:50 -0700463 }
464 }
465 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800466
467 // Auxiliary listener to device events.
468 private class InternalDeviceListener implements DeviceListener {
469 @Override
470 public void event(DeviceEvent event) {
Madan Jampania3770c32015-12-11 12:07:41 -0800471 eventHandler.execute(() -> handleEvent(event));
472 }
473
474 private void handleEvent(DeviceEvent event) {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800475 Device device = event.subject();
476 switch (event.type()) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700477 case DEVICE_ADDED:
478 break;
479 case DEVICE_AVAILABILITY_CHANGED:
480 if (hostRemovalEnabled &&
481 !deviceService.isAvailable(device.id())) {
482 removeHosts(hostService.getConnectedHosts(device.id()));
483 }
484 break;
485 case DEVICE_SUSPENDED:
486 case DEVICE_UPDATED:
487 // Nothing to do?
488 break;
489 case DEVICE_REMOVED:
490 if (hostRemovalEnabled) {
491 removeHosts(hostService.getConnectedHosts(device.id()));
492 }
493 break;
494 case PORT_ADDED:
495 break;
496 case PORT_UPDATED:
497 if (hostRemovalEnabled) {
498 ConnectPoint point =
499 new ConnectPoint(device.id(), event.port().number());
500 removeHosts(hostService.getConnectedHosts(point));
501 }
502 break;
503 case PORT_REMOVED:
504 // Nothing to do?
505 break;
506 default:
507 break;
Thomas Vachuska33601602014-11-19 03:32:15 -0800508 }
509 }
510 }
511
512 // Signals host vanish for all specified hosts.
513 private void removeHosts(Set<Host> hosts) {
514 for (Host host : hosts) {
Charles Chan8b0fdaa2016-02-23 18:35:27 -0800515 if (host.providerId().equals(HostLocationProvider.this.id())) {
516 providerService.hostVanished(host.id());
517 }
Thomas Vachuska33601602014-11-19 03:32:15 -0800518 }
519 }
520
alshabibe1cf87d2014-10-17 09:23:50 -0700521}