alshabib
Committed by Gerrit Code Review

[Falcon] Refactored mcast store implementation.

Change-Id: Ie3fbc675d02c5abe5f5a419d2fc12dbe8fb4ec35

refactored mcast store implementation

Change-Id: I67d70d678813184c522c78e0771f6b8f8f9c25f8
Showing 17 changed files with 585 additions and 218 deletions
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.igmp.impl; 16 +package org.onosproject.igmp;
17 17
18 import org.onlab.packet.IGMP; 18 import org.onlab.packet.IGMP;
19 import org.onosproject.net.ConnectPoint; 19 import org.onosproject.net.ConnectPoint;
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.igmp.impl; 16 +package org.onosproject.igmp;
17 17
18 import org.onlab.packet.IGMP; 18 import org.onlab.packet.IGMP;
19 import org.onosproject.net.ConnectPoint; 19 import org.onosproject.net.ConnectPoint;
......
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 +
17 +package org.onosproject.igmp;
18 +
19 +import org.onosproject.net.DeviceId;
20 +import org.onosproject.net.config.Config;
21 +
22 +/**
23 + * Config object for access device data.
24 + */
25 +public class IgmpDeviceConfig extends Config<DeviceId> {
26 +
27 + /**
28 + * Gets the device information.
29 + *
30 + * @return device information
31 + */
32 + public IgmpDeviceData getDevice() {
33 + return new IgmpDeviceData(subject());
34 + }
35 +}
1 +package org.onosproject.igmp;
2 +
3 +import org.onosproject.net.DeviceId;
4 +
5 +import static com.google.common.base.Preconditions.checkNotNull;
6 +
7 +/**
8 + * Information about an igmp enabled device.
9 + */
10 +public class IgmpDeviceData {
11 +
12 + private static final String DEVICE_ID_MISSING = "Device ID cannot be null";
13 +
14 + private final DeviceId deviceId;
15 +
16 + public IgmpDeviceData(DeviceId deviceId) {
17 + this.deviceId = checkNotNull(deviceId, DEVICE_ID_MISSING);
18 + }
19 +
20 + /**
21 + * Retrieves the access device ID.
22 + *
23 + * @return device ID
24 + */
25 + public DeviceId deviceId() {
26 + return deviceId;
27 + }
28 +}
...@@ -13,13 +13,14 @@ ...@@ -13,13 +13,14 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.igmp.impl; 16 +package org.onosproject.igmp;
17 17
18 import static org.slf4j.LoggerFactory.getLogger; 18 import static org.slf4j.LoggerFactory.getLogger;
19 19
20 import org.apache.felix.scr.annotations.Activate; 20 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 21 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 22 import org.apache.felix.scr.annotations.Deactivate;
23 +import org.apache.felix.scr.annotations.Property;
23 import org.apache.felix.scr.annotations.Reference; 24 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 25 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.onlab.packet.Ethernet; 26 import org.onlab.packet.Ethernet;
...@@ -30,8 +31,13 @@ import org.onlab.packet.IpPrefix; ...@@ -30,8 +31,13 @@ import org.onlab.packet.IpPrefix;
30 import org.onlab.packet.IGMP; 31 import org.onlab.packet.IGMP;
31 import org.onosproject.core.ApplicationId; 32 import org.onosproject.core.ApplicationId;
32 import org.onosproject.core.CoreService; 33 import org.onosproject.core.CoreService;
34 +import org.onosproject.net.ConnectPoint;
35 +import org.onosproject.net.DeviceId;
36 +import org.onosproject.net.config.NetworkConfigRegistry;
33 import org.onosproject.net.flow.DefaultTrafficSelector; 37 import org.onosproject.net.flow.DefaultTrafficSelector;
34 import org.onosproject.net.flow.TrafficSelector; 38 import org.onosproject.net.flow.TrafficSelector;
39 +import org.onosproject.net.mcast.McastRoute;
40 +import org.onosproject.net.mcast.MulticastRouteService;
35 import org.onosproject.net.packet.InboundPacket; 41 import org.onosproject.net.packet.InboundPacket;
36 import org.onosproject.net.packet.PacketContext; 42 import org.onosproject.net.packet.PacketContext;
37 import org.onosproject.net.packet.PacketPriority; 43 import org.onosproject.net.packet.PacketPriority;
...@@ -39,20 +45,34 @@ import org.onosproject.net.packet.PacketProcessor; ...@@ -39,20 +45,34 @@ import org.onosproject.net.packet.PacketProcessor;
39 import org.onosproject.net.packet.PacketService; 45 import org.onosproject.net.packet.PacketService;
40 import org.slf4j.Logger; 46 import org.slf4j.Logger;
41 47
48 +import java.util.Optional;
49 +
42 /** 50 /**
43 * Internet Group Management Protocol. 51 * Internet Group Management Protocol.
44 */ 52 */
45 @Component(immediate = true) 53 @Component(immediate = true)
46 -public class IGMPComponent { 54 +public class IgmpSnoop {
47 private final Logger log = getLogger(getClass()); 55 private final Logger log = getLogger(getClass());
48 56
57 + private static final String DEFAULT_MCAST_ADDR = "224.0.0.0/4";
58 +
59 + @Property(name = "multicastAddress",
60 + label = "Define the multicast base raneg to listen to")
61 + private String multicastAddress = DEFAULT_MCAST_ADDR;
62 +
49 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
50 protected PacketService packetService; 64 protected PacketService packetService;
51 65
52 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected CoreService coreService; 67 protected CoreService coreService;
54 68
55 - private IGMPPacketProcessor processor = new IGMPPacketProcessor(); 69 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 + protected NetworkConfigRegistry networkConfig;
71 +
72 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 + protected MulticastRouteService multicastService;
74 +
75 + private IgmpPacketProcessor processor = new IgmpPacketProcessor();
56 private static ApplicationId appId; 76 private static ApplicationId appId;
57 77
58 @Activate 78 @Activate
...@@ -61,11 +81,16 @@ public class IGMPComponent { ...@@ -61,11 +81,16 @@ public class IGMPComponent {
61 81
62 packetService.addProcessor(processor, PacketProcessor.director(1)); 82 packetService.addProcessor(processor, PacketProcessor.director(1));
63 83
64 - // Build a traffic selector for all multicast traffic 84 + networkConfig.getSubjects(DeviceId.class, IgmpDeviceConfig.class).forEach(
65 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 85 + subject -> {
66 - selector.matchEthType(Ethernet.TYPE_IPV4); 86 + IgmpDeviceConfig config = networkConfig.getConfig(subject,
67 - selector.matchIPProtocol(IPv4.PROTOCOL_IGMP); 87 + IgmpDeviceConfig.class);
68 - packetService.requestPackets(selector.build(), PacketPriority.REACTIVE, appId); 88 + if (config != null) {
89 + IgmpDeviceData data = config.getDevice();
90 + submitPacketRequests(data.deviceId());
91 + }
92 + }
93 + );
69 94
70 log.info("Started"); 95 log.info("Started");
71 } 96 }
...@@ -77,10 +102,21 @@ public class IGMPComponent { ...@@ -77,10 +102,21 @@ public class IGMPComponent {
77 log.info("Stopped"); 102 log.info("Stopped");
78 } 103 }
79 104
105 + private void submitPacketRequests(DeviceId deviceId) {
106 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
107 + selector.matchEthType(Ethernet.TYPE_IPV4);
108 + selector.matchIPProtocol(IPv4.PROTOCOL_IGMP);
109 + packetService.requestPackets(selector.build(),
110 + PacketPriority.REACTIVE,
111 + appId,
112 + Optional.of(deviceId));
113 +
114 + }
115 +
80 /** 116 /**
81 * Packet processor responsible for handling IGMP packets. 117 * Packet processor responsible for handling IGMP packets.
82 */ 118 */
83 - private class IGMPPacketProcessor implements PacketProcessor { 119 + private class IgmpPacketProcessor implements PacketProcessor {
84 120
85 @Override 121 @Override
86 public void process(PacketContext context) { 122 public void process(PacketContext context) {
...@@ -107,15 +143,16 @@ public class IGMPComponent { ...@@ -107,15 +143,16 @@ public class IGMPComponent {
107 IPv4 ip = (IPv4) ethPkt.getPayload(); 143 IPv4 ip = (IPv4) ethPkt.getPayload();
108 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress()); 144 IpAddress gaddr = IpAddress.valueOf(ip.getDestinationAddress());
109 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress()); 145 IpAddress saddr = Ip4Address.valueOf(ip.getSourceAddress());
110 - log.debug("Packet (" + saddr.toString() + ", " + gaddr.toString() + 146 + log.debug("Packet ({}, {}) -> ingress port: {}", saddr, gaddr,
111 - "\tingress port: " + context.inPacket().receivedFrom().toString()); 147 + context.inPacket().receivedFrom());
148 +
112 149
113 if (ip.getProtocol() != IPv4.PROTOCOL_IGMP) { 150 if (ip.getProtocol() != IPv4.PROTOCOL_IGMP) {
114 log.debug("IGMP Picked up a non IGMP packet."); 151 log.debug("IGMP Picked up a non IGMP packet.");
115 return; 152 return;
116 } 153 }
117 154
118 - IpPrefix mcast = IpPrefix.valueOf("224.0.0.0/4"); 155 + IpPrefix mcast = IpPrefix.valueOf(DEFAULT_MCAST_ADDR);
119 if (!mcast.contains(gaddr)) { 156 if (!mcast.contains(gaddr)) {
120 log.debug("IGMP Picked up a non multicast packet."); 157 log.debug("IGMP Picked up a non multicast packet.");
121 return; 158 return;
...@@ -125,8 +162,6 @@ public class IGMPComponent { ...@@ -125,8 +162,6 @@ public class IGMPComponent {
125 log.debug("IGMP Picked up a packet with a multicast source address."); 162 log.debug("IGMP Picked up a packet with a multicast source address.");
126 return; 163 return;
127 } 164 }
128 - IpPrefix spfx = IpPrefix.valueOf(saddr, 32);
129 - IpPrefix gpfx = IpPrefix.valueOf(gaddr, 32);
130 165
131 IGMP igmp = (IGMP) ip.getPayload(); 166 IGMP igmp = (IGMP) ip.getPayload();
132 switch (igmp.getIgmpType()) { 167 switch (igmp.getIgmpType()) {
...@@ -136,14 +171,14 @@ public class IGMPComponent { ...@@ -136,14 +171,14 @@ public class IGMPComponent {
136 break; 171 break;
137 172
138 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY: 173 case IGMP.TYPE_IGMPV3_MEMBERSHIP_QUERY:
139 - IGMPProcessQuery.processQuery(igmp, pkt.receivedFrom()); 174 + processQuery(igmp, pkt.receivedFrom());
140 break; 175 break;
141 176
142 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT: 177 case IGMP.TYPE_IGMPV1_MEMBERSHIP_REPORT:
143 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT: 178 case IGMP.TYPE_IGMPV2_MEMBERSHIP_REPORT:
144 case IGMP.TYPE_IGMPV2_LEAVE_GROUP: 179 case IGMP.TYPE_IGMPV2_LEAVE_GROUP:
145 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: " + 180 log.debug("IGMP version 1 & 2 message types are not currently supported. Message type: " +
146 - igmp.getIgmpType()); 181 + igmp.getIgmpType());
147 break; 182 break;
148 183
149 default: 184 default:
...@@ -152,4 +187,16 @@ public class IGMPComponent { ...@@ -152,4 +187,16 @@ public class IGMPComponent {
152 } 187 }
153 } 188 }
154 } 189 }
190 +
191 + private void processQuery(IGMP pkt, ConnectPoint location) {
192 + pkt.getGroups().forEach(group -> group.getSources().forEach(src -> {
193 +
194 + McastRoute route = new McastRoute(src,
195 + group.getGaddr(),
196 + McastRoute.Type.IGMP);
197 + multicastService.add(route);
198 + multicastService.addSink(route, location);
199 +
200 + }));
201 + }
155 } 202 }
......
...@@ -17,4 +17,4 @@ ...@@ -17,4 +17,4 @@
17 /** 17 /**
18 * IGMP implementation. 18 * IGMP implementation.
19 */ 19 */
20 -package org.onosproject.igmp.impl; 20 +package org.onosproject.igmp;
......
...@@ -17,9 +17,6 @@ package org.onosproject.net.mcast; ...@@ -17,9 +17,6 @@ package org.onosproject.net.mcast;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 import org.onosproject.event.AbstractEvent; 19 import org.onosproject.event.AbstractEvent;
20 -import org.onosproject.net.ConnectPoint;
21 -
22 -import java.util.Optional;
23 20
24 import static com.google.common.base.MoreObjects.toStringHelper; 21 import static com.google.common.base.MoreObjects.toStringHelper;
25 22
...@@ -28,10 +25,8 @@ import static com.google.common.base.MoreObjects.toStringHelper; ...@@ -28,10 +25,8 @@ import static com.google.common.base.MoreObjects.toStringHelper;
28 * sinks or sources. 25 * sinks or sources.
29 */ 26 */
30 @Beta 27 @Beta
31 -public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { 28 +public class McastEvent extends AbstractEvent<McastEvent.Type, McastRouteInfo> {
32 29
33 - private final Optional<ConnectPoint> sink;
34 - private final Optional<ConnectPoint> source;
35 30
36 public enum Type { 31 public enum Type {
37 /** 32 /**
...@@ -60,59 +55,15 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { ...@@ -60,59 +55,15 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
60 SINK_REMOVED 55 SINK_REMOVED
61 } 56 }
62 57
63 - private McastEvent(McastEvent.Type type, McastRoute subject) { 58 + public McastEvent(McastEvent.Type type, McastRouteInfo subject) {
64 - super(type, subject);
65 - sink = Optional.empty();
66 - source = Optional.empty();
67 - }
68 -
69 - private McastEvent(McastEvent.Type type, McastRoute subject, long time) {
70 - super(type, subject, time);
71 - sink = Optional.empty();
72 - source = Optional.empty();
73 - }
74 -
75 - public McastEvent(McastEvent.Type type, McastRoute subject,
76 - ConnectPoint sink,
77 - ConnectPoint source) {
78 super(type, subject); 59 super(type, subject);
79 - this.sink = Optional.ofNullable(sink);
80 - this.source = Optional.ofNullable(source);
81 } 60 }
82 61
83 - public McastEvent(McastEvent.Type type, McastRoute subject, long time,
84 - ConnectPoint sink,
85 - ConnectPoint source) {
86 - super(type, subject, time);
87 - this.sink = Optional.ofNullable(sink);
88 - this.source = Optional.ofNullable(source);
89 - }
90 -
91 - /**
92 - * The sink which has been removed or added. The field may not be set
93 - * if the sink has not been detected yet or has been removed.
94 - *
95 - * @return an optional connect point
96 - */
97 - public Optional<ConnectPoint> sink() {
98 - return sink;
99 - }
100 -
101 - /**
102 - * The source which has been removed or added.
103 -
104 - * @return an optional connect point
105 - */
106 - public Optional<ConnectPoint> source() {
107 - return source;
108 - }
109 62
110 @Override 63 @Override
111 public String toString() { 64 public String toString() {
112 return toStringHelper(this) 65 return toStringHelper(this)
113 .add("type", type()) 66 .add("type", type())
114 - .add("route", subject()) 67 + .add("info", subject()).toString();
115 - .add("source", source)
116 - .add("sinks", sink).toString();
117 } 68 }
118 } 69 }
......
...@@ -17,7 +17,7 @@ package org.onosproject.net.mcast; ...@@ -17,7 +17,7 @@ package org.onosproject.net.mcast;
17 17
18 import com.google.common.annotations.Beta; 18 import com.google.common.annotations.Beta;
19 import com.google.common.base.Objects; 19 import com.google.common.base.Objects;
20 -import org.onlab.packet.IpPrefix; 20 +import org.onlab.packet.IpAddress;
21 21
22 import static com.google.common.base.MoreObjects.toStringHelper; 22 import static com.google.common.base.MoreObjects.toStringHelper;
23 import static com.google.common.base.Preconditions.checkNotNull; 23 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -46,11 +46,11 @@ public class McastRoute { ...@@ -46,11 +46,11 @@ public class McastRoute {
46 STATIC 46 STATIC
47 } 47 }
48 48
49 - private final IpPrefix source; 49 + private final IpAddress source;
50 - private final IpPrefix group; 50 + private final IpAddress group;
51 private final Type type; 51 private final Type type;
52 52
53 - public McastRoute(IpPrefix source, IpPrefix group, Type type) { 53 + public McastRoute(IpAddress source, IpAddress group, Type type) {
54 checkNotNull(source, "Multicast route must have a source"); 54 checkNotNull(source, "Multicast route must have a source");
55 checkNotNull(group, "Multicast route must specify a group address"); 55 checkNotNull(group, "Multicast route must specify a group address");
56 checkNotNull(type, "Must indicate what type of route"); 56 checkNotNull(type, "Must indicate what type of route");
...@@ -64,7 +64,7 @@ public class McastRoute { ...@@ -64,7 +64,7 @@ public class McastRoute {
64 * 64 *
65 * @return an ip address 65 * @return an ip address
66 */ 66 */
67 - public IpPrefix source() { 67 + public IpAddress source() {
68 return source; 68 return source;
69 } 69 }
70 70
...@@ -73,7 +73,7 @@ public class McastRoute { ...@@ -73,7 +73,7 @@ public class McastRoute {
73 * 73 *
74 * @return an ip address 74 * @return an ip address
75 */ 75 */
76 - public IpPrefix group() { 76 + public IpAddress group() {
77 return group; 77 return group;
78 } 78 }
79 79
......
1 +package org.onosproject.net.mcast;
2 +
3 +import com.google.common.collect.ImmutableSet;
4 +import org.onosproject.net.ConnectPoint;
5 +
6 +import java.util.Collections;
7 +import java.util.Optional;
8 +import java.util.Set;
9 +
10 +import static com.google.common.base.Preconditions.checkNotNull;
11 +
12 +/**
13 + * Multicast information as stored in the store.
14 + */
15 +public final class McastRouteInfo {
16 +
17 + private static final String ROUTE_NOT_NULL = "Route cannot be null";
18 +
19 + private final McastRoute route;
20 + private final Optional<ConnectPoint> sink;
21 + private final Optional<ConnectPoint> source;
22 + private final Set<ConnectPoint> sinks;
23 +
24 + private McastRouteInfo(McastRoute route, ConnectPoint sink,
25 + ConnectPoint source, Set<ConnectPoint> sinks) {
26 + this.route = checkNotNull(route, ROUTE_NOT_NULL);
27 + this.sink = Optional.ofNullable(sink);
28 + this.source = Optional.ofNullable(source);
29 + this.sinks = sinks;
30 + }
31 +
32 + public static McastRouteInfo mcastRouteInfo(McastRoute route) {
33 + return new McastRouteInfo(route, null, null, Collections.EMPTY_SET);
34 + }
35 +
36 + public static McastRouteInfo mcastRouteInfo(McastRoute route,
37 + ConnectPoint sink,
38 + ConnectPoint source) {
39 + return new McastRouteInfo(route, sink, source, Collections.EMPTY_SET);
40 + }
41 +
42 + public static McastRouteInfo mcastRouteInfo(McastRoute route,
43 + Set<ConnectPoint> sinks,
44 + ConnectPoint source) {
45 + return new McastRouteInfo(route, null, source, ImmutableSet.copyOf(sinks));
46 + }
47 +
48 + public boolean isComplete() {
49 + return ((sink.isPresent() || sinks.size() > 0) && source.isPresent());
50 + }
51 +
52 + /**
53 + * The route associated with this multicast information.
54 + *
55 + * @return a mulicast route
56 + */
57 + public McastRoute route() {
58 + return route;
59 + }
60 +
61 + /**
62 + * The source which has been removed or added.
63 +
64 + * @return an optional connect point
65 + */
66 + public Optional<ConnectPoint> source() {
67 + return source;
68 + }
69 +
70 + /**
71 + * The sink which has been removed or added. The field may not be set
72 + * if the sink has not been detected yet or has been removed.
73 + *
74 + * @return an optional connect point
75 + */
76 + public Optional<ConnectPoint> sink() {
77 + return sink;
78 + }
79 +
80 + /**
81 + * Returns the set of sinks associated with this route. Only valid with
82 + * SOURCE_ADDED events.
83 + *
84 + * @return a set of connect points
85 + */
86 + public Set<ConnectPoint> sinks() {
87 + return sinks;
88 + }
89 +
90 +}
1 +package org.onosproject.net.mcast;
2 +
3 +import org.onosproject.net.ConnectPoint;
4 +import org.onosproject.store.Store;
5 +
6 +import java.util.Set;
7 +
8 +/**
9 + * Entity responsible for storing multicast state information.
10 + */
11 +public interface McastStore extends Store<McastEvent, McastStoreDelegate> {
12 +
13 + enum Type {
14 + /**
15 + * Adding a route to the mcast rib.
16 + */
17 + ADD,
18 +
19 + /**
20 + * Removing a route from the mcast rib.
21 + */
22 + REMOVE
23 + }
24 +
25 + /**
26 + * Updates the store with the route information.
27 + *
28 + * @param route a multicast route
29 + * @param operation an operation
30 + */
31 + void storeRoute(McastRoute route, Type operation);
32 +
33 + /**
34 + * Updates the store with source information for the given route. Only one
35 + * source is permitted. Submitting another source will replace the previous
36 + * value.
37 + *
38 + * @param route a multicast route
39 + * @param source a source
40 + */
41 + void storeSource(McastRoute route, ConnectPoint source);
42 +
43 + /**
44 + * Updates the store with sink information for a given route. There may be
45 + * multiple sinks.
46 + *
47 + * @param route a multicast route
48 + * @param sink a sink
49 + * @param operation an operation
50 + */
51 + void storeSink(McastRoute route, ConnectPoint sink, Type operation);
52 +
53 + /**
54 + * Obtain the source for a multicast route.
55 + *
56 + * @param route a multicast route
57 + * @return a connect point
58 + */
59 + ConnectPoint sourceFor(McastRoute route);
60 +
61 + /**
62 + * Obtain the sinks for a multicast route.
63 + *
64 + * @param route a multicast route
65 + * @return a set of sinks
66 + */
67 + Set<ConnectPoint> sinksFor(McastRoute route);
68 +}
1 +package org.onosproject.net.mcast;
2 +
3 +
4 +import org.onosproject.store.StoreDelegate;
5 +
6 +/**
7 + * Mcast store delegate abstraction.
8 + */
9 +public interface McastStoreDelegate extends StoreDelegate<McastEvent> {
10 +}
...@@ -19,7 +19,7 @@ import com.google.common.annotations.Beta; ...@@ -19,7 +19,7 @@ import com.google.common.annotations.Beta;
19 import org.onosproject.event.ListenerService; 19 import org.onosproject.event.ListenerService;
20 import org.onosproject.net.ConnectPoint; 20 import org.onosproject.net.ConnectPoint;
21 21
22 -import java.util.List; 22 +import java.util.Set;
23 23
24 /** 24 /**
25 * A service interface for maintaining multicast information. 25 * A service interface for maintaining multicast information.
...@@ -82,5 +82,5 @@ public interface MulticastRouteService ...@@ -82,5 +82,5 @@ public interface MulticastRouteService
82 * @param route a multicast route 82 * @param route a multicast route
83 * @return a list of connect points 83 * @return a list of connect points
84 */ 84 */
85 - List<ConnectPoint> fetchSinks(McastRoute route); 85 + Set<ConnectPoint> fetchSinks(McastRoute route);
86 } 86 }
......
...@@ -21,25 +21,19 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -21,25 +21,19 @@ import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference; 21 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality; 22 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.apache.felix.scr.annotations.Service; 23 import org.apache.felix.scr.annotations.Service;
24 -import org.onlab.packet.IpPrefix;
25 -import org.onlab.util.KryoNamespace;
26 -import org.onosproject.core.ApplicationId;
27 -import org.onosproject.core.CoreService;
28 import org.onosproject.event.AbstractListenerManager; 24 import org.onosproject.event.AbstractListenerManager;
29 import org.onosproject.net.ConnectPoint; 25 import org.onosproject.net.ConnectPoint;
30 import org.onosproject.net.mcast.McastEvent; 26 import org.onosproject.net.mcast.McastEvent;
31 import org.onosproject.net.mcast.McastListener; 27 import org.onosproject.net.mcast.McastListener;
32 import org.onosproject.net.mcast.McastRoute; 28 import org.onosproject.net.mcast.McastRoute;
29 +import org.onosproject.net.mcast.McastStore;
30 +import org.onosproject.net.mcast.McastStoreDelegate;
33 import org.onosproject.net.mcast.MulticastRouteService; 31 import org.onosproject.net.mcast.MulticastRouteService;
34 -import org.onosproject.store.service.ConsistentMap;
35 -import org.onosproject.store.service.Serializer;
36 -import org.onosproject.store.service.StorageService;
37 -import org.onosproject.store.service.Versioned;
38 import org.slf4j.Logger; 32 import org.slf4j.Logger;
39 33
40 -import java.util.List; 34 +import java.util.Set;
41 -import java.util.concurrent.atomic.AtomicReference;
42 35
36 +import static com.google.common.base.Preconditions.checkNotNull;
43 import static org.slf4j.LoggerFactory.getLogger; 37 import static org.slf4j.LoggerFactory.getLogger;
44 38
45 /** 39 /**
...@@ -52,38 +46,18 @@ public class MulticastRouteManager ...@@ -52,38 +46,18 @@ public class MulticastRouteManager
52 implements MulticastRouteService { 46 implements MulticastRouteService {
53 //TODO: add MulticastRouteAdminService 47 //TODO: add MulticastRouteAdminService
54 48
55 - private static final String MCASTRIB = "mcast-rib-table";
56 -
57 private Logger log = getLogger(getClass()); 49 private Logger log = getLogger(getClass());
58 50
59 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 51 + private final McastStoreDelegate delegate = new InternalMcastStoreDelegate();
60 - private StorageService storageService;
61 52
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 53 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 - private CoreService coreService; 54 + protected McastStore store;
64 -
65 -
66 - protected ApplicationId appId;
67 - protected ConsistentMap<McastRoute, MulticastData> mcastRoutes;
68 55
69 @Activate 56 @Activate
70 public void activate() { 57 public void activate() {
71 58
72 eventDispatcher.addSink(McastEvent.class, listenerRegistry); 59 eventDispatcher.addSink(McastEvent.class, listenerRegistry);
73 - 60 + store.setDelegate(delegate);
74 - appId = coreService.registerApplication("org.onosproject.mcastrib");
75 -
76 - mcastRoutes = storageService.<McastRoute, MulticastData>consistentMapBuilder()
77 - .withApplicationId(appId)
78 - .withName(MCASTRIB)
79 - .withSerializer(Serializer.using(KryoNamespace.newBuilder().register(
80 - MulticastData.class,
81 - McastRoute.class,
82 - McastRoute.Type.class,
83 - IpPrefix.class,
84 - List.class,
85 - ConnectPoint.class
86 - ).build())).build();
87 61
88 log.info("Started"); 62 log.info("Started");
89 } 63 }
...@@ -95,80 +69,55 @@ public class MulticastRouteManager ...@@ -95,80 +69,55 @@ public class MulticastRouteManager
95 69
96 @Override 70 @Override
97 public void add(McastRoute route) { 71 public void add(McastRoute route) {
98 - mcastRoutes.put(route, MulticastData.empty()); 72 + checkNotNull(route, "Route cannot be null");
99 - post(new McastEvent(McastEvent.Type.ROUTE_ADDED, route, null, null)); 73 + store.storeRoute(route, McastStore.Type.ADD);
100 } 74 }
101 75
102 @Override 76 @Override
103 public void remove(McastRoute route) { 77 public void remove(McastRoute route) {
104 - mcastRoutes.remove(route); 78 + checkNotNull(route, "Route cannot be null");
105 - post(new McastEvent(McastEvent.Type.ROUTE_REMOVED, route, null, null)); 79 + store.storeRoute(route, McastStore.Type.REMOVE);
106 } 80 }
107 81
108 @Override 82 @Override
109 public void addSource(McastRoute route, ConnectPoint connectPoint) { 83 public void addSource(McastRoute route, ConnectPoint connectPoint) {
110 - Versioned<MulticastData> d = mcastRoutes.compute(route, (k, v) -> { 84 + checkNotNull(route, "Route cannot be null");
111 - if (v.isEmpty()) { 85 + checkNotNull(connectPoint, "Source cannot be null");
112 - return new MulticastData(connectPoint); 86 + store.storeSource(route, connectPoint);
113 - } else {
114 - log.warn("Route {} is already in use.", route);
115 - return v;
116 - }
117 - });
118 -
119 - if (d != null) {
120 - post(new McastEvent(McastEvent.Type.SOURCE_ADDED,
121 - route, null, connectPoint));
122 - }
123 } 87 }
124 88
125 @Override 89 @Override
126 public void addSink(McastRoute route, ConnectPoint connectPoint) { 90 public void addSink(McastRoute route, ConnectPoint connectPoint) {
127 - AtomicReference<ConnectPoint> source = new AtomicReference<>(); 91 + checkNotNull(route, "Route cannot be null");
128 - mcastRoutes.compute(route, (k, v) -> { 92 + checkNotNull(connectPoint, "Sink cannot be null");
129 - if (!v.isEmpty()) { 93 + store.storeSink(route, connectPoint, McastStore.Type.ADD);
130 - v.appendSink(connectPoint); 94 +
131 - source.set(v.source());
132 - } else {
133 - log.warn("Route {} does not exist");
134 - }
135 - return v;
136 - });
137 -
138 - if (source.get() != null) {
139 - post(new McastEvent(McastEvent.Type.SINK_ADDED, route,
140 - connectPoint, source.get()));
141 - }
142 } 95 }
143 96
144 97
145 @Override 98 @Override
146 public void removeSink(McastRoute route, ConnectPoint connectPoint) { 99 public void removeSink(McastRoute route, ConnectPoint connectPoint) {
147 - AtomicReference<ConnectPoint> source = new AtomicReference<>(); 100 +
148 - mcastRoutes.compute(route, (k, v) -> { 101 + checkNotNull(route, "Route cannot be null");
149 - if (v.removeSink(connectPoint)) { 102 + checkNotNull(connectPoint, "Sink cannot be null");
150 - source.set(v.source()); 103 +
151 - } 104 + store.storeSink(route, connectPoint, McastStore.Type.REMOVE);
152 - return v;
153 - });
154 -
155 - if (source.get() != null) {
156 - post(new McastEvent(McastEvent.Type.SINK_REMOVED, route,
157 - connectPoint, source.get()));
158 - }
159 } 105 }
160 106
161 @Override 107 @Override
162 public ConnectPoint fetchSource(McastRoute route) { 108 public ConnectPoint fetchSource(McastRoute route) {
163 - MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route, 109 + return store.sourceFor(route);
164 - MulticastData.empty());
165 - return d.source();
166 } 110 }
167 111
168 @Override 112 @Override
169 - public List<ConnectPoint> fetchSinks(McastRoute route) { 113 + public Set<ConnectPoint> fetchSinks(McastRoute route) {
170 - MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route, 114 + return store.sinksFor(route);
171 - MulticastData.empty()); 115 + }
172 - return d.sinks(); 116 +
117 + private class InternalMcastStoreDelegate implements McastStoreDelegate {
118 + @Override
119 + public void notify(McastEvent event) {
120 + post(event);
121 + }
173 } 122 }
174 } 123 }
......
...@@ -16,15 +16,17 @@ ...@@ -16,15 +16,17 @@
16 package org.onosproject.incubator.net.mcast.impl; 16 package org.onosproject.incubator.net.mcast.impl;
17 17
18 import com.google.common.collect.Lists; 18 import com.google.common.collect.Lists;
19 +import com.google.common.collect.Sets;
19 import org.junit.After; 20 import org.junit.After;
20 import org.junit.Before; 21 import org.junit.Before;
21 import org.junit.Test; 22 import org.junit.Test;
22 import org.onlab.junit.TestUtils; 23 import org.onlab.junit.TestUtils;
23 -import org.onlab.packet.IpPrefix; 24 +import org.onlab.packet.IpAddress;
24 import org.onosproject.common.event.impl.TestEventDispatcher; 25 import org.onosproject.common.event.impl.TestEventDispatcher;
25 import org.onosproject.core.ApplicationId; 26 import org.onosproject.core.ApplicationId;
26 import org.onosproject.core.CoreServiceAdapter; 27 import org.onosproject.core.CoreServiceAdapter;
27 import org.onosproject.core.DefaultApplicationId; 28 import org.onosproject.core.DefaultApplicationId;
29 +import org.onosproject.incubator.store.mcast.impl.DistributedMcastStore;
28 import org.onosproject.net.ConnectPoint; 30 import org.onosproject.net.ConnectPoint;
29 import org.onosproject.net.PortNumber; 31 import org.onosproject.net.PortNumber;
30 import org.onosproject.net.mcast.McastEvent; 32 import org.onosproject.net.mcast.McastEvent;
...@@ -44,16 +46,16 @@ import static org.onosproject.net.NetTestTools.injectEventDispatcher; ...@@ -44,16 +46,16 @@ import static org.onosproject.net.NetTestTools.injectEventDispatcher;
44 */ 46 */
45 public class MulticastRouteManagerTest { 47 public class MulticastRouteManagerTest {
46 48
47 - McastRoute r1 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"), 49 + McastRoute r1 = new McastRoute(IpAddress.valueOf("1.1.1.1"),
48 - IpPrefix.valueOf("1.1.1.2/8"), 50 + IpAddress.valueOf("1.1.1.2"),
49 McastRoute.Type.IGMP); 51 McastRoute.Type.IGMP);
50 52
51 - McastRoute r11 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"), 53 + McastRoute r11 = new McastRoute(IpAddress.valueOf("1.1.1.1"),
52 - IpPrefix.valueOf("1.1.1.2/8"), 54 + IpAddress.valueOf("1.1.1.2"),
53 McastRoute.Type.STATIC); 55 McastRoute.Type.STATIC);
54 56
55 - McastRoute r2 = new McastRoute(IpPrefix.valueOf("2.2.2.1/8"), 57 + McastRoute r2 = new McastRoute(IpAddress.valueOf("2.2.2.1"),
56 - IpPrefix.valueOf("2.2.2.2/8"), 58 + IpAddress.valueOf("2.2.2.2"),
57 McastRoute.Type.PIM); 59 McastRoute.Type.PIM);
58 60
59 ConnectPoint cp1 = new ConnectPoint(did("1"), PortNumber.portNumber(1)); 61 ConnectPoint cp1 = new ConnectPoint(did("1"), PortNumber.portNumber(1));
...@@ -66,13 +68,17 @@ public class MulticastRouteManagerTest { ...@@ -66,13 +68,17 @@ public class MulticastRouteManagerTest {
66 68
67 private List<McastEvent> events; 69 private List<McastEvent> events;
68 70
71 + private DistributedMcastStore mcastStore;
72 +
69 @Before 73 @Before
70 public void setUp() throws Exception { 74 public void setUp() throws Exception {
71 manager = new MulticastRouteManager(); 75 manager = new MulticastRouteManager();
76 + mcastStore = new DistributedMcastStore();
77 + TestUtils.setField(mcastStore, "storageService", new TestStorageService());
72 injectEventDispatcher(manager, new TestEventDispatcher()); 78 injectEventDispatcher(manager, new TestEventDispatcher());
73 - TestUtils.setField(manager, "storageService", new TestStorageService());
74 - TestUtils.setField(manager, "coreService", new TestCoreService());
75 events = Lists.newArrayList(); 79 events = Lists.newArrayList();
80 + manager.store = mcastStore;
81 + mcastStore.activate();
76 manager.activate(); 82 manager.activate();
77 manager.addListener(listener); 83 manager.addListener(listener);
78 } 84 }
...@@ -81,13 +87,13 @@ public class MulticastRouteManagerTest { ...@@ -81,13 +87,13 @@ public class MulticastRouteManagerTest {
81 public void tearDown() { 87 public void tearDown() {
82 manager.removeListener(listener); 88 manager.removeListener(listener);
83 manager.deactivate(); 89 manager.deactivate();
90 + mcastStore.deactivate();
84 } 91 }
85 92
86 @Test 93 @Test
87 public void testAdd() { 94 public void testAdd() {
88 manager.add(r1); 95 manager.add(r1);
89 96
90 - assertEquals("Add failed", manager.mcastRoutes.size(), 1);
91 validateEvents(McastEvent.Type.ROUTE_ADDED); 97 validateEvents(McastEvent.Type.ROUTE_ADDED);
92 } 98 }
93 99
...@@ -97,48 +103,39 @@ public class MulticastRouteManagerTest { ...@@ -97,48 +103,39 @@ public class MulticastRouteManagerTest {
97 103
98 manager.remove(r1); 104 manager.remove(r1);
99 105
100 - assertEquals("Remove failed", manager.mcastRoutes.size(), 0); 106 +
101 validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.ROUTE_REMOVED); 107 validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.ROUTE_REMOVED);
102 } 108 }
103 109
104 @Test 110 @Test
105 public void testAddSource() { 111 public void testAddSource() {
106 - manager.add(r1);
107 -
108 manager.addSource(r1, cp1); 112 manager.addSource(r1, cp1);
109 113
110 - validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.SOURCE_ADDED); 114 + validateEvents(McastEvent.Type.SOURCE_ADDED);
111 assertEquals("Route is not equal", cp1, manager.fetchSource(r1)); 115 assertEquals("Route is not equal", cp1, manager.fetchSource(r1));
112 } 116 }
113 117
114 @Test 118 @Test
115 public void testAddSink() { 119 public void testAddSink() {
116 - manager.add(r1);
117 -
118 - manager.addSource(r1, cp1);
119 manager.addSink(r1, cp1); 120 manager.addSink(r1, cp1);
120 121
121 - validateEvents(McastEvent.Type.ROUTE_ADDED, 122 + validateEvents(McastEvent.Type.SINK_ADDED);
122 - McastEvent.Type.SOURCE_ADDED, 123 + assertEquals("Route is not equal", Sets.newHashSet(cp1), manager.fetchSinks(r1));
123 - McastEvent.Type.SINK_ADDED);
124 - assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1));
125 } 124 }
126 125
127 @Test 126 @Test
128 public void testRemoveSink() { 127 public void testRemoveSink() {
129 - manager.add(r1);
130 128
131 manager.addSource(r1, cp1); 129 manager.addSource(r1, cp1);
132 manager.addSink(r1, cp1); 130 manager.addSink(r1, cp1);
133 manager.addSink(r1, cp2); 131 manager.addSink(r1, cp2);
134 manager.removeSink(r1, cp2); 132 manager.removeSink(r1, cp2);
135 133
136 - validateEvents(McastEvent.Type.ROUTE_ADDED, 134 + validateEvents(McastEvent.Type.SOURCE_ADDED,
137 - McastEvent.Type.SOURCE_ADDED,
138 McastEvent.Type.SINK_ADDED, 135 McastEvent.Type.SINK_ADDED,
139 McastEvent.Type.SINK_ADDED, 136 McastEvent.Type.SINK_ADDED,
140 McastEvent.Type.SINK_REMOVED); 137 McastEvent.Type.SINK_REMOVED);
141 - assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1)); 138 + assertEquals("Route is not equal", Sets.newHashSet(cp1), manager.fetchSinks(r1));
142 } 139 }
143 140
144 private void validateEvents(McastEvent.Type... evs) { 141 private void validateEvents(McastEvent.Type... evs) {
......
1 +package org.onosproject.incubator.store.mcast.impl;
2 +
3 +import org.apache.felix.scr.annotations.Activate;
4 +import org.apache.felix.scr.annotations.Component;
5 +import org.apache.felix.scr.annotations.Deactivate;
6 +import org.apache.felix.scr.annotations.Reference;
7 +import org.apache.felix.scr.annotations.ReferenceCardinality;
8 +import org.apache.felix.scr.annotations.Service;
9 +import org.onlab.packet.IpPrefix;
10 +import org.onlab.util.KryoNamespace;
11 +import org.onosproject.net.ConnectPoint;
12 +import org.onosproject.net.mcast.McastEvent;
13 +import org.onosproject.net.mcast.McastRoute;
14 +import org.onosproject.net.mcast.McastRouteInfo;
15 +import org.onosproject.net.mcast.McastStore;
16 +import org.onosproject.net.mcast.McastStoreDelegate;
17 +import org.onosproject.store.AbstractStore;
18 +import org.onosproject.store.service.ConsistentMap;
19 +import org.onosproject.store.service.Serializer;
20 +import org.onosproject.store.service.StorageService;
21 +import org.slf4j.Logger;
22 +
23 +import java.util.List;
24 +import java.util.Map;
25 +import java.util.Set;
26 +
27 +import static org.slf4j.LoggerFactory.getLogger;
28 +
29 +/**
30 + * A distributed mcast store implementation. Routes are stored consistently
31 + * across the cluster.
32 + */
33 +@Component(immediate = true)
34 +@Service
35 +public class DistributedMcastStore extends AbstractStore<McastEvent, McastStoreDelegate>
36 + implements McastStore {
37 + //FIXME the number of events that will potentially be generated here is
38 + // not sustainable, consider changing this to an eventually consistent
39 + // map and not emitting events but rather use a provider-like mechanism
40 + // to program the dataplane.
41 +
42 + private static final String MCASTRIB = "mcast-rib-table";
43 + private Logger log = getLogger(getClass());
44 +
45 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
46 + private StorageService storageService;
47 +
48 + protected ConsistentMap<McastRoute, MulticastData> mcastRIB;
49 + protected Map<McastRoute, MulticastData> mcastRoutes;
50 +
51 +
52 + @Activate
53 + public void activate() {
54 +
55 + mcastRIB = storageService.<McastRoute, MulticastData>consistentMapBuilder()
56 + .withName(MCASTRIB)
57 + .withSerializer(Serializer.using(KryoNamespace.newBuilder().register(
58 + MulticastData.class,
59 + McastRoute.class,
60 + McastRoute.Type.class,
61 + IpPrefix.class,
62 + List.class,
63 + ConnectPoint.class
64 + ).build()))
65 + .withRelaxedReadConsistency()
66 + .build();
67 +
68 + mcastRoutes = mcastRIB.asJavaMap();
69 +
70 +
71 + log.info("Started");
72 + }
73 +
74 + @Deactivate
75 + public void deactivate() {
76 + log.info("Stopped");
77 + }
78 +
79 + @Override
80 + public void storeRoute(McastRoute route, Type operation) {
81 + switch (operation) {
82 + case ADD:
83 + if (mcastRoutes.putIfAbsent(route, MulticastData.empty()) == null) {
84 + delegate.notify(new McastEvent(McastEvent.Type.ROUTE_ADDED,
85 + McastRouteInfo.mcastRouteInfo(route)));
86 + }
87 + break;
88 + case REMOVE:
89 + if (mcastRoutes.remove(route) != null) {
90 + delegate.notify(new McastEvent(McastEvent.Type.ROUTE_REMOVED,
91 + McastRouteInfo.mcastRouteInfo(route)));
92 + }
93 + break;
94 + default:
95 + log.warn("Unknown mcast operation type: {}", operation);
96 + }
97 + }
98 +
99 + @Override
100 + public void storeSource(McastRoute route, ConnectPoint source) {
101 + MulticastData data = mcastRoutes.compute(route, (k, v) -> {
102 + if (v == null) {
103 + return new MulticastData(source);
104 + } else {
105 + v.setSource(source);
106 + }
107 + return v;
108 + });
109 +
110 +
111 + if (data != null) {
112 + delegate.notify(new McastEvent(McastEvent.Type.SOURCE_ADDED,
113 + McastRouteInfo.mcastRouteInfo(route,
114 + data.sinks(),
115 + source)));
116 + }
117 +
118 + }
119 +
120 + @Override
121 + public void storeSink(McastRoute route, ConnectPoint sink, Type operation) {
122 + MulticastData data = mcastRoutes.compute(route, (k, v) -> {
123 + switch (operation) {
124 + case ADD:
125 + if (v == null) {
126 + v = MulticastData.empty();
127 + }
128 + v.appendSink(sink);
129 + break;
130 + case REMOVE:
131 + if (v != null) {
132 + v.removeSink(sink);
133 + }
134 + break;
135 + default:
136 + log.warn("Unknown mcast operation type: {}", operation);
137 + }
138 + return v;
139 + });
140 +
141 +
142 + if (data != null) {
143 + switch (operation) {
144 + case ADD:
145 + delegate.notify(new McastEvent(
146 + McastEvent.Type.SINK_ADDED,
147 + McastRouteInfo.mcastRouteInfo(route,
148 + sink,
149 + data.source())));
150 + break;
151 + case REMOVE:
152 + if (data != null) {
153 + delegate.notify(new McastEvent(
154 + McastEvent.Type.SINK_REMOVED,
155 + McastRouteInfo.mcastRouteInfo(route,
156 + sink,
157 + data.source())));
158 + }
159 + break;
160 + default:
161 + log.warn("Unknown mcast operation type: {}", operation);
162 + }
163 + }
164 +
165 + }
166 +
167 + @Override
168 + public ConnectPoint sourceFor(McastRoute route) {
169 + return mcastRoutes.getOrDefault(route, MulticastData.empty()).source();
170 + }
171 +
172 + @Override
173 + public Set<ConnectPoint> sinksFor(McastRoute route) {
174 + return mcastRoutes.getOrDefault(route, MulticastData.empty()).sinks();
175 + }
176 +
177 +}
...@@ -13,14 +13,15 @@ ...@@ -13,14 +13,15 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.incubator.net.mcast.impl; 16 +package org.onosproject.incubator.store.mcast.impl;
17 17
18 -import com.google.common.collect.ImmutableList; 18 +import com.google.common.collect.ImmutableSet;
19 -import com.google.common.collect.Lists; 19 +import com.google.common.collect.Sets;
20 import org.onosproject.net.ConnectPoint; 20 import org.onosproject.net.ConnectPoint;
21 21
22 -import java.util.Collections; 22 +import java.util.Set;
23 -import java.util.List; 23 +import java.util.concurrent.atomic.AtomicBoolean;
24 +import java.util.concurrent.atomic.AtomicReference;
24 25
25 import static com.google.common.base.Preconditions.checkNotNull; 26 import static com.google.common.base.Preconditions.checkNotNull;
26 27
...@@ -30,40 +31,33 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -30,40 +31,33 @@ import static com.google.common.base.Preconditions.checkNotNull;
30 */ 31 */
31 public final class MulticastData { 32 public final class MulticastData {
32 33
33 - private final ConnectPoint source; 34 + private final AtomicReference<ConnectPoint> source =
34 - private final List<ConnectPoint> sinks; 35 + new AtomicReference<>();
35 - private final boolean isEmpty; 36 + private final Set<ConnectPoint> sinks;
37 + private final AtomicBoolean isEmpty = new AtomicBoolean();
36 38
37 private MulticastData() { 39 private MulticastData() {
38 - this.source = null; 40 + this.sinks = Sets.newConcurrentHashSet();
39 - this.sinks = Collections.EMPTY_LIST; 41 + isEmpty.set(true);
40 - isEmpty = true;
41 - }
42 -
43 - public MulticastData(ConnectPoint source, List<ConnectPoint> sinks) {
44 - this.source = checkNotNull(source, "Multicast source cannot be null.");
45 - this.sinks = checkNotNull(sinks, "List of sinks cannot be null.");
46 - isEmpty = false;
47 - }
48 -
49 - public MulticastData(ConnectPoint source, ConnectPoint sink) {
50 - this.source = checkNotNull(source, "Multicast source cannot be null.");
51 - this.sinks = Lists.newArrayList(checkNotNull(sink, "Sink cannot be null."));
52 - isEmpty = false;
53 } 42 }
54 43
55 public MulticastData(ConnectPoint source) { 44 public MulticastData(ConnectPoint source) {
56 - this.source = checkNotNull(source, "Multicast source cannot be null."); 45 + this.source.set(checkNotNull(source, "Multicast source cannot be null."));
57 - this.sinks = Lists.newArrayList(); 46 + this.sinks = Sets.newConcurrentHashSet();
58 - isEmpty = false; 47 + isEmpty.set(false);
59 } 48 }
60 49
61 public ConnectPoint source() { 50 public ConnectPoint source() {
62 - return source; 51 + return source.get();
52 + }
53 +
54 + public Set<ConnectPoint> sinks() {
55 + return ImmutableSet.copyOf(sinks);
63 } 56 }
64 57
65 - public List<ConnectPoint> sinks() { 58 + public void setSource(ConnectPoint source) {
66 - return ImmutableList.copyOf(sinks); 59 + isEmpty.set(false);
60 + this.source.set(source);
67 } 61 }
68 62
69 public void appendSink(ConnectPoint sink) { 63 public void appendSink(ConnectPoint sink) {
...@@ -75,7 +69,7 @@ public final class MulticastData { ...@@ -75,7 +69,7 @@ public final class MulticastData {
75 } 69 }
76 70
77 public boolean isEmpty() { 71 public boolean isEmpty() {
78 - return isEmpty; 72 + return isEmpty.get();
79 } 73 }
80 74
81 public static MulticastData empty() { 75 public static MulticastData empty() {
......
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 +
17 +/**
18 + * A distributed multicast store implementation that stores multicast rib
19 + * data consistently across the cluster.
20 + */
21 +package org.onosproject.incubator.store.mcast.impl;