alshabib
Committed by Gerrit Code Review

initial impl of a multicast route table

Change-Id: Ic86a0665d1ade6b85b05e602ead2bd9c0a7dde07
...@@ -21,6 +21,8 @@ import org.onosproject.net.ConnectPoint; ...@@ -21,6 +21,8 @@ import org.onosproject.net.ConnectPoint;
21 21
22 import java.util.Optional; 22 import java.util.Optional;
23 23
24 +import static com.google.common.base.MoreObjects.toStringHelper;
25 +
24 /** 26 /**
25 * An entity representing a multicast event. Event either add or remove 27 * An entity representing a multicast event. Event either add or remove
26 * sinks or sources. 28 * sinks or sources.
...@@ -48,11 +50,6 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { ...@@ -48,11 +50,6 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
48 SOURCE_ADDED, 50 SOURCE_ADDED,
49 51
50 /** 52 /**
51 - * A source for a mcast route (ie. the subject) has been removed.
52 - */
53 - SOURCE_REMOVED,
54 -
55 - /**
56 * A sink for a mcast route (ie. the subject) has been added. 53 * A sink for a mcast route (ie. the subject) has been added.
57 */ 54 */
58 SINK_ADDED, 55 SINK_ADDED,
...@@ -75,7 +72,7 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { ...@@ -75,7 +72,7 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
75 source = Optional.empty(); 72 source = Optional.empty();
76 } 73 }
77 74
78 - protected McastEvent(McastEvent.Type type, McastRoute subject, 75 + public McastEvent(McastEvent.Type type, McastRoute subject,
79 ConnectPoint sink, 76 ConnectPoint sink,
80 ConnectPoint source) { 77 ConnectPoint source) {
81 super(type, subject); 78 super(type, subject);
...@@ -83,7 +80,7 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { ...@@ -83,7 +80,7 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
83 this.source = Optional.ofNullable(source); 80 this.source = Optional.ofNullable(source);
84 } 81 }
85 82
86 - protected McastEvent(McastEvent.Type type, McastRoute subject, long time, 83 + public McastEvent(McastEvent.Type type, McastRoute subject, long time,
87 ConnectPoint sink, 84 ConnectPoint sink,
88 ConnectPoint source) { 85 ConnectPoint source) {
89 super(type, subject, time); 86 super(type, subject, time);
...@@ -102,12 +99,20 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> { ...@@ -102,12 +99,20 @@ public class McastEvent extends AbstractEvent<McastEvent.Type, McastRoute> {
102 } 99 }
103 100
104 /** 101 /**
105 - * The source which has been removed or added. The field may not be set 102 + * The source which has been removed or added.
106 - * if the source has not been detected yet or has been removed.
107 103
108 * @return an optional connect point 104 * @return an optional connect point
109 */ 105 */
110 public Optional<ConnectPoint> source() { 106 public Optional<ConnectPoint> source() {
111 return source; 107 return source;
112 } 108 }
109 +
110 + @Override
111 + public String toString() {
112 + return toStringHelper(this)
113 + .add("type", type())
114 + .add("route", subject())
115 + .add("source", source)
116 + .add("sinks", sink).toString();
117 + }
113 } 118 }
......
...@@ -20,6 +20,7 @@ import com.google.common.base.Objects; ...@@ -20,6 +20,7 @@ import com.google.common.base.Objects;
20 import org.onlab.packet.IpPrefix; 20 import org.onlab.packet.IpPrefix;
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 24
24 /** 25 /**
25 * An entity representing a multicast route consisting of a source 26 * An entity representing a multicast route consisting of a source
...@@ -50,6 +51,9 @@ public class McastRoute { ...@@ -50,6 +51,9 @@ public class McastRoute {
50 private final Type type; 51 private final Type type;
51 52
52 public McastRoute(IpPrefix source, IpPrefix group, Type type) { 53 public McastRoute(IpPrefix source, IpPrefix group, Type type) {
54 + checkNotNull(source, "Multicast route must have a source");
55 + checkNotNull(group, "Multicast route must specify a group address");
56 + checkNotNull(type, "Must indicate what type of route");
53 this.source = source; 57 this.source = source;
54 this.group = group; 58 this.group = group;
55 this.type = type; 59 this.type = type;
......
...@@ -24,7 +24,7 @@ import java.util.List; ...@@ -24,7 +24,7 @@ import java.util.List;
24 * A service interface for maintaining multicast information. 24 * A service interface for maintaining multicast information.
25 */ 25 */
26 @Beta 26 @Beta
27 -public interface MulticastRouteTable { 27 +public interface MulticastRouteService {
28 28
29 /** 29 /**
30 * Adds a route to the information base. 30 * Adds a route to the information base.
...@@ -59,14 +59,6 @@ public interface MulticastRouteTable { ...@@ -59,14 +59,6 @@ public interface MulticastRouteTable {
59 void addSink(McastRoute route, ConnectPoint connectPoint); 59 void addSink(McastRoute route, ConnectPoint connectPoint);
60 60
61 /** 61 /**
62 - * Removes a source connection from the route.
63 - *
64 - * @param route the multicast route
65 - * @param connectPoint a source connect point
66 - */
67 - void removeSource(McastRoute route, ConnectPoint connectPoint);
68 -
69 - /**
70 * Removes a sink from the route. 62 * Removes a sink from the route.
71 * 63 *
72 * @param route the multicast route 64 * @param route the multicast route
......
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 + * External model entities of the multicast RIB.
19 + */
20 +package org.onosproject.net.mcast;
...\ No newline at end of file ...\ No newline at end of file
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.incubator.net.mcast.impl;
17 +
18 +import com.google.common.collect.ImmutableList;
19 +import com.google.common.collect.Lists;
20 +import org.onosproject.net.ConnectPoint;
21 +
22 +import java.util.Collections;
23 +import java.util.List;
24 +
25 +/**
26 + * Simple entity maintaining a mapping between a source and a collection of sink
27 + * connect points.
28 + */
29 +public final class MulticastData {
30 +
31 + private final ConnectPoint source;
32 + private final List<ConnectPoint> sinks;
33 +
34 + private MulticastData() {
35 + this.source = null;
36 + this.sinks = Collections.EMPTY_LIST;
37 + }
38 +
39 + public MulticastData(ConnectPoint source, List<ConnectPoint> sinks) {
40 + this.source = source;
41 + this.sinks = sinks;
42 + }
43 +
44 + public MulticastData(ConnectPoint source, ConnectPoint sink) {
45 + this.source = source;
46 + this.sinks = Lists.newArrayList(sink);
47 + }
48 +
49 + public MulticastData(ConnectPoint source) {
50 + this.source = source;
51 + this.sinks = Lists.newArrayList();
52 + }
53 +
54 + public ConnectPoint source() {
55 + return source;
56 + }
57 +
58 + public List<ConnectPoint> sinks() {
59 + return ImmutableList.copyOf(sinks);
60 + }
61 +
62 + public void appendSink(ConnectPoint sink) {
63 + sinks.add(sink);
64 + }
65 +
66 + public boolean removeSink(ConnectPoint sink) {
67 + return sinks.remove(sink);
68 + }
69 +
70 + public boolean isEmpty() {
71 + return source == null && sinks.size() == 0;
72 + }
73 +
74 + public static MulticastData empty() {
75 + return new MulticastData();
76 + }
77 +
78 +}
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.incubator.net.mcast.impl;
17 +
18 +import org.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Reference;
22 +import org.apache.felix.scr.annotations.ReferenceCardinality;
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;
29 +import org.onosproject.net.ConnectPoint;
30 +import org.onosproject.net.mcast.McastEvent;
31 +import org.onosproject.net.mcast.McastListener;
32 +import org.onosproject.net.mcast.McastRoute;
33 +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;
39 +
40 +import java.util.List;
41 +
42 +import static org.slf4j.LoggerFactory.getLogger;
43 +
44 +/**
45 + * An implementation of a multicast route table.
46 + */
47 +@Component(immediate = true)
48 +@Service
49 +public class MulticastRouteManager
50 + extends AbstractListenerManager<McastEvent, McastListener>
51 + implements MulticastRouteService {
52 + //TODO: add MulticastRouteAdminService
53 +
54 + private static final String MCASTRIB = "mcast-rib-table";
55 +
56 + private Logger log = getLogger(getClass());
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + private StorageService storageService;
60 +
61 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 + private CoreService coreService;
63 +
64 +
65 + protected ApplicationId appId;
66 + protected ConsistentMap<McastRoute, MulticastData> mcastRoutes;
67 +
68 + @Activate
69 + public void activate() {
70 +
71 + eventDispatcher.addSink(McastEvent.class, listenerRegistry);
72 +
73 + appId = coreService.registerApplication("org.onosproject.mcastrib");
74 +
75 + mcastRoutes = storageService.<McastRoute, MulticastData>consistentMapBuilder()
76 + .withApplicationId(appId)
77 + .withName(MCASTRIB)
78 + .withSerializer(Serializer.using(KryoNamespace.newBuilder().register(
79 + MulticastData.class,
80 + McastRoute.class,
81 + McastRoute.Type.class,
82 + IpPrefix.class,
83 + List.class,
84 + ConnectPoint.class
85 + ).build())).build();
86 +
87 + log.info("Started");
88 + }
89 +
90 + @Deactivate
91 + public void deactivate() {
92 + log.info("Stopped");
93 + }
94 +
95 + @Override
96 + public void add(McastRoute route) {
97 + mcastRoutes.put(route, MulticastData.empty());
98 + post(new McastEvent(McastEvent.Type.ROUTE_ADDED, route, null, null));
99 + }
100 +
101 + @Override
102 + public void remove(McastRoute route) {
103 + mcastRoutes.remove(route);
104 + post(new McastEvent(McastEvent.Type.ROUTE_REMOVED, route, null, null));
105 + }
106 +
107 + @Override
108 + public void addSource(McastRoute route, ConnectPoint connectPoint) {
109 + Versioned<MulticastData> d = mcastRoutes.compute(route, (k, v) -> {
110 + if (v.isEmpty()) {
111 + return new MulticastData(connectPoint);
112 + } else {
113 + log.warn("Route {} is already in use.", route);
114 + return v;
115 + }
116 + });
117 +
118 + if (d != null) {
119 + post(new McastEvent(McastEvent.Type.SOURCE_ADDED,
120 + route, null, connectPoint));
121 + }
122 + }
123 +
124 + @Override
125 + public void addSink(McastRoute route, ConnectPoint connectPoint) {
126 + mcastRoutes.compute(route, (k, v) -> {
127 + if (!v.isEmpty()) {
128 + v.appendSink(connectPoint);
129 + post(new McastEvent(McastEvent.Type.SINK_ADDED, route,
130 + connectPoint, v.source()));
131 + } else {
132 + log.warn("Route {} does not exist");
133 + }
134 + return v;
135 + });
136 + }
137 +
138 +
139 + @Override
140 + public void removeSink(McastRoute route, ConnectPoint connectPoint) {
141 + mcastRoutes.compute(route, (k, v) -> {
142 + if (v.removeSink(connectPoint)) {
143 + post(new McastEvent(McastEvent.Type.SINK_REMOVED, route,
144 + connectPoint, v.source()));
145 + }
146 + return v;
147 + });
148 + }
149 +
150 + @Override
151 + public ConnectPoint fetchSource(McastRoute route) {
152 + MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route,
153 + MulticastData.empty());
154 + return d.source();
155 + }
156 +
157 + @Override
158 + public List<ConnectPoint> fetchSinks(McastRoute route) {
159 + MulticastData d = mcastRoutes.asJavaMap().getOrDefault(route,
160 + MulticastData.empty());
161 + return d.sinks();
162 + }
163 +}
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 + * An implementation of a multicast RIB.
19 + */
20 +package org.onosproject.incubator.net.mcast.impl;
...\ No newline at end of file ...\ No newline at end of file
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.incubator.net.mcast.impl;
17 +
18 +import com.google.common.collect.Lists;
19 +import org.junit.After;
20 +import org.junit.Before;
21 +import org.junit.Test;
22 +import org.onlab.junit.TestUtils;
23 +import org.onlab.packet.IpPrefix;
24 +import org.onosproject.common.event.impl.TestEventDispatcher;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.core.CoreService;
27 +import org.onosproject.core.DefaultApplicationId;
28 +import org.onosproject.core.IdGenerator;
29 +import org.onosproject.core.Version;
30 +import org.onosproject.net.ConnectPoint;
31 +import org.onosproject.net.PortNumber;
32 +import org.onosproject.net.mcast.McastEvent;
33 +import org.onosproject.net.mcast.McastListener;
34 +import org.onosproject.net.mcast.McastRoute;
35 +import org.onosproject.store.service.TestStorageService;
36 +
37 +import java.util.List;
38 +import java.util.Set;
39 +
40 +import static junit.framework.Assert.fail;
41 +import static junit.framework.TestCase.assertEquals;
42 +import static org.onosproject.net.NetTestTools.did;
43 +import static org.onosproject.net.NetTestTools.injectEventDispatcher;
44 +
45 +/**
46 + * Tests for the multicast RIB.
47 + */
48 +public class MulticastRouteManagerTest {
49 +
50 + McastRoute r1 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"),
51 + IpPrefix.valueOf("1.1.1.2/8"),
52 + McastRoute.Type.IGMP);
53 +
54 + McastRoute r11 = new McastRoute(IpPrefix.valueOf("1.1.1.1/8"),
55 + IpPrefix.valueOf("1.1.1.2/8"),
56 + McastRoute.Type.STATIC);
57 +
58 + McastRoute r2 = new McastRoute(IpPrefix.valueOf("2.2.2.1/8"),
59 + IpPrefix.valueOf("2.2.2.2/8"),
60 + McastRoute.Type.PIM);
61 +
62 + ConnectPoint cp1 = new ConnectPoint(did("1"), PortNumber.portNumber(1));
63 +
64 + ConnectPoint cp2 = new ConnectPoint(did("2"), PortNumber.portNumber(2));
65 +
66 + private TestMulticastListener listener = new TestMulticastListener();
67 +
68 + private MulticastRouteManager manager;
69 +
70 + private List<McastEvent> events;
71 +
72 + @Before
73 + public void setUp() throws Exception {
74 + manager = new MulticastRouteManager();
75 + injectEventDispatcher(manager, new TestEventDispatcher());
76 + TestUtils.setField(manager, "storageService", new TestStorageService());
77 + TestUtils.setField(manager, "coreService", new TestCoreService());
78 + events = Lists.newArrayList();
79 + manager.activate();
80 + manager.addListener(listener);
81 + }
82 +
83 + @After
84 + public void tearDown() {
85 + manager.removeListener(listener);
86 + manager.deactivate();
87 + }
88 +
89 + @Test
90 + public void testAdd() {
91 + manager.add(r1);
92 +
93 + assertEquals("Add failed", manager.mcastRoutes.size(), 1);
94 + validateEvents(McastEvent.Type.ROUTE_ADDED);
95 + }
96 +
97 + @Test
98 + public void testRemove() {
99 + manager.add(r1);
100 +
101 + manager.remove(r1);
102 +
103 + assertEquals("Remove failed", manager.mcastRoutes.size(), 0);
104 + validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.ROUTE_REMOVED);
105 + }
106 +
107 + @Test
108 + public void testAddSource() {
109 + manager.add(r1);
110 +
111 + manager.addSource(r1, cp1);
112 +
113 + validateEvents(McastEvent.Type.ROUTE_ADDED, McastEvent.Type.SOURCE_ADDED);
114 + assertEquals("Route is not equal", cp1, manager.fetchSource(r1));
115 + }
116 +
117 + @Test
118 + public void testAddSink() {
119 + manager.add(r1);
120 +
121 + manager.addSource(r1, cp1);
122 + manager.addSink(r1, cp1);
123 +
124 + validateEvents(McastEvent.Type.ROUTE_ADDED,
125 + McastEvent.Type.SOURCE_ADDED,
126 + McastEvent.Type.SINK_ADDED);
127 + assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1));
128 + }
129 +
130 + @Test
131 + public void testRemoveSink() {
132 + manager.add(r1);
133 +
134 + manager.addSource(r1, cp1);
135 + manager.addSink(r1, cp1);
136 + manager.addSink(r1, cp2);
137 + manager.removeSink(r1, cp2);
138 +
139 + validateEvents(McastEvent.Type.ROUTE_ADDED,
140 + McastEvent.Type.SOURCE_ADDED,
141 + McastEvent.Type.SINK_ADDED,
142 + McastEvent.Type.SINK_ADDED,
143 + McastEvent.Type.SINK_REMOVED);
144 + assertEquals("Route is not equal", Lists.newArrayList(cp1), manager.fetchSinks(r1));
145 + }
146 +
147 + private void validateEvents(McastEvent.Type... evs) {
148 + if (events.size() != evs.length) {
149 + fail(String.format("Mismatch number of events# obtained -> %s : expected %s",
150 + events, evs));
151 + }
152 +
153 + for (int i = 0; i < evs.length; i++) {
154 + if (evs[i] != events.get(i).type()) {
155 + fail(String.format("Mismtached events# obtained -> %s : expected %s",
156 + events, evs));
157 + }
158 + }
159 + }
160 +
161 + class TestMulticastListener implements McastListener {
162 +
163 + @Override
164 + public void event(McastEvent event) {
165 + events.add(event);
166 + }
167 + }
168 +
169 + private class TestCoreService implements CoreService {
170 + @Override
171 + public Version version() {
172 + return null;
173 + }
174 +
175 + @Override
176 + public Set<ApplicationId> getAppIds() {
177 + return null;
178 + }
179 +
180 + @Override
181 + public ApplicationId getAppId(Short id) {
182 + return null;
183 + }
184 +
185 + @Override
186 + public ApplicationId getAppId(String name) {
187 + return null;
188 + }
189 +
190 + @Override
191 + public ApplicationId registerApplication(String identifier) {
192 + return new DefaultApplicationId(0, identifier);
193 + }
194 +
195 + @Override
196 + public IdGenerator getIdGenerator(String topic) {
197 + return null;
198 + }
199 + }
200 +}