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
419 additions
and
39 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,7 +78,7 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -77,7 +78,7 @@ 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 | /** |
| ... | @@ -85,9 +86,12 @@ public class DefaultTopology extends AbstractModel implements Topology { | ... | @@ -85,9 +86,12 @@ public class DefaultTopology extends AbstractModel implements Topology { |
| 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 |
| ... | @@ -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); | ... | ... |
| ... | @@ -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