blob: cd35359745695e5636837195a73271956ad592b0 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.proxyarp.impl;
alshabibb5522ff2014-09-29 19:20:00 -070017
18import static com.google.common.base.Preconditions.checkArgument;
19import static com.google.common.base.Preconditions.checkNotNull;
20import static org.slf4j.LoggerFactory.getLogger;
21
22import java.nio.ByteBuffer;
Jonathan Hart1f793a72014-11-12 23:22:02 -080023import java.util.HashSet;
alshabibb5522ff2014-09-29 19:20:00 -070024import java.util.List;
25import java.util.Map.Entry;
26import java.util.Set;
27
28import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
31import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
33import org.apache.felix.scr.annotations.Service;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080034import org.onosproject.core.ApplicationId;
35import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.ConnectPoint;
37import org.onosproject.net.Device;
38import org.onosproject.net.Host;
39import org.onosproject.net.HostId;
40import org.onosproject.net.Link;
41import org.onosproject.net.Port;
42import org.onosproject.net.PortNumber;
43import org.onosproject.net.device.DeviceEvent;
44import org.onosproject.net.device.DeviceListener;
45import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080046import org.onosproject.net.flow.DefaultFlowRule;
47import org.onosproject.net.flow.DefaultTrafficSelector;
Brian O'Connorabafb502014-12-02 22:26:20 -080048import org.onosproject.net.flow.DefaultTrafficTreatment;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080049import org.onosproject.net.flow.FlowRule;
50import org.onosproject.net.flow.FlowRuleService;
51import org.onosproject.net.flow.TrafficSelector;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.net.flow.TrafficTreatment;
53import org.onosproject.net.host.HostService;
54import org.onosproject.net.host.InterfaceIpAddress;
55import org.onosproject.net.host.PortAddresses;
56import org.onosproject.net.link.LinkEvent;
57import org.onosproject.net.link.LinkListener;
58import org.onosproject.net.link.LinkService;
59import org.onosproject.net.packet.DefaultOutboundPacket;
60import org.onosproject.net.packet.InboundPacket;
61import org.onosproject.net.packet.PacketContext;
62import org.onosproject.net.packet.PacketService;
63import org.onosproject.net.proxyarp.ProxyArpService;
alshabibb5522ff2014-09-29 19:20:00 -070064import org.onlab.packet.ARP;
65import org.onlab.packet.Ethernet;
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -080066import org.onlab.packet.Ip4Address;
Jonathan Hart1f793a72014-11-12 23:22:02 -080067import org.onlab.packet.IpAddress;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -070068import org.onlab.packet.MacAddress;
alshabibb5522ff2014-09-29 19:20:00 -070069import org.onlab.packet.VlanId;
70import org.slf4j.Logger;
71
72import com.google.common.collect.HashMultimap;
73import com.google.common.collect.Lists;
74import com.google.common.collect.Multimap;
75
alshabibb5522ff2014-09-29 19:20:00 -070076@Component(immediate = true)
77@Service
78public class ProxyArpManager implements ProxyArpService {
79
80 private final Logger log = getLogger(getClass());
81
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080082 private static final int FLOW_RULE_PRIORITY = 40000;
83
alshabibb5522ff2014-09-29 19:20:00 -070084 private static final String MAC_ADDR_NULL = "Mac address cannot be null.";
85 private static final String REQUEST_NULL = "Arp request cannot be null.";
86 private static final String REQUEST_NOT_ARP = "Ethernet frame does not contain ARP request.";
87 private static final String NOT_ARP_REQUEST = "ARP is not a request.";
Jonathan Hart704ca142014-10-09 09:34:39 -070088 private static final String NOT_ARP_REPLY = "ARP is not a reply.";
alshabibb5522ff2014-09-29 19:20:00 -070089
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080091 protected CoreService coreService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected FlowRuleService flowRuleService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabibb5522ff2014-09-29 19:20:00 -070097 protected HostService hostService;
98
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected PacketService packetService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected LinkService linkService;
104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected DeviceService deviceService;
107
108 private final Multimap<Device, PortNumber> internalPorts =
109 HashMultimap.<Device, PortNumber>create();
110
111 private final Multimap<Device, PortNumber> externalPorts =
112 HashMultimap.<Device, PortNumber>create();
113
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800114 private ApplicationId appId;
115
alshabibb5522ff2014-09-29 19:20:00 -0700116 /**
117 * Listens to both device service and link service to determine
118 * whether a port is internal or external.
119 */
120 @Activate
121 public void activate() {
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800122 appId =
123 coreService.registerApplication("org.onosproject.net.proxyarp");
124
alshabibb5522ff2014-09-29 19:20:00 -0700125 deviceService.addListener(new InternalDeviceListener());
126 linkService.addListener(new InternalLinkListener());
127 determinePortLocations();
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800128 pushRules();
129
alshabibb5522ff2014-09-29 19:20:00 -0700130 log.info("Started");
131 }
132
133
134 @Deactivate
135 public void deactivate() {
136 log.info("Stopped");
137 }
138
139 @Override
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800140 public boolean known(Ip4Address addr) {
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700141 checkNotNull(addr, MAC_ADDR_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700142 Set<Host> hosts = hostService.getHostsByIp(addr);
143 return !hosts.isEmpty();
144 }
145
146 @Override
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700147 public void reply(Ethernet eth, ConnectPoint inPort) {
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700148 checkNotNull(eth, REQUEST_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700149 checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP,
150 REQUEST_NOT_ARP);
151 ARP arp = (ARP) eth.getPayload();
152 checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700153 checkNotNull(inPort);
154
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700155 // If the request came from outside the network, only reply if it was
156 // for one of our external addresses.
157 if (isOutsidePort(inPort)) {
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800158 Ip4Address target =
159 Ip4Address.valueOf(arp.getTargetProtocolAddress());
Jonathan Harta887ba82014-11-03 15:20:52 -0800160 Set<PortAddresses> addressSet =
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700161 hostService.getAddressBindingsForPort(inPort);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700162
Jonathan Harta887ba82014-11-03 15:20:52 -0800163 for (PortAddresses addresses : addressSet) {
164 for (InterfaceIpAddress ia : addresses.ipAddresses()) {
165 if (ia.ipAddress().equals(target)) {
166 Ethernet arpReply =
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800167 buildArpReply(target, addresses.mac(), eth);
Jonathan Harta887ba82014-11-03 15:20:52 -0800168 sendTo(arpReply, inPort);
169 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700170 }
171 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700172 return;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700173 } else {
174 // If the source address matches one of our external addresses
175 // it could be a request from an internal host to an external
Jonathan Hart1f793a72014-11-12 23:22:02 -0800176 // address. Forward it over to the correct ports.
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800177 Ip4Address source =
178 Ip4Address.valueOf(arp.getSenderProtocolAddress());
Jonathan Hart1f793a72014-11-12 23:22:02 -0800179 Set<PortAddresses> sourceAddresses = findPortsInSubnet(source);
180 boolean matched = false;
181 for (PortAddresses pa : sourceAddresses) {
182 for (InterfaceIpAddress ia : pa.ipAddresses()) {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700183 if (ia.ipAddress().equals(source)) {
Jonathan Hart1f793a72014-11-12 23:22:02 -0800184 matched = true;
185 sendTo(eth, pa.connectPoint());
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700186 }
187 }
188 }
Jonathan Hart1f793a72014-11-12 23:22:02 -0800189
190 if (matched) {
191 return;
192 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700193 }
194
195 // Continue with normal proxy ARP case
alshabibb5522ff2014-09-29 19:20:00 -0700196
197 VlanId vlan = VlanId.vlanId(eth.getVlanID());
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800198 Set<Host> hosts = hostService.getHostsByIp(
199 Ip4Address.valueOf(arp.getTargetProtocolAddress()));
alshabibb5522ff2014-09-29 19:20:00 -0700200
201 Host dst = null;
202 Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(),
203 VlanId.vlanId(eth.getVlanID())));
204
205 for (Host host : hosts) {
206 if (host.vlan().equals(vlan)) {
207 dst = host;
208 break;
209 }
210 }
211
212 if (src == null || dst == null) {
213 flood(eth);
214 return;
215 }
216
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800217 //
218 // TODO find the correct IP address.
219 // Right now we use the first IPv4 address that is found.
220 //
221 for (IpAddress ipAddress : dst.ipAddresses()) {
222 Ip4Address ip4Address = ipAddress.getIp4Address();
223 if (ip4Address != null) {
224 Ethernet arpReply = buildArpReply(ip4Address, dst.mac(), eth);
225 // TODO: check send status with host service.
226 sendTo(arpReply, src.location());
227 break;
228 }
229 }
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700230 }
231
232 /**
233 * Outputs the given packet out the given port.
234 *
235 * @param packet the packet to send
236 * @param outPort the port to send it out
237 */
238 private void sendTo(Ethernet packet, ConnectPoint outPort) {
239 if (internalPorts.containsEntry(
240 deviceService.getDevice(outPort.deviceId()), outPort.port())) {
241 // Sanity check to make sure we don't send the packet out an
242 // internal port and create a loop (could happen due to
243 // misconfiguration).
244 return;
245 }
246
tom9a693fd2014-10-03 11:32:19 -0700247 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700248 builder.setOutput(outPort.port());
249 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
250 builder.build(), ByteBuffer.wrap(packet.serialize())));
251 }
252
253 /**
Jonathan Hart1f793a72014-11-12 23:22:02 -0800254 * Finds ports with an address in the subnet of the target address.
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700255 *
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700256 * @param target the target address to find a matching port for
Jonathan Hart1f793a72014-11-12 23:22:02 -0800257 * @return a set of PortAddresses describing ports in the subnet
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700258 */
Jonathan Hart1f793a72014-11-12 23:22:02 -0800259 private Set<PortAddresses> findPortsInSubnet(Ip4Address target) {
260 Set<PortAddresses> result = new HashSet<PortAddresses>();
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700261 for (PortAddresses addresses : hostService.getAddressBindings()) {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700262 for (InterfaceIpAddress ia : addresses.ipAddresses()) {
263 if (ia.subnetAddress().contains(target)) {
Jonathan Hart1f793a72014-11-12 23:22:02 -0800264 result.add(addresses);
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700265 }
266 }
267 }
Jonathan Hart1f793a72014-11-12 23:22:02 -0800268 return result;
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700269 }
270
271 /**
272 * Returns whether the given port is an outside-facing port with an IP
273 * address configured.
274 *
275 * @param port the port to check
276 * @return true if the port is an outside-facing port, otherwise false
277 */
278 private boolean isOutsidePort(ConnectPoint port) {
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700279 //
280 // TODO: Is this sufficient to identify outside-facing ports: just
281 // having IP addresses on a port?
282 //
Jonathan Harta887ba82014-11-03 15:20:52 -0800283 return !hostService.getAddressBindingsForPort(port).isEmpty();
alshabibb5522ff2014-09-29 19:20:00 -0700284 }
285
286 @Override
287 public void forward(Ethernet eth) {
Yuta HIGUCHI59718042014-10-04 22:04:56 -0700288 checkNotNull(eth, REQUEST_NULL);
alshabibb5522ff2014-09-29 19:20:00 -0700289 checkArgument(eth.getEtherType() == Ethernet.TYPE_ARP,
290 REQUEST_NOT_ARP);
291 ARP arp = (ARP) eth.getPayload();
Jonathan Hart704ca142014-10-09 09:34:39 -0700292 checkArgument(arp.getOpCode() == ARP.OP_REPLY, NOT_ARP_REPLY);
alshabibb5522ff2014-09-29 19:20:00 -0700293
294 Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(),
295 VlanId.vlanId(eth.getVlanID())));
296
297 if (h == null) {
298 flood(eth);
299 } else {
tom9a693fd2014-10-03 11:32:19 -0700300 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
alshabibb5522ff2014-09-29 19:20:00 -0700301 builder.setOutput(h.location().port());
302 packetService.emit(new DefaultOutboundPacket(h.location().deviceId(),
303 builder.build(), ByteBuffer.wrap(eth.serialize())));
304 }
305
306 }
307
alshabibc274c902014-10-03 14:58:27 -0700308 @Override
309 public boolean handleArp(PacketContext context) {
310 InboundPacket pkt = context.inPacket();
311 Ethernet ethPkt = pkt.parsed();
312 if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
313 ARP arp = (ARP) ethPkt.getPayload();
314 if (arp.getOpCode() == ARP.OP_REPLY) {
315 forward(ethPkt);
316 } else if (arp.getOpCode() == ARP.OP_REQUEST) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700317 reply(ethPkt, context.inPacket().receivedFrom());
alshabibc274c902014-10-03 14:58:27 -0700318 }
319 context.block();
320 return true;
321 }
322 return false;
323 }
324
alshabibb5522ff2014-09-29 19:20:00 -0700325 /**
326 * Flood the arp request at all edges in the network.
327 * @param request the arp request.
328 */
329 private void flood(Ethernet request) {
330 TrafficTreatment.Builder builder = null;
331 ByteBuffer buf = ByteBuffer.wrap(request.serialize());
332
333 synchronized (externalPorts) {
334 for (Entry<Device, PortNumber> entry : externalPorts.entries()) {
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700335 ConnectPoint cp = new ConnectPoint(entry.getKey().id(), entry.getValue());
336 if (isOutsidePort(cp)) {
337 continue;
338 }
339
tom9a693fd2014-10-03 11:32:19 -0700340 builder = DefaultTrafficTreatment.builder();
alshabibb5522ff2014-09-29 19:20:00 -0700341 builder.setOutput(entry.getValue());
342 packetService.emit(new DefaultOutboundPacket(entry.getKey().id(),
343 builder.build(), buf));
344 }
alshabibb5522ff2014-09-29 19:20:00 -0700345 }
346 }
347
348 /**
349 * Determines the location of all known ports in the system.
350 */
351 private void determinePortLocations() {
352 Iterable<Device> devices = deviceService.getDevices();
353 Iterable<Link> links = null;
354 List<PortNumber> ports = null;
355 for (Device d : devices) {
356 ports = buildPortNumberList(deviceService.getPorts(d.id()));
357 links = linkService.getLinks();
358 for (Link l : links) {
359 // for each link, mark the concerned ports as internal
360 // and the remaining ports are therefore external.
Yuta HIGUCHI3541bf22014-10-04 22:06:19 -0700361 if (l.src().deviceId().equals(d.id())
alshabibb5522ff2014-09-29 19:20:00 -0700362 && ports.contains(l.src().port())) {
363 ports.remove(l.src().port());
364 internalPorts.put(d, l.src().port());
365 }
Yuta HIGUCHI3541bf22014-10-04 22:06:19 -0700366 if (l.dst().deviceId().equals(d.id())
alshabibb5522ff2014-09-29 19:20:00 -0700367 && ports.contains(l.dst().port())) {
368 ports.remove(l.dst().port());
369 internalPorts.put(d, l.dst().port());
370 }
371 }
372 synchronized (externalPorts) {
373 externalPorts.putAll(d, ports);
374 }
375 }
376
377 }
378
379 private List<PortNumber> buildPortNumberList(List<Port> ports) {
380 List<PortNumber> portNumbers = Lists.newLinkedList();
381 for (Port p : ports) {
382 portNumbers.add(p.number());
383 }
384 return portNumbers;
385 }
386
387 /**
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700388 * Builds an ARP reply based on a request.
389 *
390 * @param srcIp the IP address to use as the reply source
391 * @param srcMac the MAC address to use as the reply source
392 * @param request the ARP request we got
393 * @return an Ethernet frame containing the ARP reply
alshabibb5522ff2014-09-29 19:20:00 -0700394 */
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800395 private Ethernet buildArpReply(Ip4Address srcIp, MacAddress srcMac,
Jonathan Hartdbdbdbb2014-10-06 18:35:30 -0700396 Ethernet request) {
397
alshabibb5522ff2014-09-29 19:20:00 -0700398 Ethernet eth = new Ethernet();
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800399 eth.setDestinationMACAddress(request.getSourceMAC());
400 eth.setSourceMACAddress(srcMac);
alshabibb5522ff2014-09-29 19:20:00 -0700401 eth.setEtherType(Ethernet.TYPE_ARP);
402 eth.setVlanID(request.getVlanID());
403
404 ARP arp = new ARP();
405 arp.setOpCode(ARP.OP_REPLY);
406 arp.setProtocolType(ARP.PROTO_TYPE_IP);
407 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
alshabib6eb438a2014-10-01 16:39:37 -0700408
Pavlin Radoslavov5b5dc482014-11-05 14:48:08 -0800409 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
alshabibb5522ff2014-09-29 19:20:00 -0700410 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800411 arp.setSenderHardwareAddress(srcMac.toBytes());
alshabibb5522ff2014-09-29 19:20:00 -0700412 arp.setTargetHardwareAddress(request.getSourceMACAddress());
413
414 arp.setTargetProtocolAddress(((ARP) request.getPayload())
415 .getSenderProtocolAddress());
Jonathan Hartbcae7bd2014-10-16 10:24:41 -0700416 arp.setSenderProtocolAddress(srcIp.toInt());
alshabibb5522ff2014-09-29 19:20:00 -0700417 eth.setPayload(arp);
418 return eth;
419 }
420
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800421 /**
422 * Pushes flow rules to all devices.
423 */
424 private void pushRules() {
425 for (Device device : deviceService.getDevices()) {
426 pushRules(device);
427 }
428 }
429
430 /**
431 * Pushes flow rules to the device to receive control packets that need
432 * to be processed.
433 *
434 * @param device the device to push the rules to
435 */
436 private synchronized void pushRules(Device device) {
437 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
438 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
439
440 // Get all ARP packets
441 sbuilder.matchEthType(Ethernet.TYPE_ARP);
442 tbuilder.punt();
443 FlowRule flowArp =
444 new DefaultFlowRule(device.id(),
445 sbuilder.build(), tbuilder.build(),
446 FLOW_RULE_PRIORITY, appId, 0, true);
447
448 flowRuleService.applyFlowRules(flowArp);
449 }
450
alshabibb5522ff2014-09-29 19:20:00 -0700451 public class InternalLinkListener implements LinkListener {
452
453 @Override
454 public void event(LinkEvent event) {
455 Link link = event.subject();
456 Device src = deviceService.getDevice(link.src().deviceId());
457 Device dst = deviceService.getDevice(link.dst().deviceId());
458 switch (event.type()) {
459 case LINK_ADDED:
460 synchronized (externalPorts) {
461 externalPorts.remove(src, link.src().port());
462 externalPorts.remove(dst, link.dst().port());
463 internalPorts.put(src, link.src().port());
464 internalPorts.put(dst, link.dst().port());
465 }
466
467 break;
468 case LINK_REMOVED:
469 synchronized (externalPorts) {
470 externalPorts.put(src, link.src().port());
471 externalPorts.put(dst, link.dst().port());
472 internalPorts.remove(src, link.src().port());
473 internalPorts.remove(dst, link.dst().port());
474 }
475
476 break;
477 case LINK_UPDATED:
478 // don't care about links being updated.
479 break;
480 default:
481 break;
482 }
483
484 }
485
486 }
487
488 public class InternalDeviceListener implements DeviceListener {
489
490 @Override
491 public void event(DeviceEvent event) {
492 Device device = event.subject();
493 switch (event.type()) {
494 case DEVICE_ADDED:
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800495 pushRules(device);
496 break;
alshabibb5522ff2014-09-29 19:20:00 -0700497 case DEVICE_AVAILABILITY_CHANGED:
alshabibb5522ff2014-09-29 19:20:00 -0700498 case DEVICE_SUSPENDED:
499 case DEVICE_UPDATED:
alshabibb5522ff2014-09-29 19:20:00 -0700500 // nothing to do in these cases; handled when links get reported
501 break;
502 case DEVICE_REMOVED:
503 synchronized (externalPorts) {
504 externalPorts.removeAll(device);
505 internalPorts.removeAll(device);
506 }
507 break;
508 case PORT_ADDED:
alshabib6eb438a2014-10-01 16:39:37 -0700509 case PORT_UPDATED:
alshabibb5522ff2014-09-29 19:20:00 -0700510 synchronized (externalPorts) {
alshabib6eb438a2014-10-01 16:39:37 -0700511 if (event.port().isEnabled()) {
512 externalPorts.put(device, event.port().number());
513 internalPorts.remove(device, event.port().number());
514 }
alshabibb5522ff2014-09-29 19:20:00 -0700515 }
516 break;
517 case PORT_REMOVED:
518 synchronized (externalPorts) {
519 externalPorts.remove(device, event.port().number());
520 internalPorts.remove(device, event.port().number());
521 }
522 break;
523 default:
524 break;
525
526 }
527
528 }
529
alshabibc274c902014-10-03 14:58:27 -0700530 }
alshabibb5522ff2014-09-29 19:20:00 -0700531
532}