Committed by
Gerrit Code Review
Adding ability to synchronize topology clusters' broadcast trees.
Proxy ARP now supports deferred ARP replies until instance learns of the subject host location. Change-Id: Ib3ee97c0812858b5b4972d945e9e6d2bd397d4c5
Showing
8 changed files
with
423 additions
and
43 deletions
1 | +/* | ||
2 | + * Copyright 2015 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 | +package org.onosproject.net.proxyarp; | ||
17 | + | ||
18 | +import org.onosproject.net.ConnectPoint; | ||
19 | +import org.onosproject.net.Host; | ||
20 | + | ||
21 | +import java.nio.ByteBuffer; | ||
22 | + | ||
23 | +/** | ||
24 | + * State distribution mechanism for the proxy ARP service. | ||
25 | + */ | ||
26 | +public interface ProxyArpStore { | ||
27 | + | ||
28 | + /** | ||
29 | + * Forwards an ARP or neighbor solicitation request to its destination. | ||
30 | + * Floods at the edg the request if the destination is not known. | ||
31 | + * | ||
32 | + * @param outPort the port the request was received on | ||
33 | + * @param subject subject host | ||
34 | + * @param packet an ethernet frame containing an ARP or neighbor | ||
35 | + * solicitation request | ||
36 | + */ | ||
37 | + void forward(ConnectPoint outPort, Host subject, ByteBuffer packet); | ||
38 | + | ||
39 | + /** | ||
40 | + * Associates the specified delegate with the store. | ||
41 | + * | ||
42 | + * @param delegate store delegate | ||
43 | + */ | ||
44 | + void setDelegate(ProxyArpStoreDelegate delegate); | ||
45 | +} |
1 | +/* | ||
2 | + * Copyright 2015 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 | +package org.onosproject.net.proxyarp; | ||
17 | + | ||
18 | +import org.onosproject.net.ConnectPoint; | ||
19 | + | ||
20 | +import java.nio.ByteBuffer; | ||
21 | + | ||
22 | +/** | ||
23 | + * Proxy ARP store delegate. | ||
24 | + */ | ||
25 | +public interface ProxyArpStoreDelegate { | ||
26 | + | ||
27 | + /** | ||
28 | + * Emits ARP or neighbour discovery response packet. | ||
29 | + * | ||
30 | + * @param outPort output connection point | ||
31 | + * @param packet packet to emit | ||
32 | + */ | ||
33 | + void emitResponse(ConnectPoint outPort, ByteBuffer packet); | ||
34 | + | ||
35 | +} |
... | @@ -15,6 +15,7 @@ | ... | @@ -15,6 +15,7 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.common; | 16 | package org.onosproject.common; |
17 | 17 | ||
18 | +import com.google.common.base.Function; | ||
18 | import com.google.common.base.Supplier; | 19 | import com.google.common.base.Supplier; |
19 | import com.google.common.base.Suppliers; | 20 | import com.google.common.base.Suppliers; |
20 | import com.google.common.collect.ImmutableMap; | 21 | import com.google.common.collect.ImmutableMap; |
... | @@ -77,17 +78,20 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -77,17 +78,20 @@ public class DefaultTopology extends AbstractModel implements Topology { |
77 | private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters; | 78 | private final Supplier<ImmutableMap<ClusterId, TopologyCluster>> clusters; |
78 | private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints; | 79 | private final Supplier<ImmutableSet<ConnectPoint>> infrastructurePoints; |
79 | private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets; | 80 | private final Supplier<ImmutableSetMultimap<ClusterId, ConnectPoint>> broadcastSets; |
80 | - | 81 | + private final Function<ConnectPoint, Boolean> broadcastFunction; |
81 | private final Supplier<ClusterIndexes> clusterIndexes; | 82 | private final Supplier<ClusterIndexes> clusterIndexes; |
82 | 83 | ||
83 | /** | 84 | /** |
84 | * Creates a topology descriptor attributed to the specified provider. | 85 | * Creates a topology descriptor attributed to the specified provider. |
85 | * | 86 | * |
86 | - * @param providerId identity of the provider | 87 | + * @param providerId identity of the provider |
87 | - * @param description data describing the new topology | 88 | + * @param description data describing the new topology |
89 | + * @param broadcastFunction broadcast point function | ||
88 | */ | 90 | */ |
89 | - public DefaultTopology(ProviderId providerId, GraphDescription description) { | 91 | + public DefaultTopology(ProviderId providerId, GraphDescription description, |
92 | + Function<ConnectPoint, Boolean> broadcastFunction) { | ||
90 | super(providerId); | 93 | super(providerId); |
94 | + this.broadcastFunction = broadcastFunction; | ||
91 | this.time = description.timestamp(); | 95 | this.time = description.timestamp(); |
92 | this.creationTime = description.creationTime(); | 96 | this.creationTime = description.creationTime(); |
93 | 97 | ||
... | @@ -106,6 +110,16 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -106,6 +110,16 @@ public class DefaultTopology extends AbstractModel implements Topology { |
106 | this.computeCost = Math.max(0, System.nanoTime() - time); | 110 | this.computeCost = Math.max(0, System.nanoTime() - time); |
107 | } | 111 | } |
108 | 112 | ||
113 | + /** | ||
114 | + * Creates a topology descriptor attributed to the specified provider. | ||
115 | + * | ||
116 | + * @param providerId identity of the provider | ||
117 | + * @param description data describing the new topology | ||
118 | + */ | ||
119 | + public DefaultTopology(ProviderId providerId, GraphDescription description) { | ||
120 | + this(providerId, description, null); | ||
121 | + } | ||
122 | + | ||
109 | @Override | 123 | @Override |
110 | public long time() { | 124 | public long time() { |
111 | return time; | 125 | return time; |
... | @@ -223,6 +237,10 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -223,6 +237,10 @@ public class DefaultTopology extends AbstractModel implements Topology { |
223 | * @return true if in broadcast set | 237 | * @return true if in broadcast set |
224 | */ | 238 | */ |
225 | public boolean isBroadcastPoint(ConnectPoint connectPoint) { | 239 | public boolean isBroadcastPoint(ConnectPoint connectPoint) { |
240 | + if (broadcastFunction != null) { | ||
241 | + return broadcastFunction.apply(connectPoint); | ||
242 | + } | ||
243 | + | ||
226 | // Any non-infrastructure, i.e. edge points are assumed to be OK. | 244 | // Any non-infrastructure, i.e. edge points are assumed to be OK. |
227 | if (!isInfrastructure(connectPoint)) { | 245 | if (!isInfrastructure(connectPoint)) { |
228 | return true; | 246 | return true; | ... | ... |
... | @@ -36,7 +36,6 @@ import org.onlab.packet.ndp.NeighborSolicitation; | ... | @@ -36,7 +36,6 @@ import org.onlab.packet.ndp.NeighborSolicitation; |
36 | import org.onosproject.core.Permission; | 36 | import org.onosproject.core.Permission; |
37 | import org.onosproject.net.ConnectPoint; | 37 | import org.onosproject.net.ConnectPoint; |
38 | import org.onosproject.net.Host; | 38 | import org.onosproject.net.Host; |
39 | -import org.onosproject.net.HostId; | ||
40 | import org.onosproject.net.device.DeviceService; | 39 | import org.onosproject.net.device.DeviceService; |
41 | import org.onosproject.net.edge.EdgePortService; | 40 | import org.onosproject.net.edge.EdgePortService; |
42 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 41 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
... | @@ -50,6 +49,7 @@ import org.onosproject.net.packet.InboundPacket; | ... | @@ -50,6 +49,7 @@ import org.onosproject.net.packet.InboundPacket; |
50 | import org.onosproject.net.packet.PacketContext; | 49 | import org.onosproject.net.packet.PacketContext; |
51 | import org.onosproject.net.packet.PacketService; | 50 | import org.onosproject.net.packet.PacketService; |
52 | import org.onosproject.net.proxyarp.ProxyArpService; | 51 | import org.onosproject.net.proxyarp.ProxyArpService; |
52 | +import org.onosproject.net.proxyarp.ProxyArpStore; | ||
53 | import org.slf4j.Logger; | 53 | import org.slf4j.Logger; |
54 | 54 | ||
55 | import java.nio.ByteBuffer; | 55 | import java.nio.ByteBuffer; |
... | @@ -59,6 +59,8 @@ import java.util.stream.Collectors; | ... | @@ -59,6 +59,8 @@ import java.util.stream.Collectors; |
59 | 59 | ||
60 | import static com.google.common.base.Preconditions.checkArgument; | 60 | import static com.google.common.base.Preconditions.checkArgument; |
61 | import static com.google.common.base.Preconditions.checkNotNull; | 61 | import static com.google.common.base.Preconditions.checkNotNull; |
62 | +import static org.onlab.packet.VlanId.vlanId; | ||
63 | +import static org.onosproject.net.HostId.hostId; | ||
62 | import static org.onosproject.security.AppGuard.checkPermission; | 64 | import static org.onosproject.security.AppGuard.checkPermission; |
63 | import static org.slf4j.LoggerFactory.getLogger; | 65 | import static org.slf4j.LoggerFactory.getLogger; |
64 | 66 | ||
... | @@ -90,25 +92,29 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -90,25 +92,29 @@ public class ProxyArpManager implements ProxyArpService { |
90 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
91 | protected DeviceService deviceService; | 93 | protected DeviceService deviceService; |
92 | 94 | ||
95 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
96 | + protected ProxyArpStore store; | ||
97 | + | ||
93 | /** | 98 | /** |
94 | * Listens to both device service and link service to determine | 99 | * Listens to both device service and link service to determine |
95 | * whether a port is internal or external. | 100 | * whether a port is internal or external. |
96 | */ | 101 | */ |
97 | @Activate | 102 | @Activate |
98 | public void activate() { | 103 | public void activate() { |
104 | + store.setDelegate(this::sendTo); | ||
99 | log.info("Started"); | 105 | log.info("Started"); |
100 | } | 106 | } |
101 | 107 | ||
102 | 108 | ||
103 | @Deactivate | 109 | @Deactivate |
104 | public void deactivate() { | 110 | public void deactivate() { |
111 | + store.setDelegate(null); | ||
105 | log.info("Stopped"); | 112 | log.info("Stopped"); |
106 | } | 113 | } |
107 | 114 | ||
108 | @Override | 115 | @Override |
109 | public boolean isKnown(IpAddress addr) { | 116 | public boolean isKnown(IpAddress addr) { |
110 | checkPermission(Permission.PACKET_READ); | 117 | checkPermission(Permission.PACKET_READ); |
111 | - | ||
112 | checkNotNull(addr, MAC_ADDR_NULL); | 118 | checkNotNull(addr, MAC_ADDR_NULL); |
113 | Set<Host> hosts = hostService.getHostsByIp(addr); | 119 | Set<Host> hosts = hostService.getHostsByIp(addr); |
114 | return !hosts.isEmpty(); | 120 | return !hosts.isEmpty(); |
... | @@ -117,7 +123,6 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -117,7 +123,6 @@ public class ProxyArpManager implements ProxyArpService { |
117 | @Override | 123 | @Override |
118 | public void reply(Ethernet eth, ConnectPoint inPort) { | 124 | public void reply(Ethernet eth, ConnectPoint inPort) { |
119 | checkPermission(Permission.PACKET_WRITE); | 125 | checkPermission(Permission.PACKET_WRITE); |
120 | - | ||
121 | checkNotNull(eth, REQUEST_NULL); | 126 | checkNotNull(eth, REQUEST_NULL); |
122 | 127 | ||
123 | if (eth.getEtherType() == Ethernet.TYPE_ARP) { | 128 | if (eth.getEtherType() == Ethernet.TYPE_ARP) { |
... | @@ -133,7 +138,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -133,7 +138,7 @@ public class ProxyArpManager implements ProxyArpService { |
133 | checkNotNull(inPort); | 138 | checkNotNull(inPort); |
134 | Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress()); | 139 | Ip4Address targetAddress = Ip4Address.valueOf(arp.getTargetProtocolAddress()); |
135 | 140 | ||
136 | - VlanId vlan = VlanId.vlanId(eth.getVlanID()); | 141 | + VlanId vlan = vlanId(eth.getVlanID()); |
137 | 142 | ||
138 | if (isOutsidePort(inPort)) { | 143 | if (isOutsidePort(inPort)) { |
139 | // If the request came from outside the network, only reply if it was | 144 | // If the request came from outside the network, only reply if it was |
... | @@ -158,8 +163,8 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -158,8 +163,8 @@ public class ProxyArpManager implements ProxyArpService { |
158 | Set<Host> hosts = hostService.getHostsByIp(targetAddress); | 163 | Set<Host> hosts = hostService.getHostsByIp(targetAddress); |
159 | 164 | ||
160 | Host dst = null; | 165 | Host dst = null; |
161 | - Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), | 166 | + Host src = hostService.getHost(hostId(eth.getSourceMAC(), |
162 | - VlanId.vlanId(eth.getVlanID()))); | 167 | + vlanId(eth.getVlanID()))); |
163 | 168 | ||
164 | for (Host host : hosts) { | 169 | for (Host host : hosts) { |
165 | if (host.vlan().equals(vlan)) { | 170 | if (host.vlan().equals(vlan)) { |
... | @@ -202,17 +207,15 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -202,17 +207,15 @@ public class ProxyArpManager implements ProxyArpService { |
202 | // Flood the request on all ports except the incoming port. | 207 | // Flood the request on all ports except the incoming port. |
203 | // | 208 | // |
204 | flood(eth, inPort); | 209 | flood(eth, inPort); |
205 | - return; | ||
206 | } | 210 | } |
207 | 211 | ||
208 | private void replyNdp(Ethernet eth, ConnectPoint inPort) { | 212 | private void replyNdp(Ethernet eth, ConnectPoint inPort) { |
209 | - | ||
210 | IPv6 ipv6 = (IPv6) eth.getPayload(); | 213 | IPv6 ipv6 = (IPv6) eth.getPayload(); |
211 | ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); | 214 | ICMP6 icmpv6 = (ICMP6) ipv6.getPayload(); |
212 | NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); | 215 | NeighborSolicitation nsol = (NeighborSolicitation) icmpv6.getPayload(); |
213 | Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress()); | 216 | Ip6Address targetAddress = Ip6Address.valueOf(nsol.getTargetAddress()); |
214 | 217 | ||
215 | - VlanId vlan = VlanId.vlanId(eth.getVlanID()); | 218 | + VlanId vlan = vlanId(eth.getVlanID()); |
216 | 219 | ||
217 | // If the request came from outside the network, only reply if it was | 220 | // If the request came from outside the network, only reply if it was |
218 | // for one of our external addresses. | 221 | // for one of our external addresses. |
... | @@ -259,8 +262,8 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -259,8 +262,8 @@ public class ProxyArpManager implements ProxyArpService { |
259 | Set<Host> hosts = hostService.getHostsByIp(targetAddress); | 262 | Set<Host> hosts = hostService.getHostsByIp(targetAddress); |
260 | 263 | ||
261 | Host dst = null; | 264 | Host dst = null; |
262 | - Host src = hostService.getHost(HostId.hostId(eth.getSourceMAC(), | 265 | + Host src = hostService.getHost(hostId(eth.getSourceMAC(), |
263 | - VlanId.vlanId(eth.getVlanID()))); | 266 | + vlanId(eth.getVlanID()))); |
264 | 267 | ||
265 | for (Host host : hosts) { | 268 | for (Host host : hosts) { |
266 | if (host.vlan().equals(vlan)) { | 269 | if (host.vlan().equals(vlan)) { |
... | @@ -293,6 +296,10 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -293,6 +296,10 @@ public class ProxyArpManager implements ProxyArpService { |
293 | * @param outPort the port to send it out | 296 | * @param outPort the port to send it out |
294 | */ | 297 | */ |
295 | private void sendTo(Ethernet packet, ConnectPoint outPort) { | 298 | private void sendTo(Ethernet packet, ConnectPoint outPort) { |
299 | + sendTo(outPort, ByteBuffer.wrap(packet.serialize())); | ||
300 | + } | ||
301 | + | ||
302 | + private void sendTo(ConnectPoint outPort, ByteBuffer packet) { | ||
296 | if (!edgeService.isEdgePoint(outPort)) { | 303 | if (!edgeService.isEdgePoint(outPort)) { |
297 | // Sanity check to make sure we don't send the packet out an | 304 | // Sanity check to make sure we don't send the packet out an |
298 | // internal port and create a loop (could happen due to | 305 | // internal port and create a loop (could happen due to |
... | @@ -303,7 +310,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -303,7 +310,7 @@ public class ProxyArpManager implements ProxyArpService { |
303 | TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); | 310 | TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); |
304 | builder.setOutput(outPort.port()); | 311 | builder.setOutput(outPort.port()); |
305 | packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), | 312 | packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), |
306 | - builder.build(), ByteBuffer.wrap(packet.serialize()))); | 313 | + builder.build(), packet)); |
307 | } | 314 | } |
308 | 315 | ||
309 | /** | 316 | /** |
... | @@ -329,31 +336,25 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -329,31 +336,25 @@ public class ProxyArpManager implements ProxyArpService { |
329 | * @return true if the port is an outside-facing port, otherwise false | 336 | * @return true if the port is an outside-facing port, otherwise false |
330 | */ | 337 | */ |
331 | private boolean isOutsidePort(ConnectPoint port) { | 338 | private boolean isOutsidePort(ConnectPoint port) { |
332 | - // | 339 | + // TODO: Is this sufficient to identify outside-facing ports: just having IP addresses on a port? |
333 | - // TODO: Is this sufficient to identify outside-facing ports: just | ||
334 | - // having IP addresses on a port? | ||
335 | - // | ||
336 | return !hostService.getAddressBindingsForPort(port).isEmpty(); | 340 | return !hostService.getAddressBindingsForPort(port).isEmpty(); |
337 | } | 341 | } |
338 | 342 | ||
339 | @Override | 343 | @Override |
340 | public void forward(Ethernet eth, ConnectPoint inPort) { | 344 | public void forward(Ethernet eth, ConnectPoint inPort) { |
341 | checkPermission(Permission.PACKET_WRITE); | 345 | checkPermission(Permission.PACKET_WRITE); |
342 | - | ||
343 | checkNotNull(eth, REQUEST_NULL); | 346 | checkNotNull(eth, REQUEST_NULL); |
344 | 347 | ||
345 | - Host h = hostService.getHost(HostId.hostId(eth.getDestinationMAC(), | 348 | + Host h = hostService.getHost(hostId(eth.getDestinationMAC(), |
346 | - VlanId.vlanId(eth.getVlanID()))); | 349 | + vlanId(eth.getVlanID()))); |
347 | 350 | ||
348 | if (h == null) { | 351 | if (h == null) { |
349 | flood(eth, inPort); | 352 | flood(eth, inPort); |
350 | } else { | 353 | } else { |
351 | - TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); | 354 | + Host subject = hostService.getHost(hostId(eth.getSourceMAC(), |
352 | - builder.setOutput(h.location().port()); | 355 | + vlanId(eth.getVlanID()))); |
353 | - packetService.emit(new DefaultOutboundPacket(h.location().deviceId(), | 356 | + store.forward(h.location(), subject, ByteBuffer.wrap(eth.serialize())); |
354 | - builder.build(), ByteBuffer.wrap(eth.serialize()))); | ||
355 | } | 357 | } |
356 | - | ||
357 | } | 358 | } |
358 | 359 | ||
359 | @Override | 360 | @Override |
... | @@ -424,7 +425,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -424,7 +425,7 @@ public class ProxyArpManager implements ProxyArpService { |
424 | builder = DefaultTrafficTreatment.builder(); | 425 | builder = DefaultTrafficTreatment.builder(); |
425 | builder.setOutput(connectPoint.port()); | 426 | builder.setOutput(connectPoint.port()); |
426 | packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(), | 427 | packetService.emit(new DefaultOutboundPacket(connectPoint.deviceId(), |
427 | - builder.build(), buf)); | 428 | + builder.build(), buf)); |
428 | } | 429 | } |
429 | 430 | ||
430 | } | 431 | } |
... | @@ -439,7 +440,6 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -439,7 +440,6 @@ public class ProxyArpManager implements ProxyArpService { |
439 | */ | 440 | */ |
440 | private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac, | 441 | private Ethernet buildNdpReply(Ip6Address srcIp, MacAddress srcMac, |
441 | Ethernet request) { | 442 | Ethernet request) { |
442 | - | ||
443 | Ethernet eth = new Ethernet(); | 443 | Ethernet eth = new Ethernet(); |
444 | eth.setDestinationMACAddress(request.getSourceMAC()); | 444 | eth.setDestinationMACAddress(request.getSourceMAC()); |
445 | eth.setSourceMACAddress(srcMac); | 445 | eth.setSourceMACAddress(srcMac); |
... | @@ -461,7 +461,7 @@ public class ProxyArpManager implements ProxyArpService { | ... | @@ -461,7 +461,7 @@ public class ProxyArpManager implements ProxyArpService { |
461 | nadv.setSolicitedFlag((byte) 1); | 461 | nadv.setSolicitedFlag((byte) 1); |
462 | nadv.setOverrideFlag((byte) 1); | 462 | nadv.setOverrideFlag((byte) 1); |
463 | nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, | 463 | nadv.addOption(NeighborDiscoveryOptions.TYPE_TARGET_LL_ADDRESS, |
464 | - srcMac.toBytes()); | 464 | + srcMac.toBytes()); |
465 | 465 | ||
466 | icmp6.setPayload(nadv); | 466 | icmp6.setPayload(nadv); |
467 | ipv6.setPayload(icmp6); | 467 | ipv6.setPayload(icmp6); | ... | ... |
... | @@ -38,6 +38,8 @@ import org.onosproject.net.PortNumber; | ... | @@ -38,6 +38,8 @@ import org.onosproject.net.PortNumber; |
38 | import org.onosproject.net.device.DeviceListener; | 38 | import org.onosproject.net.device.DeviceListener; |
39 | import org.onosproject.net.device.DeviceService; | 39 | import org.onosproject.net.device.DeviceService; |
40 | import org.onosproject.net.edgeservice.impl.EdgeManager; | 40 | import org.onosproject.net.edgeservice.impl.EdgeManager; |
41 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
42 | +import org.onosproject.net.flow.TrafficTreatment; | ||
41 | import org.onosproject.net.flow.instructions.Instruction; | 43 | import org.onosproject.net.flow.instructions.Instruction; |
42 | import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; | 44 | import org.onosproject.net.flow.instructions.Instructions.OutputInstruction; |
43 | import org.onosproject.net.host.HostService; | 45 | import org.onosproject.net.host.HostService; |
... | @@ -45,24 +47,22 @@ import org.onosproject.net.host.InterfaceIpAddress; | ... | @@ -45,24 +47,22 @@ import org.onosproject.net.host.InterfaceIpAddress; |
45 | import org.onosproject.net.host.PortAddresses; | 47 | import org.onosproject.net.host.PortAddresses; |
46 | import org.onosproject.net.link.LinkListener; | 48 | import org.onosproject.net.link.LinkListener; |
47 | import org.onosproject.net.link.LinkService; | 49 | import org.onosproject.net.link.LinkService; |
50 | +import org.onosproject.net.packet.DefaultOutboundPacket; | ||
48 | import org.onosproject.net.packet.OutboundPacket; | 51 | import org.onosproject.net.packet.OutboundPacket; |
49 | import org.onosproject.net.packet.PacketServiceAdapter; | 52 | import org.onosproject.net.packet.PacketServiceAdapter; |
50 | import org.onosproject.net.provider.ProviderId; | 53 | import org.onosproject.net.provider.ProviderId; |
54 | +import org.onosproject.net.proxyarp.ProxyArpStore; | ||
55 | +import org.onosproject.net.proxyarp.ProxyArpStoreDelegate; | ||
51 | 56 | ||
57 | +import java.nio.ByteBuffer; | ||
52 | import java.util.ArrayList; | 58 | import java.util.ArrayList; |
53 | import java.util.Collections; | 59 | import java.util.Collections; |
54 | import java.util.Comparator; | 60 | import java.util.Comparator; |
55 | import java.util.List; | 61 | import java.util.List; |
56 | import java.util.Set; | 62 | import java.util.Set; |
57 | 63 | ||
58 | -import static org.easymock.EasyMock.anyObject; | 64 | +import static org.easymock.EasyMock.*; |
59 | -import static org.easymock.EasyMock.createMock; | 65 | +import static org.junit.Assert.*; |
60 | -import static org.easymock.EasyMock.expect; | ||
61 | -import static org.easymock.EasyMock.replay; | ||
62 | -import static org.junit.Assert.assertArrayEquals; | ||
63 | -import static org.junit.Assert.assertEquals; | ||
64 | -import static org.junit.Assert.assertFalse; | ||
65 | -import static org.junit.Assert.assertTrue; | ||
66 | 66 | ||
67 | /** | 67 | /** |
68 | * Tests for the {@link ProxyArpManager} class. | 68 | * Tests for the {@link ProxyArpManager} class. |
... | @@ -110,6 +110,7 @@ public class ProxyArpManagerTest { | ... | @@ -110,6 +110,7 @@ public class ProxyArpManagerTest { |
110 | proxyArp = new ProxyArpManager(); | 110 | proxyArp = new ProxyArpManager(); |
111 | packetService = new TestPacketService(); | 111 | packetService = new TestPacketService(); |
112 | proxyArp.packetService = packetService; | 112 | proxyArp.packetService = packetService; |
113 | + proxyArp.store = new TestProxyArpStoreAdapter(); | ||
113 | 114 | ||
114 | proxyArp.edgeService = new TestEdgePortService(); | 115 | proxyArp.edgeService = new TestEdgePortService(); |
115 | 116 | ||
... | @@ -455,8 +456,11 @@ public class ProxyArpManagerTest { | ... | @@ -455,8 +456,11 @@ public class ProxyArpManagerTest { |
455 | public void testForwardToHost() { | 456 | public void testForwardToHost() { |
456 | Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, | 457 | Host host1 = new DefaultHost(PID, HID1, MAC1, VLAN1, LOC1, |
457 | Collections.singleton(IP1)); | 458 | Collections.singleton(IP1)); |
459 | + Host host2 = new DefaultHost(PID, HID2, MAC2, VLAN1, LOC2, | ||
460 | + Collections.singleton(IP2)); | ||
458 | 461 | ||
459 | expect(hostService.getHost(HID1)).andReturn(host1); | 462 | expect(hostService.getHost(HID1)).andReturn(host1); |
463 | + expect(hostService.getHost(HID2)).andReturn(host2); | ||
460 | replay(hostService); | 464 | replay(hostService); |
461 | 465 | ||
462 | Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1); | 466 | Ethernet arpRequest = buildArp(ARP.OP_REPLY, MAC2, MAC1, IP2, IP1); |
... | @@ -625,4 +629,16 @@ public class ProxyArpManagerTest { | ... | @@ -625,4 +629,16 @@ public class ProxyArpManagerTest { |
625 | return getEdgePointsNoArg; | 629 | return getEdgePointsNoArg; |
626 | } | 630 | } |
627 | } | 631 | } |
632 | + | ||
633 | + private class TestProxyArpStoreAdapter implements ProxyArpStore { | ||
634 | + @Override | ||
635 | + public void forward(ConnectPoint outPort, Host subject, ByteBuffer packet) { | ||
636 | + TrafficTreatment tt = DefaultTrafficTreatment.builder().setOutput(outPort.port()).build(); | ||
637 | + packetService.emit(new DefaultOutboundPacket(outPort.deviceId(), tt, packet)); | ||
638 | + } | ||
639 | + | ||
640 | + @Override | ||
641 | + public void setDelegate(ProxyArpStoreDelegate delegate) { | ||
642 | + } | ||
643 | + } | ||
628 | } | 644 | } | ... | ... |
... | @@ -4,6 +4,7 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -4,6 +4,7 @@ import static com.google.common.base.Preconditions.checkNotNull; |
4 | import static org.onosproject.net.DefaultAnnotations.merge; | 4 | import static org.onosproject.net.DefaultAnnotations.merge; |
5 | import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; | 5 | import static org.onosproject.net.host.HostEvent.Type.HOST_ADDED; |
6 | import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED; | 6 | import static org.onosproject.net.host.HostEvent.Type.HOST_REMOVED; |
7 | +import static org.onosproject.net.host.HostEvent.Type.HOST_UPDATED; | ||
7 | import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; | 8 | import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.PUT; |
8 | import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; | 9 | import static org.onosproject.store.service.EventuallyConsistentMapEvent.Type.REMOVE; |
9 | import static org.slf4j.LoggerFactory.getLogger; | 10 | import static org.slf4j.LoggerFactory.getLogger; |
... | @@ -246,14 +247,17 @@ public class ECHostStore | ... | @@ -246,14 +247,17 @@ public class ECHostStore |
246 | } | 247 | } |
247 | 248 | ||
248 | private class HostLocationTracker implements EventuallyConsistentMapListener<HostId, DefaultHost> { | 249 | private class HostLocationTracker implements EventuallyConsistentMapListener<HostId, DefaultHost> { |
249 | - | ||
250 | @Override | 250 | @Override |
251 | public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) { | 251 | public void event(EventuallyConsistentMapEvent<HostId, DefaultHost> event) { |
252 | DefaultHost host = checkNotNull(event.value()); | 252 | DefaultHost host = checkNotNull(event.value()); |
253 | if (event.type() == PUT) { | 253 | if (event.type() == PUT) { |
254 | - locations.put(host.location(), host); | 254 | + boolean isNew = locations.put(host.location(), host); |
255 | + notifyDelegate(new HostEvent(isNew ? HOST_ADDED : HOST_UPDATED, host)); | ||
255 | } else if (event.type() == REMOVE) { | 256 | } else if (event.type() == REMOVE) { |
256 | - locations.remove(host.location(), host); | 257 | + if (locations.remove(host.location(), host)) { |
258 | + notifyDelegate(new HostEvent(HOST_REMOVED, host)); | ||
259 | + } | ||
260 | + | ||
257 | } | 261 | } |
258 | } | 262 | } |
259 | } | 263 | } | ... | ... |
core/store/dist/src/main/java/org/onosproject/store/proxyarp/impl/DistributedProxyArpStore.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 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 | +package org.onosproject.store.proxyarp.impl; | ||
17 | + | ||
18 | +import com.google.common.collect.Maps; | ||
19 | +import org.apache.felix.scr.annotations.Activate; | ||
20 | +import org.apache.felix.scr.annotations.Component; | ||
21 | +import org.apache.felix.scr.annotations.Deactivate; | ||
22 | +import org.apache.felix.scr.annotations.Reference; | ||
23 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
24 | +import org.apache.felix.scr.annotations.Service; | ||
25 | +import org.onlab.util.KryoNamespace; | ||
26 | +import org.onosproject.cluster.ClusterService; | ||
27 | +import org.onosproject.cluster.NodeId; | ||
28 | +import org.onosproject.mastership.MastershipService; | ||
29 | +import org.onosproject.net.ConnectPoint; | ||
30 | +import org.onosproject.net.Host; | ||
31 | +import org.onosproject.net.HostId; | ||
32 | +import org.onosproject.net.host.HostEvent; | ||
33 | +import org.onosproject.net.host.HostListener; | ||
34 | +import org.onosproject.net.host.HostService; | ||
35 | +import org.onosproject.net.proxyarp.ProxyArpStore; | ||
36 | +import org.onosproject.net.proxyarp.ProxyArpStoreDelegate; | ||
37 | +import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | ||
38 | +import org.onosproject.store.cluster.messaging.MessageSubject; | ||
39 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
40 | +import org.onosproject.store.serializers.KryoSerializer; | ||
41 | +import org.slf4j.Logger; | ||
42 | +import org.slf4j.LoggerFactory; | ||
43 | + | ||
44 | +import java.nio.ByteBuffer; | ||
45 | +import java.util.Map; | ||
46 | +import java.util.concurrent.ExecutorService; | ||
47 | + | ||
48 | +import static org.onlab.util.BoundedThreadPool.newFixedThreadPool; | ||
49 | +import static org.onlab.util.Tools.groupedThreads; | ||
50 | + | ||
51 | +/** | ||
52 | + * Implementation of proxy ARP distribution mechanism. | ||
53 | + */ | ||
54 | +@Component(immediate = true) | ||
55 | +@Service | ||
56 | +public class DistributedProxyArpStore implements ProxyArpStore { | ||
57 | + | ||
58 | + private Logger log = LoggerFactory.getLogger(getClass()); | ||
59 | + | ||
60 | + private static final MessageSubject ARP_RESPONSE_MESSAGE = | ||
61 | + new MessageSubject("onos-arp-response"); | ||
62 | + | ||
63 | + protected final KryoSerializer serializer = new KryoSerializer() { | ||
64 | + @Override | ||
65 | + protected void setupKryoPool() { | ||
66 | + serializerPool = KryoNamespace.newBuilder() | ||
67 | + .register(KryoNamespaces.API) | ||
68 | + .register(ArpResponseMessage.class) | ||
69 | + .register(ByteBuffer.class) | ||
70 | + .build(); | ||
71 | + } | ||
72 | + }; | ||
73 | + | ||
74 | + private ProxyArpStoreDelegate delegate; | ||
75 | + | ||
76 | + private Map<HostId, ArpResponseMessage> pendingMessages = Maps.newConcurrentMap(); | ||
77 | + | ||
78 | + private ExecutorService executor = | ||
79 | + newFixedThreadPool(4, groupedThreads("onos/arp", "sender-%d")); | ||
80 | + | ||
81 | + private NodeId localNodeId; | ||
82 | + | ||
83 | + private HostListener hostListener = new InternalHostListener(); | ||
84 | + | ||
85 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
86 | + protected MastershipService mastershipService; | ||
87 | + | ||
88 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
89 | + protected ClusterService clusterService; | ||
90 | + | ||
91 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
92 | + protected ClusterCommunicationService commService; | ||
93 | + | ||
94 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
95 | + protected HostService hostService; | ||
96 | + | ||
97 | + | ||
98 | + @Activate | ||
99 | + protected void activate() { | ||
100 | + localNodeId = clusterService.getLocalNode().id(); | ||
101 | + hostService.addListener(hostListener); | ||
102 | + commService.addSubscriber(ARP_RESPONSE_MESSAGE, serializer::decode, | ||
103 | + this::processArpResponse, executor); | ||
104 | + log.info("Started"); | ||
105 | + } | ||
106 | + | ||
107 | + @Deactivate | ||
108 | + protected void deactivate() { | ||
109 | + commService.removeSubscriber(ARP_RESPONSE_MESSAGE); | ||
110 | + hostService.removeListener(hostListener); | ||
111 | + log.info("Stopped"); | ||
112 | + } | ||
113 | + | ||
114 | + @Override | ||
115 | + public void forward(ConnectPoint outPort, Host subject, ByteBuffer packet) { | ||
116 | + NodeId nodeId = mastershipService.getMasterFor(outPort.deviceId()); | ||
117 | + if (nodeId.equals(localNodeId)) { | ||
118 | + if (delegate != null) { | ||
119 | + delegate.emitResponse(outPort, packet); | ||
120 | + } | ||
121 | + } else { | ||
122 | + log.info("Forwarding ARP response from {} to {}", subject.id(), outPort); | ||
123 | + commService.unicast(new ArpResponseMessage(outPort, subject, packet.array()), | ||
124 | + ARP_RESPONSE_MESSAGE, serializer::encode, nodeId); | ||
125 | + } | ||
126 | + } | ||
127 | + | ||
128 | + @Override | ||
129 | + public void setDelegate(ProxyArpStoreDelegate delegate) { | ||
130 | + this.delegate = delegate; | ||
131 | + } | ||
132 | + | ||
133 | + // Processes the incoming ARP response message. | ||
134 | + private void processArpResponse(ArpResponseMessage msg) { | ||
135 | + pendingMessages.put(msg.subject.id(), msg); | ||
136 | + if (hostService.getHost(msg.subject.id()) != null) { | ||
137 | + checkPendingArps(msg.subject.id()); | ||
138 | + } | ||
139 | + // FIXME: figure out pruning so stuff does not build up | ||
140 | + } | ||
141 | + | ||
142 | + // Checks for pending ARP response message for the specified host. | ||
143 | + // If one exists, emit response via delegate. | ||
144 | + private void checkPendingArps(HostId id) { | ||
145 | + ArpResponseMessage msg = pendingMessages.remove(id); | ||
146 | + if (msg != null && delegate != null) { | ||
147 | + log.info("Emitting ARP response from {} to {}", id, msg.outPort); | ||
148 | + delegate.emitResponse(msg.outPort, ByteBuffer.wrap(msg.packet)); | ||
149 | + } | ||
150 | + } | ||
151 | + | ||
152 | + // Message carrying an ARP response. | ||
153 | + private static class ArpResponseMessage { | ||
154 | + private ConnectPoint outPort; | ||
155 | + private Host subject; | ||
156 | + private byte[] packet; | ||
157 | + | ||
158 | + public ArpResponseMessage(ConnectPoint outPort, Host subject, byte[] packet) { | ||
159 | + this.outPort = outPort; | ||
160 | + this.subject = subject; | ||
161 | + this.packet = packet; | ||
162 | + } | ||
163 | + | ||
164 | + private ArpResponseMessage() { | ||
165 | + } | ||
166 | + } | ||
167 | + | ||
168 | + private class InternalHostListener implements HostListener { | ||
169 | + @Override | ||
170 | + public void event(HostEvent event) { | ||
171 | + checkPendingArps(event.subject().id()); | ||
172 | + } | ||
173 | + } | ||
174 | +} |
... | @@ -16,19 +16,25 @@ | ... | @@ -16,19 +16,25 @@ |
16 | package org.onosproject.store.topology.impl; | 16 | package org.onosproject.store.topology.impl; |
17 | 17 | ||
18 | import static com.google.common.base.Preconditions.checkArgument; | 18 | import static com.google.common.base.Preconditions.checkArgument; |
19 | +import static org.onlab.util.Tools.isNullOrEmpty; | ||
19 | import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; | 20 | import static org.onosproject.net.topology.TopologyEvent.Type.TOPOLOGY_CHANGED; |
20 | import static org.slf4j.LoggerFactory.getLogger; | 21 | import static org.slf4j.LoggerFactory.getLogger; |
21 | 22 | ||
22 | import java.util.Collections; | 23 | import java.util.Collections; |
23 | import java.util.List; | 24 | import java.util.List; |
24 | import java.util.Set; | 25 | import java.util.Set; |
26 | +import java.util.stream.Collectors; | ||
25 | 27 | ||
26 | import org.apache.felix.scr.annotations.Activate; | 28 | import org.apache.felix.scr.annotations.Activate; |
27 | import org.apache.felix.scr.annotations.Component; | 29 | import org.apache.felix.scr.annotations.Component; |
28 | import org.apache.felix.scr.annotations.Deactivate; | 30 | import org.apache.felix.scr.annotations.Deactivate; |
31 | +import org.apache.felix.scr.annotations.Reference; | ||
32 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
29 | import org.apache.felix.scr.annotations.Service; | 33 | import org.apache.felix.scr.annotations.Service; |
34 | +import org.onlab.util.KryoNamespace; | ||
30 | import org.onosproject.common.DefaultTopology; | 35 | import org.onosproject.common.DefaultTopology; |
31 | import org.onosproject.event.Event; | 36 | import org.onosproject.event.Event; |
37 | +import org.onosproject.mastership.MastershipService; | ||
32 | import org.onosproject.net.ConnectPoint; | 38 | import org.onosproject.net.ConnectPoint; |
33 | import org.onosproject.net.Device; | 39 | import org.onosproject.net.Device; |
34 | import org.onosproject.net.DeviceId; | 40 | import org.onosproject.net.DeviceId; |
... | @@ -46,6 +52,12 @@ import org.onosproject.net.topology.TopologyGraph; | ... | @@ -46,6 +52,12 @@ import org.onosproject.net.topology.TopologyGraph; |
46 | import org.onosproject.net.topology.TopologyStore; | 52 | import org.onosproject.net.topology.TopologyStore; |
47 | import org.onosproject.net.topology.TopologyStoreDelegate; | 53 | import org.onosproject.net.topology.TopologyStoreDelegate; |
48 | import org.onosproject.store.AbstractStore; | 54 | import org.onosproject.store.AbstractStore; |
55 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
56 | +import org.onosproject.store.service.EventuallyConsistentMap; | ||
57 | +import org.onosproject.store.service.EventuallyConsistentMapEvent; | ||
58 | +import org.onosproject.store.service.EventuallyConsistentMapListener; | ||
59 | +import org.onosproject.store.service.LogicalClockService; | ||
60 | +import org.onosproject.store.service.StorageService; | ||
49 | import org.slf4j.Logger; | 61 | import org.slf4j.Logger; |
50 | 62 | ||
51 | /** | 63 | /** |
... | @@ -69,13 +81,41 @@ public class DistributedTopologyStore | ... | @@ -69,13 +81,41 @@ public class DistributedTopologyStore |
69 | Collections.<Device>emptyList(), | 81 | Collections.<Device>emptyList(), |
70 | Collections.<Link>emptyList())); | 82 | Collections.<Link>emptyList())); |
71 | 83 | ||
84 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
85 | + protected StorageService storageService; | ||
86 | + | ||
87 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
88 | + protected LogicalClockService clockService; | ||
89 | + | ||
90 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
91 | + protected MastershipService mastershipService; | ||
92 | + | ||
93 | + // Cluster root to broadcast points bindings to allow convergence to | ||
94 | + // a shared broadcast tree; node that is the master of the cluster root | ||
95 | + // is the primary. | ||
96 | + private EventuallyConsistentMap<DeviceId, Set<ConnectPoint>> broadcastPoints; | ||
97 | + | ||
98 | + private EventuallyConsistentMapListener<DeviceId, Set<ConnectPoint>> listener = | ||
99 | + new InternalBroadcastPointListener(); | ||
100 | + | ||
72 | @Activate | 101 | @Activate |
73 | public void activate() { | 102 | public void activate() { |
103 | + KryoNamespace.Builder hostSerializer = KryoNamespace.newBuilder() | ||
104 | + .register(KryoNamespaces.API); | ||
105 | + | ||
106 | + broadcastPoints = storageService.<DeviceId, Set<ConnectPoint>>eventuallyConsistentMapBuilder() | ||
107 | + .withName("onos-broadcast-trees") | ||
108 | + .withSerializer(hostSerializer) | ||
109 | + .withTimestampProvider((k, v) -> clockService.getTimestamp()) | ||
110 | + .build(); | ||
111 | + broadcastPoints.addListener(listener); | ||
74 | log.info("Started"); | 112 | log.info("Started"); |
75 | } | 113 | } |
76 | 114 | ||
77 | @Deactivate | 115 | @Deactivate |
78 | public void deactivate() { | 116 | public void deactivate() { |
117 | + broadcastPoints.removeListener(listener); | ||
118 | + broadcastPoints.destroy(); | ||
79 | log.info("Stopped"); | 119 | log.info("Stopped"); |
80 | } | 120 | } |
81 | 121 | ||
... | @@ -136,6 +176,22 @@ public class DistributedTopologyStore | ... | @@ -136,6 +176,22 @@ public class DistributedTopologyStore |
136 | return defaultTopology(topology).isBroadcastPoint(connectPoint); | 176 | return defaultTopology(topology).isBroadcastPoint(connectPoint); |
137 | } | 177 | } |
138 | 178 | ||
179 | + private boolean isBroadcastPoint(ConnectPoint connectPoint) { | ||
180 | + // Any non-infrastructure, i.e. edge points are assumed to be OK. | ||
181 | + if (!current.isInfrastructure(connectPoint)) { | ||
182 | + return true; | ||
183 | + } | ||
184 | + | ||
185 | + // Find the cluster to which the device belongs. | ||
186 | + TopologyCluster cluster = current.getCluster(connectPoint.deviceId()); | ||
187 | + checkArgument(cluster != null, "No cluster found for device %s", connectPoint.deviceId()); | ||
188 | + | ||
189 | + // If the broadcast set is null or empty, or if the point explicitly | ||
190 | + // belongs to it, return true; | ||
191 | + Set<ConnectPoint> points = broadcastPoints.get(cluster.root().deviceId()); | ||
192 | + return isNullOrEmpty(points) || points.contains(connectPoint); | ||
193 | + } | ||
194 | + | ||
139 | @Override | 195 | @Override |
140 | public TopologyEvent updateTopology(ProviderId providerId, | 196 | public TopologyEvent updateTopology(ProviderId providerId, |
141 | GraphDescription graphDescription, | 197 | GraphDescription graphDescription, |
... | @@ -147,7 +203,9 @@ public class DistributedTopologyStore | ... | @@ -147,7 +203,9 @@ public class DistributedTopologyStore |
147 | } | 203 | } |
148 | 204 | ||
149 | // Have the default topology construct self from the description data. | 205 | // Have the default topology construct self from the description data. |
150 | - DefaultTopology newTopology = new DefaultTopology(providerId, graphDescription); | 206 | + DefaultTopology newTopology = |
207 | + new DefaultTopology(providerId, graphDescription, this::isBroadcastPoint); | ||
208 | + updateBroadcastPoints(newTopology); | ||
151 | 209 | ||
152 | // Promote the new topology to current and return a ready-to-send event. | 210 | // Promote the new topology to current and return a ready-to-send event. |
153 | synchronized (this) { | 211 | synchronized (this) { |
... | @@ -156,6 +214,24 @@ public class DistributedTopologyStore | ... | @@ -156,6 +214,24 @@ public class DistributedTopologyStore |
156 | } | 214 | } |
157 | } | 215 | } |
158 | 216 | ||
217 | + private void updateBroadcastPoints(DefaultTopology topology) { | ||
218 | + // Remove any broadcast trees rooted by devices for which we are master. | ||
219 | + Set<DeviceId> toRemove = broadcastPoints.keySet().stream() | ||
220 | + .filter(mastershipService::isLocalMaster) | ||
221 | + .collect(Collectors.toSet()); | ||
222 | + | ||
223 | + // Update the broadcast trees rooted by devices for which we are master. | ||
224 | + topology.getClusters().forEach(c -> { | ||
225 | + toRemove.remove(c.root().deviceId()); | ||
226 | + if (mastershipService.isLocalMaster(c.root().deviceId())) { | ||
227 | + broadcastPoints.put(c.root().deviceId(), | ||
228 | + topology.broadcastPoints(c.id())); | ||
229 | + } | ||
230 | + }); | ||
231 | + | ||
232 | + toRemove.forEach(broadcastPoints::remove); | ||
233 | + } | ||
234 | + | ||
159 | // Validates the specified topology and returns it as a default | 235 | // Validates the specified topology and returns it as a default |
160 | private DefaultTopology defaultTopology(Topology topology) { | 236 | private DefaultTopology defaultTopology(Topology topology) { |
161 | checkArgument(topology instanceof DefaultTopology, | 237 | checkArgument(topology instanceof DefaultTopology, |
... | @@ -163,4 +239,16 @@ public class DistributedTopologyStore | ... | @@ -163,4 +239,16 @@ public class DistributedTopologyStore |
163 | return (DefaultTopology) topology; | 239 | return (DefaultTopology) topology; |
164 | } | 240 | } |
165 | 241 | ||
242 | + private class InternalBroadcastPointListener | ||
243 | + implements EventuallyConsistentMapListener<DeviceId, Set<ConnectPoint>> { | ||
244 | + @Override | ||
245 | + public void event(EventuallyConsistentMapEvent<DeviceId, Set<ConnectPoint>> event) { | ||
246 | + if (event.type() == EventuallyConsistentMapEvent.Type.PUT) { | ||
247 | + if (!event.value().isEmpty()) { | ||
248 | + log.info("Cluster rooted at {} has {} broadcast-points; #{}", | ||
249 | + event.key(), event.value().size(), event.value().hashCode()); | ||
250 | + } | ||
251 | + } | ||
252 | + } | ||
253 | + } | ||
166 | } | 254 | } | ... | ... |
-
Please register or login to post a comment