blob: fe1a8008ba941a63bd3bb68d494f86aac42bb5d8 [file] [log] [blame]
Jonathan Hart9bdaaec2016-08-22 13:33:45 -07001/*
2 * Copyright 2016-present 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 */
16
17package org.onosproject.incubator.net.neighbour.impl;
18
Jonathan Hartc4f681c2016-09-09 07:14:25 -070019import com.google.common.collect.HashMultimap;
20import com.google.common.collect.ImmutableMap;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070021import com.google.common.collect.Multimaps;
Jonathan Hartc4f681c2016-09-09 07:14:25 -070022import com.google.common.collect.SetMultimap;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
26import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.apache.felix.scr.annotations.Service;
31import org.onlab.packet.ARP;
32import org.onlab.packet.Ethernet;
33import org.onlab.packet.ICMP6;
34import org.onlab.packet.IPv6;
35import org.onlab.packet.Ip4Address;
36import org.onlab.packet.Ip6Address;
Jonathan Hartc4f681c2016-09-09 07:14:25 -070037import org.onlab.packet.IpAddress;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070038import org.onlab.packet.MacAddress;
39import org.onlab.packet.VlanId;
40import org.onlab.packet.ndp.NeighborAdvertisement;
41import org.onlab.packet.ndp.NeighborDiscoveryOptions;
42import org.onlab.util.Tools;
43import org.onosproject.cfg.ComponentConfigService;
44import org.onosproject.core.ApplicationId;
45import org.onosproject.core.CoreService;
46import org.onosproject.incubator.net.intf.Interface;
Jonathan Hartc4f681c2016-09-09 07:14:25 -070047import org.onosproject.incubator.net.neighbour.NeighbourHandlerRegistration;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070048import org.onosproject.incubator.net.neighbour.NeighbourMessageActions;
49import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
50import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler;
51import org.onosproject.incubator.net.neighbour.NeighbourResolutionService;
52import org.onosproject.net.ConnectPoint;
53import org.onosproject.net.edge.EdgePortService;
54import org.onosproject.net.flow.DefaultTrafficSelector;
55import org.onosproject.net.flow.DefaultTrafficTreatment;
56import org.onosproject.net.flow.TrafficSelector;
57import org.onosproject.net.flow.TrafficTreatment;
58import org.onosproject.net.host.HostService;
59import org.onosproject.net.packet.DefaultOutboundPacket;
60import org.onosproject.net.packet.InboundPacket;
61import org.onosproject.net.packet.PacketContext;
62import org.onosproject.net.packet.PacketProcessor;
63import org.onosproject.net.packet.PacketService;
64import org.osgi.service.component.ComponentContext;
65import org.slf4j.Logger;
66import org.slf4j.LoggerFactory;
67
68import java.nio.ByteBuffer;
Jonathan Hartc4f681c2016-09-09 07:14:25 -070069import java.util.Collection;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070070import java.util.Dictionary;
Jonathan Hartc4f681c2016-09-09 07:14:25 -070071import java.util.Iterator;
72import java.util.Map;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070073import java.util.Objects;
74
75import static com.google.common.base.Preconditions.checkNotNull;
76import static org.onlab.packet.Ethernet.TYPE_ARP;
77import static org.onlab.packet.Ethernet.TYPE_IPV6;
78import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
79import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
80import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
81import static org.onosproject.net.packet.PacketPriority.CONTROL;
82
83/**
84 * Manages handlers for neighbour messages.
85 */
86@Service
Jonathan Hartc4f681c2016-09-09 07:14:25 -070087@Component(immediate = true)
Jonathan Hart1e393bb2016-09-14 08:51:09 -070088public class NeighbourResolutionManager implements NeighbourResolutionService {
Jonathan Hart9bdaaec2016-08-22 13:33:45 -070089
90 private final Logger log = LoggerFactory.getLogger(getClass());
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected HostService hostService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected EdgePortService edgeService;
100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 protected PacketService packetService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected ComponentConfigService componentConfigService;
106
107 @Property(name = "ndpEnabled", boolValue = false,
108 label = "Enable IPv6 neighbour discovery")
109 protected boolean ndpEnabled = false;
110
111 private static final String APP_NAME = "org.onosproject.neighbour";
112 private ApplicationId appId;
113
Jonathan Hartc004adf2016-09-15 16:50:04 -0700114 private final SetMultimap<ConnectPoint, NeighbourHandlerRegistration> packetHandlers =
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700115 Multimaps.synchronizedSetMultimap(HashMultimap.create());
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700116
117 private final InternalPacketProcessor processor = new InternalPacketProcessor();
118 private final InternalNeighbourMessageActions actions = new InternalNeighbourMessageActions();
119
120 @Activate
121 protected void activate(ComponentContext context) {
122 appId = coreService.registerApplication(APP_NAME);
123
124 componentConfigService.registerProperties(getClass());
125 modified(context);
126
127 packetService.addProcessor(processor, PacketProcessor.director(1));
128 }
129
130 @Deactivate
131 protected void deactivate() {
132 cancelPackets();
133 packetService.removeProcessor(processor);
134 componentConfigService.unregisterProperties(getClass(), false);
135 }
136
137 @Modified
138 protected void modified(ComponentContext context) {
139 Dictionary<?, ?> properties = context.getProperties();
140 Boolean flag;
141
142 flag = Tools.isPropertyEnabled(properties, "ndpEnabled");
143 if (flag != null) {
144 ndpEnabled = flag;
145 log.info("IPv6 neighbor discovery is {}",
146 ndpEnabled ? "enabled" : "disabled");
147 }
148
Jonathan Hartc004adf2016-09-15 16:50:04 -0700149 synchronized (packetHandlers) {
150 if (!packetHandlers.isEmpty()) {
151 requestPackets();
152 }
153 }
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700154 }
155
156 private void requestPackets() {
157 packetService.requestPackets(buildArpSelector(), CONTROL, appId);
158
159 if (ndpEnabled) {
160 packetService.requestPackets(buildNeighborSolicitationSelector(),
161 CONTROL, appId);
162 packetService.requestPackets(buildNeighborAdvertisementSelector(),
163 CONTROL, appId);
164 } else {
165 packetService.cancelPackets(buildNeighborSolicitationSelector(),
166 CONTROL, appId);
167 packetService.cancelPackets(buildNeighborAdvertisementSelector(),
168 CONTROL, appId);
169 }
170 }
171
172 private void cancelPackets() {
173 packetService.cancelPackets(buildArpSelector(), CONTROL, appId);
174 packetService.cancelPackets(buildNeighborSolicitationSelector(),
175 CONTROL, appId);
176 packetService.cancelPackets(buildNeighborAdvertisementSelector(),
177 CONTROL, appId);
178 }
179
180 private TrafficSelector buildArpSelector() {
181 return DefaultTrafficSelector.builder()
182 .matchEthType(TYPE_ARP)
183 .build();
184 }
185
186 private TrafficSelector buildNeighborSolicitationSelector() {
187 return DefaultTrafficSelector.builder()
188 .matchEthType(TYPE_IPV6)
189 .matchIPProtocol(PROTOCOL_ICMP6)
190 .matchIcmpv6Type(NEIGHBOR_SOLICITATION)
191 .build();
192 }
193
194 private TrafficSelector buildNeighborAdvertisementSelector() {
195 return DefaultTrafficSelector.builder()
196 .matchEthType(TYPE_IPV6)
197 .matchIPProtocol(PROTOCOL_ICMP6)
198 .matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT)
199 .build();
200 }
201
202 @Override
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700203 public void registerNeighbourHandler(ConnectPoint connectPoint,
204 NeighbourMessageHandler handler,
205 ApplicationId appId) {
Jonathan Hartc004adf2016-09-15 16:50:04 -0700206 register(connectPoint, new HandlerRegistration(handler, appId));
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700207 }
208
209 @Override
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700210 public void registerNeighbourHandler(Interface intf,
211 NeighbourMessageHandler handler,
212 ApplicationId appId) {
Jonathan Hartc004adf2016-09-15 16:50:04 -0700213 register(intf.connectPoint(), new HandlerRegistration(handler, intf, appId));
214 }
215
216 private void register(ConnectPoint connectPoint, HandlerRegistration registration) {
217 synchronized (packetHandlers) {
218 if (packetHandlers.isEmpty()) {
219 requestPackets();
220 }
221 packetHandlers.put(connectPoint, registration);
222 }
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700223 }
224
225 @Override
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700226 public void unregisterNeighbourHandler(ConnectPoint connectPoint,
227 NeighbourMessageHandler handler,
228 ApplicationId appId) {
Jonathan Hartc004adf2016-09-15 16:50:04 -0700229 unregister(connectPoint, new HandlerRegistration(handler, appId));
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700230 }
231
232 @Override
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700233 public void unregisterNeighbourHandler(Interface intf,
234 NeighbourMessageHandler handler,
235 ApplicationId appId) {
Jonathan Hartc004adf2016-09-15 16:50:04 -0700236 unregister(intf.connectPoint(), new HandlerRegistration(handler, intf, appId));
237 }
238
239 private void unregister(ConnectPoint connectPoint, HandlerRegistration registration) {
240 synchronized (packetHandlers) {
241 packetHandlers.remove(connectPoint, registration);
242
243 if (packetHandlers.isEmpty()) {
244 cancelPackets();
245 }
246 }
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700247 }
248
249 @Override
250 public void unregisterNeighbourHandlers(ApplicationId appId) {
251 synchronized (packetHandlers) {
252 Iterator<NeighbourHandlerRegistration> it = packetHandlers.values().iterator();
253
254 while (it.hasNext()) {
255 NeighbourHandlerRegistration registration = it.next();
256 if (registration.appId().equals(appId)) {
257 it.remove();
258 }
259 }
Jonathan Hartc004adf2016-09-15 16:50:04 -0700260
261 if (packetHandlers.isEmpty()) {
262 cancelPackets();
263 }
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700264 }
265 }
266
267 @Override
268 public Map<ConnectPoint, Collection<NeighbourHandlerRegistration>> getHandlerRegistrations() {
269 return ImmutableMap.copyOf(Multimaps.asMap(packetHandlers));
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700270 }
271
272 public void handlePacket(PacketContext context) {
273 InboundPacket pkt = context.inPacket();
274 Ethernet ethPkt = pkt.parsed();
275
276 NeighbourMessageContext msgContext =
277 DefaultNeighbourMessageContext.createContext(ethPkt, pkt.receivedFrom(), actions);
278
279 if (msgContext == null) {
280 return;
281 }
282
283 handleMessage(msgContext);
284
285 context.block();
286 }
287
288 private void handleMessage(NeighbourMessageContext context) {
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700289 Collection<NeighbourHandlerRegistration> handlers = packetHandlers.get(context.inPort());
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700290
291 handlers.forEach(registration -> {
292 if (registration.intf() == null || matches(context, registration.intf())) {
293 registration.handler().handleMessage(context, hostService);
294 }
295 });
296 }
297
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700298 /**
299 * Checks that incoming packet matches the parameters of the interface.
300 * This means that if the interface specifies a particular parameter
301 * (VLAN, IP address, etc.) then the incoming packet should match those
302 * parameters.
303 *
304 * @param context incoming message context
305 * @param intf interface to check
306 * @return true if the incoming message matches the interface, otherwise false
307 */
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700308 private boolean matches(NeighbourMessageContext context, Interface intf) {
309 checkNotNull(context);
310 checkNotNull(intf);
311
312 boolean matches = true;
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700313 // For non-broadcast packets, if the interface has a MAC address check that
314 // the destination MAC address of the packet matches the interface MAC
315 if (!context.dstMac().isBroadcast() &&
316 !intf.mac().equals(MacAddress.NONE) &&
317 !intf.mac().equals(context.dstMac())) {
318 matches = false;
319 }
320 // If the interface has a VLAN, check that the packet's VLAN matches
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700321 if (!intf.vlan().equals(VlanId.NONE) && !intf.vlan().equals(context.vlan())) {
322 matches = false;
323 }
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700324 // If the interface has IP addresses, check that the packet's target IP
325 // address matches one of the interface IP addresses
326 if (!intf.ipAddressesList().isEmpty() && !hasIp(intf, context.target())) {
327 matches = false;
328 }
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700329
330 return matches;
331 }
332
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700333 /**
334 * Returns true if the interface has the given IP address.
335 *
336 * @param intf interface to check
337 * @param ip IP address
338 * @return true if the IP is configured on the interface, otherwise false
339 */
340 private boolean hasIp(Interface intf, IpAddress ip) {
341 return intf.ipAddressesList().stream()
342 .anyMatch(intfAddress -> intfAddress.ipAddress().equals(ip));
343 }
344
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700345 private void reply(NeighbourMessageContext context, MacAddress targetMac) {
346 switch (context.protocol()) {
347 case ARP:
348 sendTo(ARP.buildArpReply((Ip4Address) context.target(),
349 targetMac, context.packet()), context.inPort());
350 break;
351 case NDP:
352 sendTo(buildNdpReply((Ip6Address) context.target(), targetMac,
353 context.packet()), context.inPort());
354 break;
355 default:
356 break;
357 }
358 }
359
360 /**
361 * Outputs a packet out a specific port.
362 *
363 * @param packet the packet to send
364 * @param outPort the port to send it out
365 */
366 private void sendTo(Ethernet packet, ConnectPoint outPort) {
367 sendTo(ByteBuffer.wrap(packet.serialize()), outPort);
368 }
369
370 /**
371 * Outputs a packet out a specific port.
372 *
373 * @param packet packet to send
374 * @param outPort port to send it out
375 */
376 private void sendTo(ByteBuffer packet, ConnectPoint outPort) {
377 if (!edgeService.isEdgePoint(outPort)) {
378 // Sanity check to make sure we don't send the packet out an
379 // internal port and create a loop (could happen due to
380 // misconfiguration).
381 return;
382 }
383
384 TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
385 builder.setOutput(outPort.port());
386 packetService.emit(new DefaultOutboundPacket(outPort.deviceId(),
387 builder.build(), packet));
388 }
389
390 /**
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700391 * Builds an NDP reply based on a request.
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700392 *
393 * @param srcIp the IP address to use as the reply source
394 * @param srcMac the MAC address to use as the reply source
395 * @param request the Neighbor Solicitation request we got
396 * @return an Ethernet frame containing the Neighbor Advertisement reply
397 */
398 private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac,
399 Ethernet request) {
400 Ethernet eth = new Ethernet();
401 eth.setDestinationMACAddress(request.getSourceMAC());
402 eth.setSourceMACAddress(srcMac);
403 eth.setEtherType(Ethernet.TYPE_IPV6);
404 eth.setVlanID(request.getVlanID());
405
406 IPv6 requestIp = (IPv6) request.getPayload();
407 IPv6 ipv6 = new IPv6();
408 ipv6.setSourceAddress(srcIp.toOctets());
409 ipv6.setDestinationAddress(requestIp.getSourceAddress());
410 ipv6.setHopLimit((byte) 255);
411
412 ICMP6 icmp6 = new ICMP6();
413 icmp6.setIcmpType(ICMP6.NEIGHBOR_ADVERTISEMENT);
414 icmp6.setIcmpCode((byte) 0);
415
416 NeighborAdvertisement nadv = new NeighborAdvertisement();
417 nadv.setTargetAddress(srcIp.toOctets());
418 nadv.setSolicitedFlag((byte) 1);
419 nadv.setOverrideFlag((byte) 1);
420 nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS,
421 srcMac.toBytes());
422
423 icmp6.setPayload(nadv);
424 ipv6.setPayload(icmp6);
425 eth.setPayload(ipv6);
426 return eth;
427 }
428
429 /**
430 * Stores a neighbour message handler registration.
431 */
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700432 private class HandlerRegistration implements NeighbourHandlerRegistration {
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700433 private final Interface intf;
434 private final NeighbourMessageHandler handler;
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700435 private final ApplicationId appId;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700436
437 /**
438 * Creates a new handler registration.
439 *
440 * @param handler neighbour message handler
441 */
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700442 public HandlerRegistration(NeighbourMessageHandler handler, ApplicationId appId) {
443 this(handler, null, appId);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700444 }
445
446 /**
447 * Creates a new handler registration.
448 *
449 * @param handler neighbour message handler
450 * @param intf interface
451 */
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700452 public HandlerRegistration(NeighbourMessageHandler handler, Interface intf, ApplicationId appId) {
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700453 this.intf = intf;
454 this.handler = handler;
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700455 this.appId = appId;
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700456 }
457
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700458 @Override
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700459 public Interface intf() {
460 return intf;
461 }
462
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700463 @Override
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700464 public NeighbourMessageHandler handler() {
465 return handler;
466 }
467
468 @Override
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700469 public ApplicationId appId() {
470 return appId;
471 }
472
473 @Override
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700474 public boolean equals(Object other) {
475 if (this == other) {
476 return true;
477 }
478
479 if (!(other instanceof HandlerRegistration)) {
480 return false;
481 }
482
483 HandlerRegistration that = (HandlerRegistration) other;
484
485 return Objects.equals(intf, that.intf) &&
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700486 Objects.equals(handler, that.handler) &&
487 Objects.equals(appId, that.appId);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700488 }
489
490 @Override
491 public int hashCode() {
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700492 return Objects.hash(intf, handler, appId);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700493 }
494 }
495
496 /**
497 * Packet processor for incoming packets.
498 */
499 private class InternalPacketProcessor implements PacketProcessor {
500
501 @Override
502 public void process(PacketContext context) {
503 // Stop processing if the packet has been handled, since we
504 // can't do any more to it.
505 if (context.isHandled()) {
506 return;
507 }
508
509 InboundPacket pkt = context.inPacket();
510 Ethernet ethPkt = pkt.parsed();
511 if (ethPkt == null) {
512 return;
513 }
514
515 if (ethPkt.getEtherType() == TYPE_ARP) {
516 // handle ARP packets
517 handlePacket(context);
518 } else if (ethPkt.getEtherType() == TYPE_IPV6) {
519 IPv6 ipv6 = (IPv6) ethPkt.getPayload();
520 if (ipv6.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
521 ICMP6 icmp6 = (ICMP6) ipv6.getPayload();
522 if (icmp6.getIcmpType() == NEIGHBOR_SOLICITATION ||
523 icmp6.getIcmpType() == NEIGHBOR_ADVERTISEMENT) {
524 // handle ICMPv6 solicitations and advertisements (NDP)
525 handlePacket(context);
526 }
527 }
528 }
529 }
530 }
531
532 private class InternalNeighbourMessageActions implements NeighbourMessageActions {
533
534 @Override
535 public void reply(NeighbourMessageContext context, MacAddress targetMac) {
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700536 NeighbourResolutionManager.this.reply(context, targetMac);
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700537 }
538
539 @Override
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700540 public void forward(NeighbourMessageContext context, ConnectPoint outPort) {
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700541 sendTo(context.packet(), outPort);
542 }
543
544 @Override
Jonathan Hart1e393bb2016-09-14 08:51:09 -0700545 public void forward(NeighbourMessageContext context, Interface outIntf) {
Jonathan Hartc4f681c2016-09-09 07:14:25 -0700546 // TODO implement
Jonathan Hart9bdaaec2016-08-22 13:33:45 -0700547 }
548
549 @Override
550 public void flood(NeighbourMessageContext context) {
551 edgeService.getEdgePoints().forEach(connectPoint -> {
552 if (!connectPoint.equals(context.inPort())) {
553 sendTo(context.packet(), connectPoint);
554 }
555 });
556 }
557
558 @Override
559 public void drop(NeighbourMessageContext context) {
560
561 }
562 }
563
564}