Srikanth Vavilapalli
Committed by Gerrit Code Review

Distributed group store using eventual consistent map abstraction

Change-Id: I618a0f6fa80e0e25285d7a2026032f09ba90aa70
Showing 25 changed files with 1123 additions and 294 deletions
...@@ -15,11 +15,14 @@ ...@@ -15,11 +15,14 @@
15 */ 15 */
16 package org.onosproject.bgprouter; 16 package org.onosproject.bgprouter;
17 17
18 -import com.google.common.collect.ConcurrentHashMultiset; 18 +import java.util.Collection;
19 -import com.google.common.collect.HashMultimap; 19 +import java.util.Collections;
20 -import com.google.common.collect.Maps; 20 +import java.util.HashMap;
21 -import com.google.common.collect.Multimap; 21 +import java.util.HashSet;
22 -import com.google.common.collect.Multiset; 22 +import java.util.Map;
23 +import java.util.Set;
24 +import java.util.stream.Collectors;
25 +
23 import org.apache.felix.scr.annotations.Activate; 26 import org.apache.felix.scr.annotations.Activate;
24 import org.apache.felix.scr.annotations.Component; 27 import org.apache.felix.scr.annotations.Component;
25 import org.apache.felix.scr.annotations.Deactivate; 28 import org.apache.felix.scr.annotations.Deactivate;
...@@ -30,6 +33,7 @@ import org.onlab.packet.IpAddress; ...@@ -30,6 +33,7 @@ import org.onlab.packet.IpAddress;
30 import org.onlab.packet.IpPrefix; 33 import org.onlab.packet.IpPrefix;
31 import org.onlab.packet.MacAddress; 34 import org.onlab.packet.MacAddress;
32 import org.onlab.packet.VlanId; 35 import org.onlab.packet.VlanId;
36 +import org.onlab.util.KryoNamespace;
33 import org.onosproject.config.NetworkConfigService; 37 import org.onosproject.config.NetworkConfigService;
34 import org.onosproject.core.ApplicationId; 38 import org.onosproject.core.ApplicationId;
35 import org.onosproject.core.CoreService; 39 import org.onosproject.core.CoreService;
...@@ -47,12 +51,12 @@ import org.onosproject.net.flow.TrafficSelector; ...@@ -47,12 +51,12 @@ import org.onosproject.net.flow.TrafficSelector;
47 import org.onosproject.net.flow.TrafficTreatment; 51 import org.onosproject.net.flow.TrafficTreatment;
48 import org.onosproject.net.group.DefaultGroupBucket; 52 import org.onosproject.net.group.DefaultGroupBucket;
49 import org.onosproject.net.group.DefaultGroupDescription; 53 import org.onosproject.net.group.DefaultGroupDescription;
54 +import org.onosproject.net.group.DefaultGroupKey;
50 import org.onosproject.net.group.Group; 55 import org.onosproject.net.group.Group;
51 import org.onosproject.net.group.GroupBucket; 56 import org.onosproject.net.group.GroupBucket;
52 import org.onosproject.net.group.GroupBuckets; 57 import org.onosproject.net.group.GroupBuckets;
53 import org.onosproject.net.group.GroupDescription; 58 import org.onosproject.net.group.GroupDescription;
54 import org.onosproject.net.group.GroupEvent; 59 import org.onosproject.net.group.GroupEvent;
55 -import org.onosproject.net.group.GroupKey;
56 import org.onosproject.net.group.GroupListener; 60 import org.onosproject.net.group.GroupListener;
57 import org.onosproject.net.group.GroupService; 61 import org.onosproject.net.group.GroupService;
58 import org.onosproject.net.host.InterfaceIpAddress; 62 import org.onosproject.net.host.InterfaceIpAddress;
...@@ -67,13 +71,11 @@ import org.onosproject.routing.config.RoutingConfigurationService; ...@@ -67,13 +71,11 @@ import org.onosproject.routing.config.RoutingConfigurationService;
67 import org.slf4j.Logger; 71 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory; 72 import org.slf4j.LoggerFactory;
69 73
70 -import java.util.Collection; 74 +import com.google.common.collect.ConcurrentHashMultiset;
71 -import java.util.Collections; 75 +import com.google.common.collect.HashMultimap;
72 -import java.util.HashMap; 76 +import com.google.common.collect.Maps;
73 -import java.util.HashSet; 77 +import com.google.common.collect.Multimap;
74 -import java.util.Map; 78 +import com.google.common.collect.Multiset;
75 -import java.util.Set;
76 -import java.util.stream.Collectors;
77 79
78 /** 80 /**
79 * BgpRouter component. 81 * BgpRouter component.
...@@ -126,7 +128,7 @@ public class BgpRouter { ...@@ -126,7 +128,7 @@ public class BgpRouter {
126 private final Map<IpAddress, NextHop> nextHops = Maps.newHashMap(); 128 private final Map<IpAddress, NextHop> nextHops = Maps.newHashMap();
127 129
128 // Stores FIB updates that are waiting for groups to be set up 130 // Stores FIB updates that are waiting for groups to be set up
129 - private final Multimap<GroupKey, FibEntry> pendingUpdates = HashMultimap.create(); 131 + private final Multimap<NextHopGroupKey, FibEntry> pendingUpdates = HashMultimap.create();
130 132
131 // Device id of data-plane switch - should be learned from config 133 // Device id of data-plane switch - should be learned from config
132 private DeviceId deviceId; 134 private DeviceId deviceId;
...@@ -143,6 +145,11 @@ public class BgpRouter { ...@@ -143,6 +145,11 @@ public class BgpRouter {
143 145
144 private InternalTableHandler provisionStaticTables = new InternalTableHandler(); 146 private InternalTableHandler provisionStaticTables = new InternalTableHandler();
145 147
148 + private KryoNamespace.Builder appKryo = new KryoNamespace.Builder()
149 + .register(IpAddress.Version.class)
150 + .register(IpAddress.class)
151 + .register(NextHopGroupKey.class);
152 +
146 @Activate 153 @Activate
147 protected void activate() { 154 protected void activate() {
148 appId = coreService.registerApplication(BGP_ROUTER_APP); 155 appId = coreService.registerApplication(BGP_ROUTER_APP);
...@@ -210,7 +217,9 @@ public class BgpRouter { ...@@ -210,7 +217,9 @@ public class BgpRouter {
210 Group group; 217 Group group;
211 synchronized (pendingUpdates) { 218 synchronized (pendingUpdates) {
212 NextHop nextHop = nextHops.get(entry.nextHopIp()); 219 NextHop nextHop = nextHops.get(entry.nextHopIp());
213 - group = groupService.getGroup(deviceId, nextHop.group()); 220 + group = groupService.getGroup(deviceId,
221 + new DefaultGroupKey(
222 + appKryo.build().serialize(nextHop.group())));
214 223
215 if (group == null) { 224 if (group == null) {
216 log.debug("Adding pending flow {}", update.entry()); 225 log.debug("Adding pending flow {}", update.entry());
...@@ -309,7 +318,7 @@ public class BgpRouter { ...@@ -309,7 +318,7 @@ public class BgpRouter {
309 GroupDescription.Type.INDIRECT, 318 GroupDescription.Type.INDIRECT,
310 new GroupBuckets(Collections 319 new GroupBuckets(Collections
311 .singletonList(bucket)), 320 .singletonList(bucket)),
312 - groupKey, 321 + new DefaultGroupKey(appKryo.build().serialize(groupKey)),
313 appId); 322 appId);
314 323
315 groupService.addGroup(groupDescription); 324 groupService.addGroup(groupDescription);
...@@ -329,7 +338,10 @@ public class BgpRouter { ...@@ -329,7 +338,10 @@ public class BgpRouter {
329 return null; 338 return null;
330 } 339 }
331 340
332 - Group group = groupService.getGroup(deviceId, nextHop.group()); 341 + Group group = groupService.getGroup(deviceId,
342 + new DefaultGroupKey(appKryo.
343 + build().
344 + serialize(nextHop.group())));
333 345
334 // FIXME disabling group deletes for now until we verify the logic is OK 346 // FIXME disabling group deletes for now until we verify the logic is OK
335 /*if (nextHopsCount.remove(nextHopIp, 1) <= 1) { 347 /*if (nextHopsCount.remove(nextHopIp, 1) <= 1) {
...@@ -339,7 +351,9 @@ public class BgpRouter { ...@@ -339,7 +351,9 @@ public class BgpRouter {
339 351
340 nextHops.remove(nextHopIp); 352 nextHops.remove(nextHopIp);
341 353
342 - groupService.removeGroup(deviceId, nextHop.group(), appId); 354 + groupService.removeGroup(deviceId,
355 + new DefaultGroupKey(appKryo.build().serialize(nextHop.group())),
356 + appId);
343 }*/ 357 }*/
344 358
345 return group; 359 return group;
...@@ -699,8 +713,10 @@ public class BgpRouter { ...@@ -699,8 +713,10 @@ public class BgpRouter {
699 event.type() == GroupEvent.Type.GROUP_UPDATED) { 713 event.type() == GroupEvent.Type.GROUP_UPDATED) {
700 synchronized (pendingUpdates) { 714 synchronized (pendingUpdates) {
701 715
716 + NextHopGroupKey nhGroupKey =
717 + appKryo.build().deserialize(group.appCookie().key());
702 Map<FibEntry, Group> entriesToInstall = 718 Map<FibEntry, Group> entriesToInstall =
703 - pendingUpdates.removeAll(group.appCookie()) 719 + pendingUpdates.removeAll(nhGroupKey)
704 .stream() 720 .stream()
705 .collect(Collectors 721 .collect(Collectors
706 .toMap(e -> e, e -> group)); 722 .toMap(e -> e, e -> group));
......
...@@ -15,12 +15,12 @@ ...@@ -15,12 +15,12 @@
15 */ 15 */
16 package org.onosproject.bgprouter; 16 package org.onosproject.bgprouter;
17 17
18 -import com.google.common.base.MoreObjects; 18 +import java.util.Objects;
19 +
19 import org.onlab.packet.IpAddress; 20 import org.onlab.packet.IpAddress;
20 import org.onlab.packet.MacAddress; 21 import org.onlab.packet.MacAddress;
21 -import org.onosproject.net.group.GroupKey;
22 22
23 -import java.util.Objects; 23 +import com.google.common.base.MoreObjects;
24 24
25 /** 25 /**
26 * Represents a next hop for routing, whose MAC address has already been resolved. 26 * Represents a next hop for routing, whose MAC address has already been resolved.
...@@ -29,7 +29,7 @@ public class NextHop { ...@@ -29,7 +29,7 @@ public class NextHop {
29 29
30 private final IpAddress ip; 30 private final IpAddress ip;
31 private final MacAddress mac; 31 private final MacAddress mac;
32 - private final GroupKey group; 32 + private final NextHopGroupKey group;
33 33
34 /** 34 /**
35 * Creates a new next hop. 35 * Creates a new next hop.
...@@ -38,7 +38,7 @@ public class NextHop { ...@@ -38,7 +38,7 @@ public class NextHop {
38 * @param mac next hop's MAC address 38 * @param mac next hop's MAC address
39 * @param group next hop's group 39 * @param group next hop's group
40 */ 40 */
41 - public NextHop(IpAddress ip, MacAddress mac, GroupKey group) { 41 + public NextHop(IpAddress ip, MacAddress mac, NextHopGroupKey group) {
42 this.ip = ip; 42 this.ip = ip;
43 this.mac = mac; 43 this.mac = mac;
44 this.group = group; 44 this.group = group;
...@@ -67,7 +67,7 @@ public class NextHop { ...@@ -67,7 +67,7 @@ public class NextHop {
67 * 67 *
68 * @return group 68 * @return group
69 */ 69 */
70 - public GroupKey group() { 70 + public NextHopGroupKey group() {
71 return group; 71 return group;
72 } 72 }
73 73
......
...@@ -15,18 +15,18 @@ ...@@ -15,18 +15,18 @@
15 */ 15 */
16 package org.onosproject.bgprouter; 16 package org.onosproject.bgprouter;
17 17
18 -import com.google.common.base.MoreObjects; 18 +import static com.google.common.base.Preconditions.checkNotNull;
19 -import org.onlab.packet.IpAddress;
20 -import org.onosproject.net.group.GroupKey;
21 19
22 import java.util.Objects; 20 import java.util.Objects;
23 21
24 -import static com.google.common.base.Preconditions.checkNotNull; 22 +import org.onlab.packet.IpAddress;
23 +
24 +import com.google.common.base.MoreObjects;
25 25
26 /** 26 /**
27 * Identifier for a next hop group. 27 * Identifier for a next hop group.
28 */ 28 */
29 -public class NextHopGroupKey implements GroupKey { 29 +public class NextHopGroupKey {
30 30
31 private final IpAddress address; 31 private final IpAddress address;
32 32
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
22 <parent> 22 <parent>
23 <groupId>org.onosproject</groupId> 23 <groupId>org.onosproject</groupId>
24 <artifactId>onos-apps</artifactId> 24 <artifactId>onos-apps</artifactId>
25 - <version>1.1.0-SNAPSHOT</version> 25 + <version>1.2.0-SNAPSHOT</version>
26 <relativePath>../pom.xml</relativePath> 26 <relativePath>../pom.xml</relativePath>
27 </parent> 27 </parent>
28 28
......
...@@ -124,16 +124,23 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler { ...@@ -124,16 +124,23 @@ public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
124 tBuilder.setOutput(newNeighborLink.src().port()) 124 tBuilder.setOutput(newNeighborLink.src().port())
125 .setEthDst(deviceConfig.getDeviceMac( 125 .setEthDst(deviceConfig.getDeviceMac(
126 newNeighborLink.dst().deviceId())) 126 newNeighborLink.dst().deviceId()))
127 - .setEthSrc(nodeMacAddr) 127 + .setEthSrc(nodeMacAddr);
128 - .pushMpls() 128 + if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
129 - .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 129 + tBuilder.pushMpls()
130 + .setMpls(MplsLabel.
131 + mplsLabel(ns.getEdgeLabel()));
132 + }
130 GroupBucket updatedBucket = DefaultGroupBucket. 133 GroupBucket updatedBucket = DefaultGroupBucket.
131 createSelectGroupBucket(tBuilder.build()); 134 createSelectGroupBucket(tBuilder.build());
132 GroupBuckets updatedBuckets = new GroupBuckets( 135 GroupBuckets updatedBuckets = new GroupBuckets(
133 Arrays.asList(updatedBucket)); 136 Arrays.asList(updatedBucket));
134 log.debug("newPortToExistingNeighborAtEdgeRouter: " 137 log.debug("newPortToExistingNeighborAtEdgeRouter: "
135 + "groupService.addBucketsToGroup for neighborset{}", ns); 138 + "groupService.addBucketsToGroup for neighborset{}", ns);
136 - groupService.addBucketsToGroup(deviceId, ns, updatedBuckets, ns, appId); 139 + groupService.addBucketsToGroup(deviceId,
140 + getGroupKey(ns),
141 + updatedBuckets,
142 + getGroupKey(ns),
143 + appId);
137 } 144 }
138 } 145 }
139 146
......
...@@ -18,6 +18,7 @@ package org.onosproject.grouphandler; ...@@ -18,6 +18,7 @@ package org.onosproject.grouphandler;
18 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static org.slf4j.LoggerFactory.getLogger; 19 import static org.slf4j.LoggerFactory.getLogger;
20 20
21 +import java.net.URI;
21 import java.util.ArrayList; 22 import java.util.ArrayList;
22 import java.util.Arrays; 23 import java.util.Arrays;
23 import java.util.HashMap; 24 import java.util.HashMap;
...@@ -27,6 +28,7 @@ import java.util.Set; ...@@ -27,6 +28,7 @@ import java.util.Set;
27 28
28 import org.onlab.packet.MacAddress; 29 import org.onlab.packet.MacAddress;
29 import org.onlab.packet.MplsLabel; 30 import org.onlab.packet.MplsLabel;
31 +import org.onlab.util.KryoNamespace;
30 import org.onosproject.core.ApplicationId; 32 import org.onosproject.core.ApplicationId;
31 import org.onosproject.net.DeviceId; 33 import org.onosproject.net.DeviceId;
32 import org.onosproject.net.Link; 34 import org.onosproject.net.Link;
...@@ -35,6 +37,7 @@ import org.onosproject.net.flow.DefaultTrafficTreatment; ...@@ -35,6 +37,7 @@ import org.onosproject.net.flow.DefaultTrafficTreatment;
35 import org.onosproject.net.flow.TrafficTreatment; 37 import org.onosproject.net.flow.TrafficTreatment;
36 import org.onosproject.net.group.DefaultGroupBucket; 38 import org.onosproject.net.group.DefaultGroupBucket;
37 import org.onosproject.net.group.DefaultGroupDescription; 39 import org.onosproject.net.group.DefaultGroupDescription;
40 +import org.onosproject.net.group.DefaultGroupKey;
38 import org.onosproject.net.group.Group; 41 import org.onosproject.net.group.Group;
39 import org.onosproject.net.group.GroupBucket; 42 import org.onosproject.net.group.GroupBucket;
40 import org.onosproject.net.group.GroupBuckets; 43 import org.onosproject.net.group.GroupBuckets;
...@@ -71,6 +74,16 @@ public class DefaultGroupHandler { ...@@ -71,6 +74,16 @@ public class DefaultGroupHandler {
71 new HashMap<PortNumber, DeviceId>(); 74 new HashMap<PortNumber, DeviceId>();
72 75
73 private GroupListener listener = new InternalGroupListener(); 76 private GroupListener listener = new InternalGroupListener();
77 + protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
78 + .register(URI.class)
79 + .register(HashSet.class)
80 + .register(DeviceId.class)
81 + .register(PortNumber.class)
82 + .register(NeighborSet.class)
83 + .register(PolicyGroupIdentifier.class)
84 + .register(PolicyGroupParams.class)
85 + .register(GroupBucketIdentifier.class)
86 + .register(GroupBucketIdentifier.BucketOutputType.class);
74 87
75 protected DefaultGroupHandler(DeviceId deviceId, 88 protected DefaultGroupHandler(DeviceId deviceId,
76 ApplicationId appId, 89 ApplicationId appId,
...@@ -185,9 +198,11 @@ public class DefaultGroupHandler { ...@@ -185,9 +198,11 @@ public class DefaultGroupHandler {
185 tBuilder.setOutput(port) 198 tBuilder.setOutput(port)
186 .setEthDst(deviceConfig.getDeviceMac( 199 .setEthDst(deviceConfig.getDeviceMac(
187 portDeviceMap.get(port))) 200 portDeviceMap.get(port)))
188 - .setEthSrc(nodeMacAddr) 201 + .setEthSrc(nodeMacAddr);
189 - .pushMpls() 202 + if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
203 + tBuilder.pushMpls()
190 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 204 .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel()));
205 + }
191 GroupBucket removeBucket = DefaultGroupBucket. 206 GroupBucket removeBucket = DefaultGroupBucket.
192 createSelectGroupBucket(tBuilder.build()); 207 createSelectGroupBucket(tBuilder.build());
193 GroupBuckets removeBuckets = new GroupBuckets( 208 GroupBuckets removeBuckets = new GroupBuckets(
...@@ -196,9 +211,9 @@ public class DefaultGroupHandler { ...@@ -196,9 +211,9 @@ public class DefaultGroupHandler {
196 + "groupService.removeBucketsFromGroup " 211 + "groupService.removeBucketsFromGroup "
197 + "for neighborset{}", deviceId, ns); 212 + "for neighborset{}", deviceId, ns);
198 groupService.removeBucketsFromGroup(deviceId, 213 groupService.removeBucketsFromGroup(deviceId,
199 - ns, 214 + getGroupKey(ns),
200 removeBuckets, 215 removeBuckets,
201 - ns, 216 + getGroupKey(ns),
202 appId); 217 appId);
203 } 218 }
204 219
...@@ -331,9 +346,12 @@ public class DefaultGroupHandler { ...@@ -331,9 +346,12 @@ public class DefaultGroupHandler {
331 DefaultTrafficTreatment.builder(); 346 DefaultTrafficTreatment.builder();
332 tBuilder.setOutput(sp) 347 tBuilder.setOutput(sp)
333 .setEthDst(deviceConfig.getDeviceMac(d)) 348 .setEthDst(deviceConfig.getDeviceMac(d))
334 - .setEthSrc(nodeMacAddr) 349 + .setEthSrc(nodeMacAddr);
335 - .pushMpls() 350 + if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
336 - .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 351 + tBuilder.pushMpls()
352 + .setMpls(MplsLabel.
353 + mplsLabel(ns.getEdgeLabel()));
354 + }
337 buckets.add(DefaultGroupBucket.createSelectGroupBucket( 355 buckets.add(DefaultGroupBucket.createSelectGroupBucket(
338 tBuilder.build())); 356 tBuilder.build()));
339 } 357 }
...@@ -343,7 +361,7 @@ public class DefaultGroupHandler { ...@@ -343,7 +361,7 @@ public class DefaultGroupHandler {
343 deviceId, 361 deviceId,
344 Group.Type.SELECT, 362 Group.Type.SELECT,
345 groupBuckets, 363 groupBuckets,
346 - ns, 364 + getGroupKey(ns),
347 appId); 365 appId);
348 log.debug("createGroupsFromNeighborsets: " 366 log.debug("createGroupsFromNeighborsets: "
349 + "groupService.addGroup for neighborset{}", ns); 367 + "groupService.addGroup for neighborset{}", ns);
...@@ -386,4 +404,8 @@ public class DefaultGroupHandler { ...@@ -386,4 +404,8 @@ public class DefaultGroupHandler {
386 handleGroupEvent(event); 404 handleGroupEvent(event);
387 } 405 }
388 } 406 }
407 +
408 + protected GroupKey getGroupKey(Object obj) {
409 + return new DefaultGroupKey(kryo.build().serialize(obj));
410 + }
389 } 411 }
......
...@@ -17,8 +17,10 @@ package org.onosproject.grouphandler; ...@@ -17,8 +17,10 @@ package org.onosproject.grouphandler;
17 17
18 import static org.slf4j.LoggerFactory.getLogger; 18 import static org.slf4j.LoggerFactory.getLogger;
19 19
20 +import java.net.URI;
20 import java.util.Arrays; 21 import java.util.Arrays;
21 import java.util.HashMap; 22 import java.util.HashMap;
23 +import java.util.HashSet;
22 import java.util.List; 24 import java.util.List;
23 25
24 import org.apache.felix.scr.annotations.Activate; 26 import org.apache.felix.scr.annotations.Activate;
...@@ -27,10 +29,13 @@ import org.apache.felix.scr.annotations.Deactivate; ...@@ -27,10 +29,13 @@ import org.apache.felix.scr.annotations.Deactivate;
27 import org.apache.felix.scr.annotations.Reference; 29 import org.apache.felix.scr.annotations.Reference;
28 import org.apache.felix.scr.annotations.ReferenceCardinality; 30 import org.apache.felix.scr.annotations.ReferenceCardinality;
29 import org.onlab.packet.MacAddress; 31 import org.onlab.packet.MacAddress;
32 +import org.onlab.util.KryoNamespace;
30 import org.onosproject.core.ApplicationId; 33 import org.onosproject.core.ApplicationId;
31 import org.onosproject.core.CoreService; 34 import org.onosproject.core.CoreService;
35 +import org.onosproject.mastership.MastershipService;
32 import org.onosproject.net.Device; 36 import org.onosproject.net.Device;
33 import org.onosproject.net.DeviceId; 37 import org.onosproject.net.DeviceId;
38 +import org.onosproject.net.MastershipRole;
34 import org.onosproject.net.device.DeviceEvent; 39 import org.onosproject.net.device.DeviceEvent;
35 import org.onosproject.net.device.DeviceListener; 40 import org.onosproject.net.device.DeviceListener;
36 import org.onosproject.net.device.DeviceService; 41 import org.onosproject.net.device.DeviceService;
...@@ -69,10 +74,18 @@ public class DefaultGroupHandlerApp { ...@@ -69,10 +74,18 @@ public class DefaultGroupHandlerApp {
69 protected GroupService groupService; 74 protected GroupService groupService;
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected CoreService coreService; 76 protected CoreService coreService;
77 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 + protected MastershipService mastershipService;
72 79
73 private DeviceListener deviceListener = new InternalDeviceListener(); 80 private DeviceListener deviceListener = new InternalDeviceListener();
74 private LinkListener linkListener = new InternalLinkListener(); 81 private LinkListener linkListener = new InternalLinkListener();
75 82
83 + protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
84 + .register(URI.class)
85 + .register(HashSet.class)
86 + .register(DeviceId.class)
87 + .register(NeighborSet.class);
88 +
76 @Activate 89 @Activate
77 public void activate() { 90 public void activate() {
78 appId = coreService.registerApplication("org.onosproject.defaultgrouphandler"); 91 appId = coreService.registerApplication("org.onosproject.defaultgrouphandler");
...@@ -80,6 +93,8 @@ public class DefaultGroupHandlerApp { ...@@ -80,6 +93,8 @@ public class DefaultGroupHandlerApp {
80 deviceService.addListener(deviceListener); 93 deviceService.addListener(deviceListener);
81 linkService.addListener(linkListener); 94 linkService.addListener(linkListener);
82 for (Device device: deviceService.getDevices()) { 95 for (Device device: deviceService.getDevices()) {
96 + if (mastershipService.
97 + getLocalRole(device.id()) == MastershipRole.MASTER) {
83 log.debug("Initiating default group handling for {}", device.id()); 98 log.debug("Initiating default group handling for {}", device.id());
84 DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device.id(), 99 DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device.id(),
85 appId, 100 appId,
...@@ -88,6 +103,13 @@ public class DefaultGroupHandlerApp { ...@@ -88,6 +103,13 @@ public class DefaultGroupHandlerApp {
88 groupService); 103 groupService);
89 dgh.createGroups(); 104 dgh.createGroups();
90 dghMap.put(device.id(), dgh); 105 dghMap.put(device.id(), dgh);
106 + } else {
107 + log.debug("Activate: Local role {} "
108 + + "is not MASTER for device {}",
109 + mastershipService.
110 + getLocalRole(device.id()),
111 + device.id());
112 + }
91 } 113 }
92 log.info("Activated"); 114 log.info("Activated");
93 } 115 }
...@@ -165,6 +187,14 @@ public class DefaultGroupHandlerApp { ...@@ -165,6 +187,14 @@ public class DefaultGroupHandlerApp {
165 187
166 @Override 188 @Override
167 public void event(DeviceEvent event) { 189 public void event(DeviceEvent event) {
190 + if (mastershipService.
191 + getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
192 + log.debug("Local role {} is not MASTER for device {}",
193 + mastershipService.
194 + getLocalRole(event.subject().id()),
195 + event.subject().id());
196 + return;
197 + }
168 switch (event.type()) { 198 switch (event.type()) {
169 case DEVICE_ADDED: 199 case DEVICE_ADDED:
170 log.debug("Initiating default group handling for {}", event.subject().id()); 200 log.debug("Initiating default group handling for {}", event.subject().id());
...@@ -193,6 +223,16 @@ public class DefaultGroupHandlerApp { ...@@ -193,6 +223,16 @@ public class DefaultGroupHandlerApp {
193 223
194 @Override 224 @Override
195 public void event(LinkEvent event) { 225 public void event(LinkEvent event) {
226 + if (mastershipService.
227 + getLocalRole(event.subject().src().deviceId()) !=
228 + MastershipRole.MASTER) {
229 + log.debug("InternalLinkListener: Local role {} "
230 + + "is not MASTER for device {}",
231 + mastershipService.
232 + getLocalRole(event.subject().src().deviceId()),
233 + event.subject().src().deviceId());
234 + return;
235 + }
196 switch (event.type()) { 236 switch (event.type()) {
197 case LINK_ADDED: 237 case LINK_ADDED:
198 if (dghMap.get(event.subject().src().deviceId()) != null) { 238 if (dghMap.get(event.subject().src().deviceId()) != null) {
......
...@@ -112,16 +112,23 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler { ...@@ -112,16 +112,23 @@ public class DefaultTransitGroupHandler extends DefaultGroupHandler {
112 tBuilder.setOutput(newNeighborLink.src().port()) 112 tBuilder.setOutput(newNeighborLink.src().port())
113 .setEthDst(deviceConfig.getDeviceMac( 113 .setEthDst(deviceConfig.getDeviceMac(
114 newNeighborLink.dst().deviceId())) 114 newNeighborLink.dst().deviceId()))
115 - .setEthSrc(nodeMacAddr) 115 + .setEthSrc(nodeMacAddr);
116 - .pushMpls() 116 + if (ns.getEdgeLabel() != NeighborSet.NO_EDGE_LABEL) {
117 - .setMpls(MplsLabel.mplsLabel(ns.getEdgeLabel())); 117 + tBuilder.pushMpls()
118 + .setMpls(MplsLabel.
119 + mplsLabel(ns.getEdgeLabel()));
120 + }
118 GroupBucket updatedBucket = DefaultGroupBucket. 121 GroupBucket updatedBucket = DefaultGroupBucket.
119 createSelectGroupBucket(tBuilder.build()); 122 createSelectGroupBucket(tBuilder.build());
120 GroupBuckets updatedBuckets = new GroupBuckets( 123 GroupBuckets updatedBuckets = new GroupBuckets(
121 Arrays.asList(updatedBucket)); 124 Arrays.asList(updatedBucket));
122 log.debug("newPortToExistingNeighborAtEdgeRouter: " 125 log.debug("newPortToExistingNeighborAtEdgeRouter: "
123 + "groupService.addBucketsToGroup for neighborset{}", ns); 126 + "groupService.addBucketsToGroup for neighborset{}", ns);
124 - groupService.addBucketsToGroup(deviceId, ns, updatedBuckets, ns, appId); 127 + groupService.addBucketsToGroup(deviceId,
128 + getGroupKey(ns),
129 + updatedBuckets,
130 + getGroupKey(ns),
131 + appId);
125 } 132 }
126 } 133 }
127 134
......
...@@ -18,7 +18,6 @@ package org.onosproject.grouphandler; ...@@ -18,7 +18,6 @@ package org.onosproject.grouphandler;
18 import static com.google.common.base.Preconditions.checkNotNull; 18 import static com.google.common.base.Preconditions.checkNotNull;
19 19
20 import org.onosproject.net.PortNumber; 20 import org.onosproject.net.PortNumber;
21 -import org.onosproject.net.group.GroupKey;
22 21
23 /** 22 /**
24 * Representation of policy group bucket identifier. Not exposed to 23 * Representation of policy group bucket identifier. Not exposed to
...@@ -28,7 +27,7 @@ public class GroupBucketIdentifier { ...@@ -28,7 +27,7 @@ public class GroupBucketIdentifier {
28 private int label; 27 private int label;
29 private BucketOutputType type; 28 private BucketOutputType type;
30 private PortNumber outPort; 29 private PortNumber outPort;
31 - private GroupKey outGroup; 30 + private PolicyGroupIdentifier outGroup;
32 31
33 protected enum BucketOutputType { 32 protected enum BucketOutputType {
34 PORT, 33 PORT,
...@@ -44,7 +43,7 @@ public class GroupBucketIdentifier { ...@@ -44,7 +43,7 @@ public class GroupBucketIdentifier {
44 } 43 }
45 44
46 protected GroupBucketIdentifier(int label, 45 protected GroupBucketIdentifier(int label,
47 - GroupKey outGroup) { 46 + PolicyGroupIdentifier outGroup) {
48 this.label = label; 47 this.label = label;
49 this.type = BucketOutputType.GROUP; 48 this.type = BucketOutputType.GROUP;
50 this.outPort = null; 49 this.outPort = null;
...@@ -63,7 +62,7 @@ public class GroupBucketIdentifier { ...@@ -63,7 +62,7 @@ public class GroupBucketIdentifier {
63 return this.outPort; 62 return this.outPort;
64 } 63 }
65 64
66 - protected GroupKey outGroup() { 65 + protected PolicyGroupIdentifier outGroup() {
67 return this.outGroup; 66 return this.outGroup;
68 } 67 }
69 } 68 }
......
...@@ -23,7 +23,6 @@ import java.util.Objects; ...@@ -23,7 +23,6 @@ import java.util.Objects;
23 import java.util.Set; 23 import java.util.Set;
24 24
25 import org.onosproject.net.DeviceId; 25 import org.onosproject.net.DeviceId;
26 -import org.onosproject.net.group.GroupKey;
27 26
28 /** 27 /**
29 * Representation of a set of neighbor switch dpids along with edge node 28 * Representation of a set of neighbor switch dpids along with edge node
...@@ -31,9 +30,10 @@ import org.onosproject.net.group.GroupKey; ...@@ -31,9 +30,10 @@ import org.onosproject.net.group.GroupKey;
31 * ECMP-group that hashes packets to a set of ports connecting to the 30 * ECMP-group that hashes packets to a set of ports connecting to the
32 * neighbors in this set. 31 * neighbors in this set.
33 */ 32 */
34 -public class NeighborSet implements GroupKey { 33 +public class NeighborSet {
35 private final Set<DeviceId> neighbors; 34 private final Set<DeviceId> neighbors;
36 private final int edgeLabel; 35 private final int edgeLabel;
36 + public static final int NO_EDGE_LABEL = -1;
37 37
38 /** 38 /**
39 * Constructor with set of neighbors. Edge label is 39 * Constructor with set of neighbors. Edge label is
...@@ -43,7 +43,7 @@ public class NeighborSet implements GroupKey { ...@@ -43,7 +43,7 @@ public class NeighborSet implements GroupKey {
43 */ 43 */
44 public NeighborSet(Set<DeviceId> neighbors) { 44 public NeighborSet(Set<DeviceId> neighbors) {
45 checkNotNull(neighbors); 45 checkNotNull(neighbors);
46 - this.edgeLabel = -1; 46 + this.edgeLabel = NO_EDGE_LABEL;
47 this.neighbors = new HashSet<DeviceId>(); 47 this.neighbors = new HashSet<DeviceId>();
48 this.neighbors.addAll(neighbors); 48 this.neighbors.addAll(neighbors);
49 } 49 }
...@@ -65,7 +65,7 @@ public class NeighborSet implements GroupKey { ...@@ -65,7 +65,7 @@ public class NeighborSet implements GroupKey {
65 * Default constructor for kryo serialization. 65 * Default constructor for kryo serialization.
66 */ 66 */
67 public NeighborSet() { 67 public NeighborSet() {
68 - this.edgeLabel = -1; 68 + this.edgeLabel = NO_EDGE_LABEL;
69 this.neighbors = new HashSet<DeviceId>(); 69 this.neighbors = new HashSet<DeviceId>();
70 } 70 }
71 71
......
...@@ -37,7 +37,6 @@ import org.onosproject.net.group.GroupBucket; ...@@ -37,7 +37,6 @@ import org.onosproject.net.group.GroupBucket;
37 import org.onosproject.net.group.GroupBuckets; 37 import org.onosproject.net.group.GroupBuckets;
38 import org.onosproject.net.group.GroupDescription; 38 import org.onosproject.net.group.GroupDescription;
39 import org.onosproject.net.group.GroupEvent; 39 import org.onosproject.net.group.GroupEvent;
40 -import org.onosproject.net.group.GroupKey;
41 import org.onosproject.net.group.GroupService; 40 import org.onosproject.net.group.GroupService;
42 import org.onosproject.net.link.LinkService; 41 import org.onosproject.net.link.LinkService;
43 import org.slf4j.Logger; 42 import org.slf4j.Logger;
...@@ -49,18 +48,17 @@ import org.slf4j.Logger; ...@@ -49,18 +48,17 @@ import org.slf4j.Logger;
49 public class PolicyGroupHandler extends DefaultGroupHandler { 48 public class PolicyGroupHandler extends DefaultGroupHandler {
50 49
51 private final Logger log = getLogger(getClass()); 50 private final Logger log = getLogger(getClass());
52 - private HashMap<GroupKey, GroupKey> dependentGroups = 51 + private HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier> dependentGroups =
53 - new HashMap<GroupKey, GroupKey>(); 52 + new HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier>();
54 53
55 /** 54 /**
56 - * Creates policy group handler object. 55 + * Policy group handler constructor.
57 * 56 *
58 * @param deviceId device identifier 57 * @param deviceId device identifier
59 * @param appId application identifier 58 * @param appId application identifier
60 * @param config interface to retrieve the device properties 59 * @param config interface to retrieve the device properties
61 * @param linkService link service object 60 * @param linkService link service object
62 * @param groupService group service object 61 * @param groupService group service object
63 - * @return policy group handler type
64 */ 62 */
65 public PolicyGroupHandler(DeviceId deviceId, 63 public PolicyGroupHandler(DeviceId deviceId,
66 ApplicationId appId, 64 ApplicationId appId,
...@@ -175,9 +173,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -175,9 +173,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
175 tBuilder.setOutput(bucketId.outPort()) 173 tBuilder.setOutput(bucketId.outPort())
176 .setEthDst(deviceConfig. 174 .setEthDst(deviceConfig.
177 getDeviceMac(neighbor)) 175 getDeviceMac(neighbor))
178 - .setEthSrc(nodeMacAddr) 176 + .setEthSrc(nodeMacAddr);
179 - .pushMpls() 177 + if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
178 + tBuilder.pushMpls()
180 .setMpls(MplsLabel.mplsLabel(bucketId.label())); 179 .setMpls(MplsLabel.mplsLabel(bucketId.label()));
180 + }
181 //TODO: BoS 181 //TODO: BoS
182 outBuckets.add(DefaultGroupBucket. 182 outBuckets.add(DefaultGroupBucket.
183 createSelectGroupBucket(tBuilder.build())); 183 createSelectGroupBucket(tBuilder.build()));
...@@ -196,8 +196,7 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -196,8 +196,7 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
196 protected void handleGroupEvent(GroupEvent event) { 196 protected void handleGroupEvent(GroupEvent event) {
197 if (event.type() == GroupEvent.Type.GROUP_ADDED) { 197 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
198 if (dependentGroups.get(event.subject().appCookie()) != null) { 198 if (dependentGroups.get(event.subject().appCookie()) != null) {
199 - PolicyGroupIdentifier dependentGroupKey = (PolicyGroupIdentifier) 199 + PolicyGroupIdentifier dependentGroupKey = dependentGroups.get(event.subject().appCookie());
200 - dependentGroups.get(event.subject().appCookie());
201 dependentGroups.remove(event.subject().appCookie()); 200 dependentGroups.remove(event.subject().appCookie());
202 boolean fullyResolved = true; 201 boolean fullyResolved = true;
203 for (GroupBucketIdentifier bucketId: 202 for (GroupBucketIdentifier bucketId:
...@@ -217,8 +216,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -217,8 +216,11 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
217 dependentGroupKey.bucketIds()) { 216 dependentGroupKey.bucketIds()) {
218 TrafficTreatment.Builder tBuilder = 217 TrafficTreatment.Builder tBuilder =
219 DefaultTrafficTreatment.builder(); 218 DefaultTrafficTreatment.builder();
219 + if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
220 tBuilder.pushMpls() 220 tBuilder.pushMpls()
221 - .setMpls(MplsLabel.mplsLabel(bucketId.label())); 221 + .setMpls(MplsLabel.
222 + mplsLabel(bucketId.label()));
223 + }
222 //TODO: BoS 224 //TODO: BoS
223 if (bucketId.type() == BucketOutputType.PORT) { 225 if (bucketId.type() == BucketOutputType.PORT) {
224 DeviceId neighbor = portDeviceMap. 226 DeviceId neighbor = portDeviceMap.
...@@ -230,12 +232,14 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -230,12 +232,14 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
230 } else { 232 } else {
231 if (groupService. 233 if (groupService.
232 getGroup(deviceId, 234 getGroup(deviceId,
233 - bucketId.outGroup()) == null) { 235 + getGroupKey(bucketId.
236 + outGroup())) == null) {
234 throw new IllegalStateException(); 237 throw new IllegalStateException();
235 } 238 }
236 GroupId indirectGroupId = groupService. 239 GroupId indirectGroupId = groupService.
237 getGroup(deviceId, 240 getGroup(deviceId,
238 - bucketId.outGroup()).id(); 241 + getGroupKey(bucketId.
242 + outGroup())).id();
239 tBuilder.group(indirectGroupId); 243 tBuilder.group(indirectGroupId);
240 } 244 }
241 outBuckets.add(DefaultGroupBucket. 245 outBuckets.add(DefaultGroupBucket.
...@@ -251,7 +255,7 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -251,7 +255,7 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
251 } 255 }
252 } 256 }
253 257
254 - public GroupKey generatePolicyGroupKey(String id, 258 + public PolicyGroupIdentifier generatePolicyGroupKey(String id,
255 List<PolicyGroupParams> params) { 259 List<PolicyGroupParams> params) {
256 List<GroupBucketIdentifier> bucketIds = new ArrayList<GroupBucketIdentifier>(); 260 List<GroupBucketIdentifier> bucketIds = new ArrayList<GroupBucketIdentifier>();
257 for (PolicyGroupParams param: params) { 261 for (PolicyGroupParams param: params) {
...@@ -320,25 +324,28 @@ public class PolicyGroupHandler extends DefaultGroupHandler { ...@@ -320,25 +324,28 @@ public class PolicyGroupHandler extends DefaultGroupHandler {
320 return innermostGroupkey; 324 return innermostGroupkey;
321 } 325 }
322 326
323 - public void removeGroupChain(GroupKey key) { 327 + public void removeGroupChain(PolicyGroupIdentifier key) {
324 if (!(key instanceof PolicyGroupIdentifier)) { 328 if (!(key instanceof PolicyGroupIdentifier)) {
325 throw new IllegalArgumentException(); 329 throw new IllegalArgumentException();
326 } 330 }
327 - List<GroupKey> groupsToBeDeleted = new ArrayList<GroupKey>(); 331 + List<PolicyGroupIdentifier> groupsToBeDeleted =
332 + new ArrayList<PolicyGroupIdentifier>();
328 groupsToBeDeleted.add(key); 333 groupsToBeDeleted.add(key);
329 334
330 - Iterator<GroupKey> it = groupsToBeDeleted.iterator(); 335 + Iterator<PolicyGroupIdentifier> it =
336 + groupsToBeDeleted.iterator();
331 337
332 while (it.hasNext()) { 338 while (it.hasNext()) {
333 - PolicyGroupIdentifier innerMostGroupKey = 339 + PolicyGroupIdentifier innerMostGroupKey = it.next();
334 - (PolicyGroupIdentifier) it.next();
335 for (GroupBucketIdentifier bucketId: 340 for (GroupBucketIdentifier bucketId:
336 innerMostGroupKey.bucketIds()) { 341 innerMostGroupKey.bucketIds()) {
337 if (bucketId.type() != BucketOutputType.GROUP) { 342 if (bucketId.type() != BucketOutputType.GROUP) {
338 groupsToBeDeleted.add(bucketId.outGroup()); 343 groupsToBeDeleted.add(bucketId.outGroup());
339 } 344 }
340 } 345 }
341 - groupService.removeGroup(deviceId, innerMostGroupKey, appId); 346 + groupService.removeGroup(deviceId,
347 + getGroupKey(innerMostGroupKey),
348 + appId);
342 it.remove(); 349 it.remove();
343 } 350 }
344 } 351 }
......
...@@ -17,14 +17,12 @@ package org.onosproject.grouphandler; ...@@ -17,14 +17,12 @@ package org.onosproject.grouphandler;
17 17
18 import java.util.List; 18 import java.util.List;
19 19
20 -import org.onosproject.net.group.GroupKey;
21 -
22 /** 20 /**
23 * Representation of policy based group identifiers. 21 * Representation of policy based group identifiers.
24 * Opaque to group handler applications and only the outermost 22 * Opaque to group handler applications and only the outermost
25 * policy group identifier in a chain is visible to the applications. 23 * policy group identifier in a chain is visible to the applications.
26 */ 24 */
27 -public class PolicyGroupIdentifier implements GroupKey { 25 +public class PolicyGroupIdentifier {
28 private String id; 26 private String id;
29 private List<PolicyGroupParams> inputParams; 27 private List<PolicyGroupParams> inputParams;
30 private List<GroupBucketIdentifier> bucketIds; 28 private List<GroupBucketIdentifier> bucketIds;
......
...@@ -16,13 +16,11 @@ ...@@ -16,13 +16,11 @@
16 package org.onosproject.net.group; 16 package org.onosproject.net.group;
17 17
18 import static com.google.common.base.MoreObjects.toStringHelper; 18 import static com.google.common.base.MoreObjects.toStringHelper;
19 -import static org.slf4j.LoggerFactory.getLogger;
20 19
21 import java.util.Objects; 20 import java.util.Objects;
22 21
23 import org.onosproject.core.GroupId; 22 import org.onosproject.core.GroupId;
24 import org.onosproject.net.DeviceId; 23 import org.onosproject.net.DeviceId;
25 -import org.slf4j.Logger;
26 24
27 /** 25 /**
28 * ONOS implementation of default group that is stored in the system. 26 * ONOS implementation of default group that is stored in the system.
...@@ -30,9 +28,8 @@ import org.slf4j.Logger; ...@@ -30,9 +28,8 @@ import org.slf4j.Logger;
30 public class DefaultGroup extends DefaultGroupDescription 28 public class DefaultGroup extends DefaultGroupDescription
31 implements Group, StoredGroupEntry { 29 implements Group, StoredGroupEntry {
32 30
33 - private final Logger log = getLogger(getClass());
34 -
35 private GroupState state; 31 private GroupState state;
32 + private boolean isGroupStateAddedFirstTime;
36 private long life; 33 private long life;
37 private long packets; 34 private long packets;
38 private long bytes; 35 private long bytes;
...@@ -215,4 +212,14 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -215,4 +212,14 @@ public class DefaultGroup extends DefaultGroupDescription
215 .add("state", state) 212 .add("state", state)
216 .toString(); 213 .toString();
217 } 214 }
215 +
216 + @Override
217 + public void setIsGroupStateAddedFirstTime(boolean isGroupStateAddedFirstTime) {
218 + this.isGroupStateAddedFirstTime = isGroupStateAddedFirstTime;
219 + }
220 +
221 + @Override
222 + public boolean isGroupStateAddedFirstTime() {
223 + return isGroupStateAddedFirstTime;
224 + }
218 } 225 }
......
...@@ -41,7 +41,8 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -41,7 +41,8 @@ public class DefaultGroupDescription implements GroupDescription {
41 * @param deviceId device identifier 41 * @param deviceId device identifier
42 * @param type type of the group 42 * @param type type of the group
43 * @param buckets immutable list of group bucket 43 * @param buckets immutable list of group bucket
44 - * @param appCookie immutable application cookie to be associated with the group 44 + * @param appCookie immutable application cookie of type DefaultGroupKey
45 + * to be associated with the group
45 * @param appId application id 46 * @param appId application id
46 */ 47 */
47 public DefaultGroupDescription(DeviceId deviceId, 48 public DefaultGroupDescription(DeviceId deviceId,
......
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.group;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import java.util.Arrays;
21 +
22 +/**
23 + * Default implementation of group key interface.
24 + */
25 +public class DefaultGroupKey implements GroupKey {
26 +
27 + private final byte[] key;
28 +
29 + public DefaultGroupKey(byte[] key) {
30 + this.key = checkNotNull(key);
31 + }
32 +
33 + @Override
34 + public byte[] key() {
35 + return key;
36 + }
37 +
38 + @Override
39 + public boolean equals(Object o) {
40 + if (this == o) {
41 + return true;
42 + }
43 + if (!(o instanceof DefaultGroupKey)) {
44 + return false;
45 + }
46 + DefaultGroupKey that = (DefaultGroupKey) o;
47 + return (Arrays.equals(this.key, that.key));
48 + }
49 +
50 + @Override
51 + public int hashCode() {
52 + return Arrays.hashCode(this.key);
53 + }
54 +
55 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -17,8 +17,15 @@ package org.onosproject.net.group; ...@@ -17,8 +17,15 @@ package org.onosproject.net.group;
17 17
18 /** 18 /**
19 * Representation of generalized Key that would be used to store 19 * Representation of generalized Key that would be used to store
20 - * groups in &lt; Key, Value &gt; store. Implementation of this interface 20 + * groups in &lt; Key, Value &gt; store. This key uses a generic
21 - * MUST override "equals()" and "hashcode()" methods. 21 + * byte array so that applications can associate their groups with
22 + * any of their data by translating it into a byte array.
22 */ 23 */
23 public interface GroupKey { 24 public interface GroupKey {
25 + /**
26 + * Returns the byte representation of key.
27 + *
28 + * @return byte array
29 + */
30 + public byte[] key();
24 } 31 }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.net.group; 16 package org.onosproject.net.group;
17 17
18 +import org.onosproject.core.GroupId;
18 import org.onosproject.net.DeviceId; 19 import org.onosproject.net.DeviceId;
19 import org.onosproject.store.Store; 20 import org.onosproject.store.Store;
20 21
...@@ -60,6 +61,15 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { ...@@ -60,6 +61,15 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> {
60 Group getGroup(DeviceId deviceId, GroupKey appCookie); 61 Group getGroup(DeviceId deviceId, GroupKey appCookie);
61 62
62 /** 63 /**
64 + * Returns the stored group entry for an id.
65 + *
66 + * @param deviceId the device ID
67 + * @param groupId the group identifier
68 + * @return a group associated with the key
69 + */
70 + Group getGroup(DeviceId deviceId, GroupId groupId);
71 +
72 + /**
63 * Stores a new group entry using the information from group description. 73 * Stores a new group entry using the information from group description.
64 * 74 *
65 * @param groupDesc group description to be used to store group entry 75 * @param groupDesc group description to be used to store group entry
......
...@@ -29,6 +29,23 @@ public interface StoredGroupEntry extends Group { ...@@ -29,6 +29,23 @@ public interface StoredGroupEntry extends Group {
29 void setState(Group.GroupState newState); 29 void setState(Group.GroupState newState);
30 30
31 /** 31 /**
32 + * Sets if group has transitioned to ADDED state for the first time.
33 + * This is to differentiate state transitions "from PENDING_ADD to ADDED"
34 + * and "from PENDING_UPDATE to ADDED". For internal use only.
35 + *
36 + * @param isGroupAddedFirstTime true if group moves to ADDED state
37 + * for the first time.
38 + */
39 + void setIsGroupStateAddedFirstTime(boolean isGroupAddedFirstTime);
40 +
41 + /**
42 + * Returns the isGroupStateAddedFirstTime value. For internal use only.
43 + *
44 + * @return isGroupStateAddedFirstTime value
45 + */
46 + boolean isGroupStateAddedFirstTime();
47 +
48 + /**
32 * Sets how long this entry has been entered in the system. 49 * Sets how long this entry has been entered in the system.
33 * 50 *
34 * @param life epoch time 51 * @param life epoch time
......
...@@ -15,7 +15,13 @@ ...@@ -15,7 +15,13 @@
15 */ 15 */
16 package org.onosproject.net.group.impl; 16 package org.onosproject.net.group.impl;
17 17
18 -import com.google.common.collect.Sets; 18 +import static org.slf4j.LoggerFactory.getLogger;
19 +
20 +import java.util.Arrays;
21 +import java.util.Collection;
22 +import java.util.Iterator;
23 +import java.util.Set;
24 +
19 import org.apache.felix.scr.annotations.Activate; 25 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 26 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 27 import org.apache.felix.scr.annotations.Deactivate;
...@@ -48,12 +54,7 @@ import org.onosproject.net.provider.AbstractProviderRegistry; ...@@ -48,12 +54,7 @@ import org.onosproject.net.provider.AbstractProviderRegistry;
48 import org.onosproject.net.provider.AbstractProviderService; 54 import org.onosproject.net.provider.AbstractProviderService;
49 import org.slf4j.Logger; 55 import org.slf4j.Logger;
50 56
51 -import java.util.Arrays; 57 +import com.google.common.collect.Sets;
52 -import java.util.Collection;
53 -import java.util.Iterator;
54 -import java.util.Set;
55 -
56 -import static org.slf4j.LoggerFactory.getLogger;
57 58
58 /** 59 /**
59 * Provides implementation of the group service APIs. 60 * Provides implementation of the group service APIs.
...@@ -103,6 +104,7 @@ public class GroupManager ...@@ -103,6 +104,7 @@ public class GroupManager
103 */ 104 */
104 @Override 105 @Override
105 public void addGroup(GroupDescription groupDesc) { 106 public void addGroup(GroupDescription groupDesc) {
107 + log.trace("In addGroup API");
106 store.storeGroupDescription(groupDesc); 108 store.storeGroupDescription(groupDesc);
107 } 109 }
108 110
...@@ -121,6 +123,7 @@ public class GroupManager ...@@ -121,6 +123,7 @@ public class GroupManager
121 */ 123 */
122 @Override 124 @Override
123 public Group getGroup(DeviceId deviceId, GroupKey appCookie) { 125 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
126 + log.trace("In getGroup API");
124 return store.getGroup(deviceId, appCookie); 127 return store.getGroup(deviceId, appCookie);
125 } 128 }
126 129
...@@ -142,6 +145,7 @@ public class GroupManager ...@@ -142,6 +145,7 @@ public class GroupManager
142 GroupBuckets buckets, 145 GroupBuckets buckets,
143 GroupKey newCookie, 146 GroupKey newCookie,
144 ApplicationId appId) { 147 ApplicationId appId) {
148 + log.trace("In addBucketsToGroup API");
145 store.updateGroupDescription(deviceId, 149 store.updateGroupDescription(deviceId,
146 oldCookie, 150 oldCookie,
147 UpdateType.ADD, 151 UpdateType.ADD,
...@@ -167,6 +171,7 @@ public class GroupManager ...@@ -167,6 +171,7 @@ public class GroupManager
167 GroupBuckets buckets, 171 GroupBuckets buckets,
168 GroupKey newCookie, 172 GroupKey newCookie,
169 ApplicationId appId) { 173 ApplicationId appId) {
174 + log.trace("In removeBucketsFromGroup API");
170 store.updateGroupDescription(deviceId, 175 store.updateGroupDescription(deviceId,
171 oldCookie, 176 oldCookie,
172 UpdateType.REMOVE, 177 UpdateType.REMOVE,
...@@ -188,6 +193,7 @@ public class GroupManager ...@@ -188,6 +193,7 @@ public class GroupManager
188 public void removeGroup(DeviceId deviceId, 193 public void removeGroup(DeviceId deviceId,
189 GroupKey appCookie, 194 GroupKey appCookie,
190 ApplicationId appId) { 195 ApplicationId appId) {
196 + log.trace("In removeGroup API");
191 store.deleteGroupDescription(deviceId, appCookie); 197 store.deleteGroupDescription(deviceId, appCookie);
192 } 198 }
193 199
...@@ -202,11 +208,13 @@ public class GroupManager ...@@ -202,11 +208,13 @@ public class GroupManager
202 @Override 208 @Override
203 public Iterable<Group> getGroups(DeviceId deviceId, 209 public Iterable<Group> getGroups(DeviceId deviceId,
204 ApplicationId appId) { 210 ApplicationId appId) {
211 + log.trace("In getGroups API");
205 return store.getGroups(deviceId); 212 return store.getGroups(deviceId);
206 } 213 }
207 214
208 @Override 215 @Override
209 public Iterable<Group> getGroups(DeviceId deviceId) { 216 public Iterable<Group> getGroups(DeviceId deviceId) {
217 + log.trace("In getGroups API");
210 return store.getGroups(deviceId); 218 return store.getGroups(deviceId);
211 } 219 }
212 220
...@@ -217,6 +225,7 @@ public class GroupManager ...@@ -217,6 +225,7 @@ public class GroupManager
217 */ 225 */
218 @Override 226 @Override
219 public void addListener(GroupListener listener) { 227 public void addListener(GroupListener listener) {
228 + log.trace("In addListener API");
220 listenerRegistry.addListener(listener); 229 listenerRegistry.addListener(listener);
221 } 230 }
222 231
...@@ -227,6 +236,7 @@ public class GroupManager ...@@ -227,6 +236,7 @@ public class GroupManager
227 */ 236 */
228 @Override 237 @Override
229 public void removeListener(GroupListener listener) { 238 public void removeListener(GroupListener listener) {
239 + log.trace("In removeListener API");
230 listenerRegistry.removeListener(listener); 240 listenerRegistry.removeListener(listener);
231 } 241 }
232 242
...@@ -364,30 +374,45 @@ public class GroupManager ...@@ -364,30 +374,45 @@ public class GroupManager
364 Set<Group> extraneousStoredEntries = 374 Set<Group> extraneousStoredEntries =
365 Sets.newHashSet(store.getExtraneousGroups(deviceId)); 375 Sets.newHashSet(store.getExtraneousGroups(deviceId));
366 376
367 - log.trace("Displaying all southboundGroupEntries for device {}", deviceId); 377 + log.trace("Displaying all ({}) southboundGroupEntries for device {}",
378 + southboundGroupEntries.size(),
379 + deviceId);
368 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) { 380 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
369 Group group = it.next(); 381 Group group = it.next();
370 log.trace("Group {} in device {}", group, deviceId); 382 log.trace("Group {} in device {}", group, deviceId);
371 } 383 }
372 384
373 - log.trace("Displaying all stored group entries for device {}", deviceId); 385 + log.trace("Displaying all ({}) stored group entries for device {}",
374 - for (Iterator<Group> it = storedGroupEntries.iterator(); it.hasNext();) { 386 + storedGroupEntries.size(),
375 - Group group = it.next(); 387 + deviceId);
388 + for (Iterator<Group> it1 = storedGroupEntries.iterator(); it1.hasNext();) {
389 + Group group = it1.next();
376 log.trace("Stored Group {} for device {}", group, deviceId); 390 log.trace("Stored Group {} for device {}", group, deviceId);
377 } 391 }
378 392
379 - for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) { 393 + for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
380 - Group group = it.next(); 394 + Group group = it2.next();
381 if (storedGroupEntries.remove(group)) { 395 if (storedGroupEntries.remove(group)) {
382 // we both have the group, let's update some info then. 396 // we both have the group, let's update some info then.
383 log.trace("Group AUDIT: group {} exists " 397 log.trace("Group AUDIT: group {} exists "
384 + "in both planes for device {}", 398 + "in both planes for device {}",
385 group.id(), deviceId); 399 group.id(), deviceId);
386 groupAdded(group); 400 groupAdded(group);
387 - it.remove(); 401 + it2.remove();
388 } 402 }
389 } 403 }
390 for (Group group : southboundGroupEntries) { 404 for (Group group : southboundGroupEntries) {
405 + if (store.getGroup(group.deviceId(), group.id()) != null) {
406 + // There is a group existing with the same id
407 + // It is possible that group update is
408 + // in progress while we got a stale info from switch
409 + if (!storedGroupEntries.remove(store.getGroup(
410 + group.deviceId(), group.id()))) {
411 + log.warn("Group AUDIT: Inconsistent state:"
412 + + "Group exists in ID based table while "
413 + + "not present in key based table");
414 + }
415 + } else {
391 // there are groups in the switch that aren't in the store 416 // there are groups in the switch that aren't in the store
392 log.trace("Group AUDIT: extraneous group {} exists " 417 log.trace("Group AUDIT: extraneous group {} exists "
393 + "in data plane for device {}", 418 + "in data plane for device {}",
...@@ -395,6 +420,7 @@ public class GroupManager ...@@ -395,6 +420,7 @@ public class GroupManager
395 extraneousStoredEntries.remove(group); 420 extraneousStoredEntries.remove(group);
396 extraneousGroup(group); 421 extraneousGroup(group);
397 } 422 }
423 + }
398 for (Group group : storedGroupEntries) { 424 for (Group group : storedGroupEntries) {
399 // there are groups in the store that aren't in the switch 425 // there are groups in the store that aren't in the switch
400 log.trace("Group AUDIT: group {} missing " 426 log.trace("Group AUDIT: group {} missing "
......
...@@ -15,6 +15,12 @@ ...@@ -15,6 +15,12 @@
15 */ 15 */
16 package org.onosproject.net.group.impl; 16 package org.onosproject.net.group.impl;
17 17
18 +import static org.junit.Assert.assertEquals;
19 +import static org.junit.Assert.assertFalse;
20 +import static org.junit.Assert.assertNotEquals;
21 +import static org.junit.Assert.assertNotNull;
22 +import static org.junit.Assert.assertTrue;
23 +
18 import java.util.ArrayList; 24 import java.util.ArrayList;
19 import java.util.Arrays; 25 import java.util.Arrays;
20 import java.util.Collections; 26 import java.util.Collections;
...@@ -38,6 +44,7 @@ import org.onosproject.net.flow.TrafficTreatment; ...@@ -38,6 +44,7 @@ import org.onosproject.net.flow.TrafficTreatment;
38 import org.onosproject.net.group.DefaultGroup; 44 import org.onosproject.net.group.DefaultGroup;
39 import org.onosproject.net.group.DefaultGroupBucket; 45 import org.onosproject.net.group.DefaultGroupBucket;
40 import org.onosproject.net.group.DefaultGroupDescription; 46 import org.onosproject.net.group.DefaultGroupDescription;
47 +import org.onosproject.net.group.DefaultGroupKey;
41 import org.onosproject.net.group.Group; 48 import org.onosproject.net.group.Group;
42 import org.onosproject.net.group.GroupBucket; 49 import org.onosproject.net.group.GroupBucket;
43 import org.onosproject.net.group.GroupBuckets; 50 import org.onosproject.net.group.GroupBuckets;
...@@ -58,8 +65,6 @@ import org.onosproject.store.trivial.impl.SimpleGroupStore; ...@@ -58,8 +65,6 @@ import org.onosproject.store.trivial.impl.SimpleGroupStore;
58 65
59 import com.google.common.collect.Iterables; 66 import com.google.common.collect.Iterables;
60 67
61 -import static org.junit.Assert.*;
62 -
63 /** 68 /**
64 * Test codifying the group service & group provider service contracts. 69 * Test codifying the group service & group provider service contracts.
65 */ 70 */
...@@ -108,31 +113,6 @@ public class GroupManagerTest { ...@@ -108,31 +113,6 @@ public class GroupManagerTest {
108 mgr.eventDispatcher = null; 113 mgr.eventDispatcher = null;
109 } 114 }
110 115
111 - private class TestGroupKey implements GroupKey {
112 - private String groupId;
113 -
114 - public TestGroupKey(String id) {
115 - this.groupId = id;
116 - }
117 -
118 - public String id() {
119 - return this.groupId;
120 - }
121 -
122 - @Override
123 - public int hashCode() {
124 - return groupId.hashCode();
125 - }
126 -
127 - @Override
128 - public boolean equals(Object obj) {
129 - if (obj instanceof TestGroupKey) {
130 - return this.groupId.equals(((TestGroupKey) obj).id());
131 - }
132 - return false;
133 - }
134 - }
135 -
136 /** 116 /**
137 * Tests group service north bound and south bound interfaces. 117 * Tests group service north bound and south bound interfaces.
138 * The following operations are tested: 118 * The following operations are tested:
...@@ -177,7 +157,7 @@ public class GroupManagerTest { ...@@ -177,7 +157,7 @@ public class GroupManagerTest {
177 PortNumber.portNumber(32)}; 157 PortNumber.portNumber(32)};
178 PortNumber[] ports2 = {PortNumber.portNumber(41), 158 PortNumber[] ports2 = {PortNumber.portNumber(41),
179 PortNumber.portNumber(42)}; 159 PortNumber.portNumber(42)};
180 - TestGroupKey key = new TestGroupKey("group1BeforeAudit"); 160 + GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
181 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 161 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
182 List<PortNumber> outPorts = new ArrayList<PortNumber>(); 162 List<PortNumber> outPorts = new ArrayList<PortNumber>();
183 outPorts.addAll(Arrays.asList(ports1)); 163 outPorts.addAll(Arrays.asList(ports1));
...@@ -224,7 +204,7 @@ public class GroupManagerTest { ...@@ -224,7 +204,7 @@ public class GroupManagerTest {
224 providerService.pushGroupMetrics(DID, groupEntries); 204 providerService.pushGroupMetrics(DID, groupEntries);
225 // First group metrics would trigger the device audit completion 205 // First group metrics would trigger the device audit completion
226 // post which all pending group requests are also executed. 206 // post which all pending group requests are also executed.
227 - TestGroupKey key = new TestGroupKey("group1BeforeAudit"); 207 + GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
228 Group createdGroup = groupService.getGroup(DID, key); 208 Group createdGroup = groupService.getGroup(DID, key);
229 int createdGroupId = createdGroup.id().id(); 209 int createdGroupId = createdGroup.id().id();
230 assertNotEquals(gId1.id(), createdGroupId); 210 assertNotEquals(gId1.id(), createdGroupId);
...@@ -256,7 +236,7 @@ public class GroupManagerTest { ...@@ -256,7 +236,7 @@ public class GroupManagerTest {
256 0); 236 0);
257 List<Group> groupEntries = Arrays.asList(group1, group2); 237 List<Group> groupEntries = Arrays.asList(group1, group2);
258 providerService.pushGroupMetrics(DID, groupEntries); 238 providerService.pushGroupMetrics(DID, groupEntries);
259 - TestGroupKey key = new TestGroupKey("group1BeforeAudit"); 239 + GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
260 Group createdGroup = groupService.getGroup(DID, key); 240 Group createdGroup = groupService.getGroup(DID, key);
261 List<GroupOperation> expectedGroupOps = Arrays.asList( 241 List<GroupOperation> expectedGroupOps = Arrays.asList(
262 GroupOperation.createDeleteGroupOperation(gId1, 242 GroupOperation.createDeleteGroupOperation(gId1,
...@@ -271,7 +251,7 @@ public class GroupManagerTest { ...@@ -271,7 +251,7 @@ public class GroupManagerTest {
271 251
272 // Test AUDIT with confirmed groups 252 // Test AUDIT with confirmed groups
273 private void testAuditWithConfirmedGroups() { 253 private void testAuditWithConfirmedGroups() {
274 - TestGroupKey key = new TestGroupKey("group1BeforeAudit"); 254 + GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
275 Group createdGroup = groupService.getGroup(DID, key); 255 Group createdGroup = groupService.getGroup(DID, key);
276 createdGroup = new DefaultGroup(createdGroup.id(), 256 createdGroup = new DefaultGroup(createdGroup.id(),
277 DID, 257 DID,
...@@ -284,9 +264,9 @@ public class GroupManagerTest { ...@@ -284,9 +264,9 @@ public class GroupManagerTest {
284 264
285 // Test group add bucket operations 265 // Test group add bucket operations
286 private void testAddBuckets() { 266 private void testAddBuckets() {
287 - TestGroupKey addKey = new TestGroupKey("group1AddBuckets"); 267 + GroupKey addKey = new DefaultGroupKey("group1AddBuckets".getBytes());
288 268
289 - TestGroupKey prevKey = new TestGroupKey("group1BeforeAudit"); 269 + GroupKey prevKey = new DefaultGroupKey("group1BeforeAudit".getBytes());
290 Group createdGroup = groupService.getGroup(DID, prevKey); 270 Group createdGroup = groupService.getGroup(DID, prevKey);
291 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 271 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
292 buckets.addAll(createdGroup.buckets().buckets()); 272 buckets.addAll(createdGroup.buckets().buckets());
...@@ -328,9 +308,9 @@ public class GroupManagerTest { ...@@ -328,9 +308,9 @@ public class GroupManagerTest {
328 308
329 // Test group remove bucket operations 309 // Test group remove bucket operations
330 private void testRemoveBuckets() { 310 private void testRemoveBuckets() {
331 - TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets"); 311 + GroupKey removeKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
332 312
333 - TestGroupKey prevKey = new TestGroupKey("group1AddBuckets"); 313 + GroupKey prevKey = new DefaultGroupKey("group1AddBuckets".getBytes());
334 Group createdGroup = groupService.getGroup(DID, prevKey); 314 Group createdGroup = groupService.getGroup(DID, prevKey);
335 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 315 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
336 buckets.addAll(createdGroup.buckets().buckets()); 316 buckets.addAll(createdGroup.buckets().buckets());
...@@ -372,7 +352,7 @@ public class GroupManagerTest { ...@@ -372,7 +352,7 @@ public class GroupManagerTest {
372 352
373 // Test group remove operations 353 // Test group remove operations
374 private void testRemoveGroup() { 354 private void testRemoveGroup() {
375 - TestGroupKey currKey = new TestGroupKey("group1RemoveBuckets"); 355 + GroupKey currKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
376 Group existingGroup = groupService.getGroup(DID, currKey); 356 Group existingGroup = groupService.getGroup(DID, currKey);
377 groupService.removeGroup(DID, currKey, appId); 357 groupService.removeGroup(DID, currKey, appId);
378 List<GroupOperation> expectedGroupOps = Arrays.asList( 358 List<GroupOperation> expectedGroupOps = Arrays.asList(
...@@ -397,7 +377,7 @@ public class GroupManagerTest { ...@@ -397,7 +377,7 @@ public class GroupManagerTest {
397 PortNumber[] ports2 = {PortNumber.portNumber(41), 377 PortNumber[] ports2 = {PortNumber.portNumber(41),
398 PortNumber.portNumber(42)}; 378 PortNumber.portNumber(42)};
399 // Test Group creation before AUDIT process 379 // Test Group creation before AUDIT process
400 - TestGroupKey key = new TestGroupKey("group1BeforeAudit"); 380 + GroupKey key = new DefaultGroupKey("group1BeforeAudit".getBytes());
401 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 381 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
402 List<PortNumber> outPorts = new ArrayList<PortNumber>(); 382 List<PortNumber> outPorts = new ArrayList<PortNumber>();
403 outPorts.addAll(Arrays.asList(ports1)); 383 outPorts.addAll(Arrays.asList(ports1));
......
...@@ -16,25 +16,48 @@ ...@@ -16,25 +16,48 @@
16 package org.onosproject.store.group.impl; 16 package org.onosproject.store.group.impl;
17 17
18 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; 18 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
19 +import static org.onlab.util.Tools.groupedThreads;
19 import static org.slf4j.LoggerFactory.getLogger; 20 import static org.slf4j.LoggerFactory.getLogger;
20 21
22 +import java.net.URI;
21 import java.util.ArrayList; 23 import java.util.ArrayList;
22 import java.util.HashMap; 24 import java.util.HashMap;
23 import java.util.List; 25 import java.util.List;
26 +import java.util.Objects;
24 import java.util.concurrent.ConcurrentHashMap; 27 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap; 28 import java.util.concurrent.ConcurrentMap;
29 +import java.util.concurrent.ExecutorService;
30 +import java.util.concurrent.Executors;
26 import java.util.concurrent.atomic.AtomicInteger; 31 import java.util.concurrent.atomic.AtomicInteger;
32 +import java.util.concurrent.atomic.AtomicLong;
33 +import java.util.stream.Collectors;
27 34
28 import org.apache.felix.scr.annotations.Activate; 35 import org.apache.felix.scr.annotations.Activate;
29 import org.apache.felix.scr.annotations.Component; 36 import org.apache.felix.scr.annotations.Component;
30 import org.apache.felix.scr.annotations.Deactivate; 37 import org.apache.felix.scr.annotations.Deactivate;
38 +import org.apache.felix.scr.annotations.Reference;
39 +import org.apache.felix.scr.annotations.ReferenceCardinality;
31 import org.apache.felix.scr.annotations.Service; 40 import org.apache.felix.scr.annotations.Service;
41 +import org.onlab.util.KryoNamespace;
32 import org.onlab.util.NewConcurrentHashMap; 42 import org.onlab.util.NewConcurrentHashMap;
43 +import org.onosproject.cluster.ClusterService;
44 +import org.onosproject.core.DefaultApplicationId;
33 import org.onosproject.core.DefaultGroupId; 45 import org.onosproject.core.DefaultGroupId;
34 import org.onosproject.core.GroupId; 46 import org.onosproject.core.GroupId;
47 +import org.onosproject.mastership.MastershipService;
35 import org.onosproject.net.DeviceId; 48 import org.onosproject.net.DeviceId;
49 +import org.onosproject.net.MastershipRole;
50 +import org.onosproject.net.PortNumber;
51 +import org.onosproject.net.flow.DefaultTrafficTreatment;
52 +import org.onosproject.net.flow.FlowRule;
53 +import org.onosproject.net.flow.instructions.Instructions;
54 +import org.onosproject.net.flow.instructions.L0ModificationInstruction;
55 +import org.onosproject.net.flow.instructions.L2ModificationInstruction;
56 +import org.onosproject.net.flow.instructions.L3ModificationInstruction;
36 import org.onosproject.net.group.DefaultGroup; 57 import org.onosproject.net.group.DefaultGroup;
58 +import org.onosproject.net.group.DefaultGroupBucket;
37 import org.onosproject.net.group.DefaultGroupDescription; 59 import org.onosproject.net.group.DefaultGroupDescription;
60 +import org.onosproject.net.group.DefaultGroupKey;
38 import org.onosproject.net.group.Group; 61 import org.onosproject.net.group.Group;
39 import org.onosproject.net.group.Group.GroupState; 62 import org.onosproject.net.group.Group.GroupState;
40 import org.onosproject.net.group.GroupBucket; 63 import org.onosproject.net.group.GroupBucket;
...@@ -48,10 +71,21 @@ import org.onosproject.net.group.GroupStore; ...@@ -48,10 +71,21 @@ import org.onosproject.net.group.GroupStore;
48 import org.onosproject.net.group.GroupStoreDelegate; 71 import org.onosproject.net.group.GroupStoreDelegate;
49 import org.onosproject.net.group.StoredGroupEntry; 72 import org.onosproject.net.group.StoredGroupEntry;
50 import org.onosproject.store.AbstractStore; 73 import org.onosproject.store.AbstractStore;
74 +import org.onosproject.store.Timestamp;
75 +import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
76 +import org.onosproject.store.cluster.messaging.ClusterMessage;
77 +import org.onosproject.store.cluster.messaging.ClusterMessageHandler;
78 +import org.onosproject.store.ecmap.EventuallyConsistentMap;
79 +import org.onosproject.store.ecmap.EventuallyConsistentMapEvent;
80 +import org.onosproject.store.ecmap.EventuallyConsistentMapImpl;
81 +import org.onosproject.store.ecmap.EventuallyConsistentMapListener;
82 +import org.onosproject.store.impl.ClockService;
83 +import org.onosproject.store.impl.MultiValuedTimestamp;
84 +import org.onosproject.store.serializers.KryoNamespaces;
51 import org.slf4j.Logger; 85 import org.slf4j.Logger;
52 86
53 -import com.google.common.base.Function;
54 import com.google.common.collect.FluentIterable; 87 import com.google.common.collect.FluentIterable;
88 +import com.google.common.collect.Iterables;
55 89
56 /** 90 /**
57 * Manages inventory of group entries using trivial in-memory implementation. 91 * Manages inventory of group entries using trivial in-memory implementation.
...@@ -67,85 +101,165 @@ public class DistributedGroupStore ...@@ -67,85 +101,165 @@ public class DistributedGroupStore
67 private final int dummyId = 0xffffffff; 101 private final int dummyId = 0xffffffff;
68 private final GroupId dummyGroupId = new DefaultGroupId(dummyId); 102 private final GroupId dummyGroupId = new DefaultGroupId(dummyId);
69 103
70 - // inner Map is per device group table 104 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 - private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>> 105 + protected ClusterCommunicationService clusterCommunicator;
72 - groupEntriesByKey = new ConcurrentHashMap<>(); 106 +
73 - private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>> 107 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 - groupEntriesById = new ConcurrentHashMap<>(); 108 + protected ClusterService clusterService;
75 - private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>> 109 +
76 - pendingGroupEntriesByKey = new ConcurrentHashMap<>(); 110 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 + protected MastershipService mastershipService;
112 +
113 + // Per device group table with (device id + app cookie) as key
114 + private EventuallyConsistentMap<GroupStoreKeyMapKey,
115 + StoredGroupEntry> groupStoreEntriesByKey = null;
116 + // Per device group table with (device id + group id) as key
117 + private EventuallyConsistentMap<GroupStoreIdMapKey,
118 + StoredGroupEntry> groupStoreEntriesById = null;
119 + private EventuallyConsistentMap<GroupStoreKeyMapKey,
120 + StoredGroupEntry> auditPendingReqQueue = null;
77 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>> 121 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>>
78 extraneousGroupEntriesById = new ConcurrentHashMap<>(); 122 extraneousGroupEntriesById = new ConcurrentHashMap<>();
123 + private ExecutorService messageHandlingExecutor;
124 + private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 1;
79 125
80 private final HashMap<DeviceId, Boolean> deviceAuditStatus = 126 private final HashMap<DeviceId, Boolean> deviceAuditStatus =
81 new HashMap<DeviceId, Boolean>(); 127 new HashMap<DeviceId, Boolean>();
82 128
83 private final AtomicInteger groupIdGen = new AtomicInteger(); 129 private final AtomicInteger groupIdGen = new AtomicInteger();
84 130
131 + private KryoNamespace.Builder kryoBuilder = null;
132 +
85 @Activate 133 @Activate
86 public void activate() { 134 public void activate() {
135 + kryoBuilder = new KryoNamespace.Builder()
136 + .register(DefaultGroup.class,
137 + DefaultGroupBucket.class,
138 + DefaultGroupDescription.class,
139 + DefaultGroupKey.class,
140 + GroupDescription.Type.class,
141 + Group.GroupState.class,
142 + GroupBuckets.class,
143 + DefaultGroupId.class,
144 + GroupStoreMessage.class,
145 + GroupStoreMessage.Type.class,
146 + UpdateType.class,
147 + GroupStoreMessageSubjects.class,
148 + MultiValuedTimestamp.class,
149 + GroupStoreKeyMapKey.class,
150 + GroupStoreIdMapKey.class,
151 + GroupStoreMapKey.class
152 + )
153 + .register(URI.class)
154 + .register(DeviceId.class)
155 + .register(PortNumber.class)
156 + .register(DefaultApplicationId.class)
157 + .register(DefaultTrafficTreatment.class,
158 + Instructions.DropInstruction.class,
159 + Instructions.OutputInstruction.class,
160 + Instructions.GroupInstruction.class,
161 + Instructions.TableTypeTransition.class,
162 + FlowRule.Type.class,
163 + L0ModificationInstruction.class,
164 + L0ModificationInstruction.L0SubType.class,
165 + L0ModificationInstruction.ModLambdaInstruction.class,
166 + L2ModificationInstruction.class,
167 + L2ModificationInstruction.L2SubType.class,
168 + L2ModificationInstruction.ModEtherInstruction.class,
169 + L2ModificationInstruction.PushHeaderInstructions.class,
170 + L2ModificationInstruction.ModVlanIdInstruction.class,
171 + L2ModificationInstruction.ModVlanPcpInstruction.class,
172 + L2ModificationInstruction.ModMplsLabelInstruction.class,
173 + L2ModificationInstruction.ModMplsTtlInstruction.class,
174 + L3ModificationInstruction.class,
175 + L3ModificationInstruction.L3SubType.class,
176 + L3ModificationInstruction.ModIPInstruction.class,
177 + L3ModificationInstruction.ModIPv6FlowLabelInstruction.class,
178 + L3ModificationInstruction.ModTtlInstruction.class,
179 + org.onlab.packet.MplsLabel.class
180 + )
181 + .register(org.onosproject.cluster.NodeId.class)
182 + .register(KryoNamespaces.BASIC)
183 + .register(KryoNamespaces.MISC);
184 +
185 + messageHandlingExecutor = Executors.
186 + newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE,
187 + groupedThreads("onos/store/group",
188 + "message-handlers"));
189 + clusterCommunicator.
190 + addSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
191 + new ClusterGroupMsgHandler(),
192 + messageHandlingExecutor);
193 +
194 + log.debug("Creating EC map groupstorekeymap");
195 + groupStoreEntriesByKey =
196 + new EventuallyConsistentMapImpl<>("groupstorekeymap",
197 + clusterService,
198 + clusterCommunicator,
199 + kryoBuilder,
200 + new GroupStoreLogicalClockManager<>());
201 + log.trace("Current size {}", groupStoreEntriesByKey.size());
202 +
203 + log.debug("Creating EC map groupstoreidmap");
204 + groupStoreEntriesById =
205 + new EventuallyConsistentMapImpl<>("groupstoreidmap",
206 + clusterService,
207 + clusterCommunicator,
208 + kryoBuilder,
209 + new GroupStoreLogicalClockManager<>());
210 + groupStoreEntriesById.addListener(new GroupStoreIdMapListener());
211 + log.trace("Current size {}", groupStoreEntriesById.size());
212 +
213 + log.debug("Creating EC map pendinggroupkeymap");
214 + auditPendingReqQueue =
215 + new EventuallyConsistentMapImpl<>("pendinggroupkeymap",
216 + clusterService,
217 + clusterCommunicator,
218 + kryoBuilder,
219 + new GroupStoreLogicalClockManager<>());
220 + log.trace("Current size {}", auditPendingReqQueue.size());
221 +
87 log.info("Started"); 222 log.info("Started");
88 } 223 }
89 224
90 @Deactivate 225 @Deactivate
91 public void deactivate() { 226 public void deactivate() {
92 - groupEntriesByKey.clear();
93 - groupEntriesById.clear();
94 log.info("Stopped"); 227 log.info("Stopped");
95 } 228 }
96 229
97 - private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
98 - lazyEmptyGroupKeyTable() {
99 - return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
100 - }
101 -
102 - private static NewConcurrentHashMap<GroupId, StoredGroupEntry>
103 - lazyEmptyGroupIdTable() {
104 - return NewConcurrentHashMap.<GroupId, StoredGroupEntry>ifNeeded();
105 - }
106 -
107 - private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
108 - lazyEmptyPendingGroupKeyTable() {
109 - return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
110 - }
111 -
112 private static NewConcurrentHashMap<GroupId, Group> 230 private static NewConcurrentHashMap<GroupId, Group>
113 lazyEmptyExtraneousGroupIdTable() { 231 lazyEmptyExtraneousGroupIdTable() {
114 return NewConcurrentHashMap.<GroupId, Group>ifNeeded(); 232 return NewConcurrentHashMap.<GroupId, Group>ifNeeded();
115 } 233 }
116 234
117 /** 235 /**
118 - * Returns the group key table for specified device. 236 + * Returns the group store eventual consistent key map.
119 * 237 *
120 - * @param deviceId identifier of the device 238 + * @return Map representing group key table.
121 - * @return Map representing group key table of given device.
122 */ 239 */
123 - private ConcurrentMap<GroupKey, StoredGroupEntry> getGroupKeyTable(DeviceId deviceId) { 240 + private EventuallyConsistentMap<GroupStoreKeyMapKey, StoredGroupEntry>
124 - return createIfAbsentUnchecked(groupEntriesByKey, 241 + getGroupStoreKeyMap() {
125 - deviceId, lazyEmptyGroupKeyTable()); 242 + return groupStoreEntriesByKey;
126 } 243 }
127 244
128 /** 245 /**
129 - * Returns the group id table for specified device. 246 + * Returns the group store eventual consistent id map.
130 * 247 *
131 - * @param deviceId identifier of the device 248 + * @return Map representing group id table.
132 - * @return Map representing group key table of given device.
133 */ 249 */
134 - private ConcurrentMap<GroupId, StoredGroupEntry> getGroupIdTable(DeviceId deviceId) { 250 + private EventuallyConsistentMap<GroupStoreIdMapKey, StoredGroupEntry>
135 - return createIfAbsentUnchecked(groupEntriesById, 251 + getGroupStoreIdMap() {
136 - deviceId, lazyEmptyGroupIdTable()); 252 + return groupStoreEntriesById;
137 } 253 }
138 254
139 /** 255 /**
140 - * Returns the pending group key table for specified device. 256 + * Returns the pending group request table.
141 * 257 *
142 - * @param deviceId identifier of the device 258 + * @return Map representing group key table.
143 - * @return Map representing group key table of given device.
144 */ 259 */
145 - private ConcurrentMap<GroupKey, StoredGroupEntry> 260 + private EventuallyConsistentMap<GroupStoreKeyMapKey, StoredGroupEntry>
146 - getPendingGroupKeyTable(DeviceId deviceId) { 261 + getPendingGroupKeyTable() {
147 - return createIfAbsentUnchecked(pendingGroupEntriesByKey, 262 + return auditPendingReqQueue;
148 - deviceId, lazyEmptyPendingGroupKeyTable());
149 } 263 }
150 264
151 /** 265 /**
...@@ -168,8 +282,8 @@ public class DistributedGroupStore ...@@ -168,8 +282,8 @@ public class DistributedGroupStore
168 */ 282 */
169 @Override 283 @Override
170 public int getGroupCount(DeviceId deviceId) { 284 public int getGroupCount(DeviceId deviceId) {
171 - return (groupEntriesByKey.get(deviceId) != null) ? 285 + return (getGroups(deviceId) != null) ?
172 - groupEntriesByKey.get(deviceId).size() : 0; 286 + Iterables.size(getGroups(deviceId)) : 0;
173 } 287 }
174 288
175 /** 289 /**
...@@ -182,16 +296,11 @@ public class DistributedGroupStore ...@@ -182,16 +296,11 @@ public class DistributedGroupStore
182 @Override 296 @Override
183 public Iterable<Group> getGroups(DeviceId deviceId) { 297 public Iterable<Group> getGroups(DeviceId deviceId) {
184 // flatten and make iterator unmodifiable 298 // flatten and make iterator unmodifiable
185 - return FluentIterable.from(getGroupKeyTable(deviceId).values()) 299 + log.trace("getGroups: for device {} total number of groups {}",
186 - .transform( 300 + deviceId, getGroupStoreKeyMap().values().size());
187 - new Function<StoredGroupEntry, Group>() { 301 + return FluentIterable.from(getGroupStoreKeyMap().values())
188 - 302 + .filter(input -> input.deviceId().equals(deviceId))
189 - @Override 303 + .transform(input -> input);
190 - public Group apply(
191 - StoredGroupEntry input) {
192 - return input;
193 - }
194 - });
195 } 304 }
196 305
197 /** 306 /**
...@@ -204,19 +313,31 @@ public class DistributedGroupStore ...@@ -204,19 +313,31 @@ public class DistributedGroupStore
204 */ 313 */
205 @Override 314 @Override
206 public Group getGroup(DeviceId deviceId, GroupKey appCookie) { 315 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
207 - return (groupEntriesByKey.get(deviceId) != null) ? 316 + return getStoredGroupEntry(deviceId, appCookie);
208 - groupEntriesByKey.get(deviceId).get(appCookie) : 317 + }
209 - null; 318 +
319 + private StoredGroupEntry getStoredGroupEntry(DeviceId deviceId,
320 + GroupKey appCookie) {
321 + return getGroupStoreKeyMap().get(new GroupStoreKeyMapKey(deviceId,
322 + appCookie));
323 + }
324 +
325 + @Override
326 + public Group getGroup(DeviceId deviceId, GroupId groupId) {
327 + return getStoredGroupEntry(deviceId, groupId);
328 + }
329 +
330 + private StoredGroupEntry getStoredGroupEntry(DeviceId deviceId,
331 + GroupId groupId) {
332 + return getGroupStoreIdMap().get(new GroupStoreIdMapKey(deviceId,
333 + groupId));
210 } 334 }
211 335
212 private int getFreeGroupIdValue(DeviceId deviceId) { 336 private int getFreeGroupIdValue(DeviceId deviceId) {
213 int freeId = groupIdGen.incrementAndGet(); 337 int freeId = groupIdGen.incrementAndGet();
214 338
215 while (true) { 339 while (true) {
216 - Group existing = ( 340 + Group existing = getGroup(deviceId, new DefaultGroupId(freeId));
217 - groupEntriesById.get(deviceId) != null) ?
218 - groupEntriesById.get(deviceId).get(new DefaultGroupId(freeId)) :
219 - null;
220 if (existing == null) { 341 if (existing == null) {
221 existing = ( 342 existing = (
222 extraneousGroupEntriesById.get(deviceId) != null) ? 343 extraneousGroupEntriesById.get(deviceId) != null) ?
...@@ -240,23 +361,45 @@ public class DistributedGroupStore ...@@ -240,23 +361,45 @@ public class DistributedGroupStore
240 */ 361 */
241 @Override 362 @Override
242 public void storeGroupDescription(GroupDescription groupDesc) { 363 public void storeGroupDescription(GroupDescription groupDesc) {
364 + log.trace("In storeGroupDescription");
243 // Check if a group is existing with the same key 365 // Check if a group is existing with the same key
244 if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { 366 if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
367 + log.warn("Group already exists with the same key {}",
368 + groupDesc.appCookie());
245 return; 369 return;
246 } 370 }
247 371
248 - if (deviceAuditStatus.get(groupDesc.deviceId()) == null) { 372 + // Check if group to be created by a remote instance
249 - // Device group audit has not completed yet 373 + if (mastershipService.getLocalRole(
250 - // Add this group description to pending group key table 374 + groupDesc.deviceId()) != MastershipRole.MASTER) {
251 - // Create a group entry object with Dummy Group ID 375 + log.debug("Device {} local role is not MASTER",
252 - StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc); 376 + groupDesc.deviceId());
253 - group.setState(GroupState.WAITING_AUDIT_COMPLETE); 377 + GroupStoreMessage groupOp = GroupStoreMessage.
254 - ConcurrentMap<GroupKey, StoredGroupEntry> pendingKeyTable = 378 + createGroupAddRequestMsg(groupDesc.deviceId(),
255 - getPendingGroupKeyTable(groupDesc.deviceId()); 379 + groupDesc);
256 - pendingKeyTable.put(groupDesc.appCookie(), group); 380 + ClusterMessage message = new ClusterMessage(
381 + clusterService.getLocalNode().id(),
382 + GroupStoreMessageSubjects.
383 + REMOTE_GROUP_OP_REQUEST,
384 + kryoBuilder.build().serialize(groupOp));
385 + if (!clusterCommunicator.unicast(message,
386 + mastershipService.
387 + getMasterFor(
388 + groupDesc.deviceId()))) {
389 + log.warn("Failed to send request to master: {} to {}",
390 + message,
391 + mastershipService.getMasterFor(groupDesc.deviceId()));
392 + //TODO: Send Group operation failure event
393 + }
394 + log.debug("Sent Group operation request for device {} "
395 + + "to remote MASTER {}",
396 + groupDesc.deviceId(),
397 + mastershipService.getMasterFor(groupDesc.deviceId()));
257 return; 398 return;
258 } 399 }
259 400
401 + log.debug("Store group for device {} is getting handled locally",
402 + groupDesc.deviceId());
260 storeGroupDescriptionInternal(groupDesc); 403 storeGroupDescriptionInternal(groupDesc);
261 } 404 }
262 405
...@@ -266,17 +409,34 @@ public class DistributedGroupStore ...@@ -266,17 +409,34 @@ public class DistributedGroupStore
266 return; 409 return;
267 } 410 }
268 411
412 + if (deviceAuditStatus.get(groupDesc.deviceId()) == null) {
413 + // Device group audit has not completed yet
414 + // Add this group description to pending group key table
415 + // Create a group entry object with Dummy Group ID
416 + log.debug("storeGroupDescriptionInternal: Device {} AUDIT "
417 + + "pending...Queuing Group ADD request",
418 + groupDesc.deviceId());
419 + StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc);
420 + group.setState(GroupState.WAITING_AUDIT_COMPLETE);
421 + EventuallyConsistentMap<GroupStoreKeyMapKey, StoredGroupEntry> pendingKeyTable =
422 + getPendingGroupKeyTable();
423 + pendingKeyTable.put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
424 + groupDesc.appCookie()),
425 + group);
426 + return;
427 + }
428 +
269 // Get a new group identifier 429 // Get a new group identifier
270 GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); 430 GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
271 // Create a group entry object 431 // Create a group entry object
272 StoredGroupEntry group = new DefaultGroup(id, groupDesc); 432 StoredGroupEntry group = new DefaultGroup(id, groupDesc);
273 - // Insert the newly created group entry into concurrent key and id maps 433 + // Insert the newly created group entry into key and id maps
274 - ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = 434 + getGroupStoreKeyMap().
275 - getGroupKeyTable(groupDesc.deviceId()); 435 + put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
276 - keyTable.put(groupDesc.appCookie(), group); 436 + groupDesc.appCookie()), group);
277 - ConcurrentMap<GroupId, StoredGroupEntry> idTable = 437 + getGroupStoreIdMap().
278 - getGroupIdTable(groupDesc.deviceId()); 438 + put(new GroupStoreIdMapKey(groupDesc.deviceId(),
279 - idTable.put(id, group); 439 + id), group);
280 notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED, 440 notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
281 group)); 441 group));
282 } 442 }
...@@ -297,6 +457,42 @@ public class DistributedGroupStore ...@@ -297,6 +457,42 @@ public class DistributedGroupStore
297 UpdateType type, 457 UpdateType type,
298 GroupBuckets newBuckets, 458 GroupBuckets newBuckets,
299 GroupKey newAppCookie) { 459 GroupKey newAppCookie) {
460 + // Check if group update to be done by a remote instance
461 + if (mastershipService.
462 + getLocalRole(deviceId) != MastershipRole.MASTER) {
463 + GroupStoreMessage groupOp = GroupStoreMessage.
464 + createGroupUpdateRequestMsg(deviceId,
465 + oldAppCookie,
466 + type,
467 + newBuckets,
468 + newAppCookie);
469 + ClusterMessage message =
470 + new ClusterMessage(clusterService.getLocalNode().id(),
471 + GroupStoreMessageSubjects.
472 + REMOTE_GROUP_OP_REQUEST,
473 + kryoBuilder.build().serialize(groupOp));
474 + if (!clusterCommunicator.unicast(message,
475 + mastershipService.
476 + getMasterFor(deviceId))) {
477 + log.warn("Failed to send request to master: {} to {}",
478 + message,
479 + mastershipService.getMasterFor(deviceId));
480 + //TODO: Send Group operation failure event
481 + }
482 + return;
483 + }
484 + updateGroupDescriptionInternal(deviceId,
485 + oldAppCookie,
486 + type,
487 + newBuckets,
488 + newAppCookie);
489 + }
490 +
491 + private void updateGroupDescriptionInternal(DeviceId deviceId,
492 + GroupKey oldAppCookie,
493 + UpdateType type,
494 + GroupBuckets newBuckets,
495 + GroupKey newAppCookie) {
300 // Check if a group is existing with the provided key 496 // Check if a group is existing with the provided key
301 Group oldGroup = getGroup(deviceId, oldAppCookie); 497 Group oldGroup = getGroup(deviceId, oldAppCookie);
302 if (oldGroup == null) { 498 if (oldGroup == null) {
...@@ -323,14 +519,17 @@ public class DistributedGroupStore ...@@ -323,14 +519,17 @@ public class DistributedGroupStore
323 newGroup.setPackets(oldGroup.packets()); 519 newGroup.setPackets(oldGroup.packets());
324 newGroup.setBytes(oldGroup.bytes()); 520 newGroup.setBytes(oldGroup.bytes());
325 // Remove the old entry from maps and add new entry using new key 521 // Remove the old entry from maps and add new entry using new key
326 - ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = 522 + getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(oldGroup.deviceId(),
327 - getGroupKeyTable(oldGroup.deviceId()); 523 + oldGroup.appCookie()));
328 - ConcurrentMap<GroupId, StoredGroupEntry> idTable = 524 + getGroupStoreIdMap().remove(new GroupStoreIdMapKey(oldGroup.deviceId(),
329 - getGroupIdTable(oldGroup.deviceId()); 525 + oldGroup.id()));
330 - keyTable.remove(oldGroup.appCookie()); 526 + getGroupStoreKeyMap().
331 - idTable.remove(oldGroup.id()); 527 + put(new GroupStoreKeyMapKey(newGroup.deviceId(),
332 - keyTable.put(newGroup.appCookie(), newGroup); 528 + newGroup.appCookie()), newGroup);
333 - idTable.put(newGroup.id(), newGroup); 529 + getGroupStoreIdMap().
530 + put(new GroupStoreIdMapKey(newGroup.deviceId(),
531 + newGroup.id()), newGroup);
532 +
334 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup)); 533 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup));
335 } 534 }
336 } 535 }
...@@ -379,10 +578,34 @@ public class DistributedGroupStore ...@@ -379,10 +578,34 @@ public class DistributedGroupStore
379 @Override 578 @Override
380 public void deleteGroupDescription(DeviceId deviceId, 579 public void deleteGroupDescription(DeviceId deviceId,
381 GroupKey appCookie) { 580 GroupKey appCookie) {
581 + // Check if group to be deleted by a remote instance
582 + if (mastershipService.
583 + getLocalRole(deviceId) != MastershipRole.MASTER) {
584 + GroupStoreMessage groupOp = GroupStoreMessage.
585 + createGroupDeleteRequestMsg(deviceId,
586 + appCookie);
587 + ClusterMessage message =
588 + new ClusterMessage(clusterService.getLocalNode().id(),
589 + GroupStoreMessageSubjects.
590 + REMOTE_GROUP_OP_REQUEST,
591 + kryoBuilder.build().serialize(groupOp));
592 + if (!clusterCommunicator.unicast(message,
593 + mastershipService.
594 + getMasterFor(deviceId))) {
595 + log.warn("Failed to send request to master: {} to {}",
596 + message,
597 + mastershipService.getMasterFor(deviceId));
598 + //TODO: Send Group operation failure event
599 + }
600 + return;
601 + }
602 + deleteGroupDescriptionInternal(deviceId, appCookie);
603 + }
604 +
605 + private void deleteGroupDescriptionInternal(DeviceId deviceId,
606 + GroupKey appCookie) {
382 // Check if a group is existing with the provided key 607 // Check if a group is existing with the provided key
383 - StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ? 608 + StoredGroupEntry existing = getStoredGroupEntry(deviceId, appCookie);
384 - groupEntriesByKey.get(deviceId).get(appCookie) :
385 - null;
386 if (existing == null) { 609 if (existing == null) {
387 return; 610 return;
388 } 611 }
...@@ -401,26 +624,35 @@ public class DistributedGroupStore ...@@ -401,26 +624,35 @@ public class DistributedGroupStore
401 @Override 624 @Override
402 public void addOrUpdateGroupEntry(Group group) { 625 public void addOrUpdateGroupEntry(Group group) {
403 // check if this new entry is an update to an existing entry 626 // check if this new entry is an update to an existing entry
404 - StoredGroupEntry existing = (groupEntriesById.get( 627 + StoredGroupEntry existing = getStoredGroupEntry(group.deviceId(),
405 - group.deviceId()) != null) ? 628 + group.id());
406 - groupEntriesById.get(group.deviceId()).get(group.id()) :
407 - null;
408 GroupEvent event = null; 629 GroupEvent event = null;
409 630
410 if (existing != null) { 631 if (existing != null) {
632 + log.trace("addOrUpdateGroupEntry: updating group "
633 + + "entry {} in device {}",
634 + group.id(),
635 + group.deviceId());
411 synchronized (existing) { 636 synchronized (existing) {
412 existing.setLife(group.life()); 637 existing.setLife(group.life());
413 existing.setPackets(group.packets()); 638 existing.setPackets(group.packets());
414 existing.setBytes(group.bytes()); 639 existing.setBytes(group.bytes());
415 if (existing.state() == GroupState.PENDING_ADD) { 640 if (existing.state() == GroupState.PENDING_ADD) {
416 existing.setState(GroupState.ADDED); 641 existing.setState(GroupState.ADDED);
642 + existing.setIsGroupStateAddedFirstTime(true);
417 event = new GroupEvent(Type.GROUP_ADDED, existing); 643 event = new GroupEvent(Type.GROUP_ADDED, existing);
418 } else { 644 } else {
419 - if (existing.state() == GroupState.PENDING_UPDATE) { 645 + existing.setState(GroupState.ADDED);
420 - existing.setState(GroupState.PENDING_UPDATE); 646 + existing.setIsGroupStateAddedFirstTime(false);
421 - }
422 event = new GroupEvent(Type.GROUP_UPDATED, existing); 647 event = new GroupEvent(Type.GROUP_UPDATED, existing);
423 } 648 }
649 + //Re-PUT map entries to trigger map update events
650 + getGroupStoreKeyMap().
651 + put(new GroupStoreKeyMapKey(existing.deviceId(),
652 + existing.appCookie()), existing);
653 + getGroupStoreIdMap().
654 + put(new GroupStoreIdMapKey(existing.deviceId(),
655 + existing.id()), existing);
424 } 656 }
425 } 657 }
426 658
...@@ -436,18 +668,18 @@ public class DistributedGroupStore ...@@ -436,18 +668,18 @@ public class DistributedGroupStore
436 */ 668 */
437 @Override 669 @Override
438 public void removeGroupEntry(Group group) { 670 public void removeGroupEntry(Group group) {
439 - StoredGroupEntry existing = (groupEntriesById.get( 671 + StoredGroupEntry existing = getStoredGroupEntry(group.deviceId(),
440 - group.deviceId()) != null) ? 672 + group.id());
441 - groupEntriesById.get(group.deviceId()).get(group.id()) :
442 - null;
443 673
444 if (existing != null) { 674 if (existing != null) {
445 - ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = 675 + log.trace("removeGroupEntry: removing group "
446 - getGroupKeyTable(existing.deviceId()); 676 + + "entry {} in device {}",
447 - ConcurrentMap<GroupId, StoredGroupEntry> idTable = 677 + group.id(),
448 - getGroupIdTable(existing.deviceId()); 678 + group.deviceId());
449 - idTable.remove(existing.id()); 679 + getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
450 - keyTable.remove(existing.appCookie()); 680 + existing.appCookie()));
681 + getGroupStoreIdMap().remove(new GroupStoreIdMapKey(existing.deviceId(),
682 + existing.id()));
451 notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing)); 683 notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing));
452 } 684 }
453 } 685 }
...@@ -461,9 +693,17 @@ public class DistributedGroupStore ...@@ -461,9 +693,17 @@ public class DistributedGroupStore
461 + "completed for device {}", deviceId); 693 + "completed for device {}", deviceId);
462 deviceAuditStatus.put(deviceId, true); 694 deviceAuditStatus.put(deviceId, true);
463 // Execute all pending group requests 695 // Execute all pending group requests
464 - ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests = 696 + List<StoredGroupEntry> pendingGroupRequests =
465 - getPendingGroupKeyTable(deviceId); 697 + getPendingGroupKeyTable().values()
466 - for (Group group:pendingGroupRequests.values()) { 698 + .stream()
699 + .filter(g-> g.deviceId().equals(deviceId))
700 + .collect(Collectors.toList());
701 + log.trace("deviceInitialAuditCompleted: processing "
702 + + "pending group add requests for device {} and "
703 + + "number of pending requests {}",
704 + deviceId,
705 + pendingGroupRequests.size());
706 + for (Group group:pendingGroupRequests) {
467 GroupDescription tmp = new DefaultGroupDescription( 707 GroupDescription tmp = new DefaultGroupDescription(
468 group.deviceId(), 708 group.deviceId(),
469 group.type(), 709 group.type(),
...@@ -471,8 +711,9 @@ public class DistributedGroupStore ...@@ -471,8 +711,9 @@ public class DistributedGroupStore
471 group.appCookie(), 711 group.appCookie(),
472 group.appId()); 712 group.appId());
473 storeGroupDescriptionInternal(tmp); 713 storeGroupDescriptionInternal(tmp);
714 + getPendingGroupKeyTable().
715 + remove(new GroupStoreKeyMapKey(deviceId, group.appCookie()));
474 } 716 }
475 - getPendingGroupKeyTable(deviceId).clear();
476 } else { 717 } else {
477 if (deviceAuditStatus.get(deviceId)) { 718 if (deviceAuditStatus.get(deviceId)) {
478 log.debug("deviceInitialAuditCompleted: Clearing AUDIT " 719 log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
...@@ -494,10 +735,8 @@ public class DistributedGroupStore ...@@ -494,10 +735,8 @@ public class DistributedGroupStore
494 @Override 735 @Override
495 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) { 736 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
496 737
497 - StoredGroupEntry existing = (groupEntriesById.get( 738 + StoredGroupEntry existing = getStoredGroupEntry(deviceId,
498 - deviceId) != null) ? 739 + operation.groupId());
499 - groupEntriesById.get(deviceId).get(operation.groupId()) :
500 - null;
501 740
502 if (existing == null) { 741 if (existing == null) {
503 log.warn("No group entry with ID {} found ", operation.groupId()); 742 log.warn("No group entry with ID {} found ", operation.groupId());
...@@ -518,27 +757,37 @@ public class DistributedGroupStore ...@@ -518,27 +757,37 @@ public class DistributedGroupStore
518 log.warn("Unknown group operation type {}", operation.opType()); 757 log.warn("Unknown group operation type {}", operation.opType());
519 } 758 }
520 759
521 - ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = 760 + getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
522 - getGroupKeyTable(existing.deviceId()); 761 + existing.appCookie()));
523 - ConcurrentMap<GroupId, StoredGroupEntry> idTable = 762 + getGroupStoreIdMap().remove(new GroupStoreIdMapKey(existing.deviceId(),
524 - getGroupIdTable(existing.deviceId()); 763 + existing.id()));
525 - idTable.remove(existing.id());
526 - keyTable.remove(existing.appCookie());
527 } 764 }
528 765
529 @Override 766 @Override
530 public void addOrUpdateExtraneousGroupEntry(Group group) { 767 public void addOrUpdateExtraneousGroupEntry(Group group) {
768 + log.trace("addOrUpdateExtraneousGroupEntry: add/update extraneous "
769 + + "group entry {} in device {}",
770 + group.id(),
771 + group.deviceId());
531 ConcurrentMap<GroupId, Group> extraneousIdTable = 772 ConcurrentMap<GroupId, Group> extraneousIdTable =
532 getExtraneousGroupIdTable(group.deviceId()); 773 getExtraneousGroupIdTable(group.deviceId());
533 extraneousIdTable.put(group.id(), group); 774 extraneousIdTable.put(group.id(), group);
534 // Check the reference counter 775 // Check the reference counter
535 if (group.referenceCount() == 0) { 776 if (group.referenceCount() == 0) {
777 + log.trace("addOrUpdateExtraneousGroupEntry: Flow reference "
778 + + "counter is zero and triggering remove",
779 + group.id(),
780 + group.deviceId());
536 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group)); 781 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
537 } 782 }
538 } 783 }
539 784
540 @Override 785 @Override
541 public void removeExtraneousGroupEntry(Group group) { 786 public void removeExtraneousGroupEntry(Group group) {
787 + log.trace("removeExtraneousGroupEntry: remove extraneous "
788 + + "group entry {} of device {} from store",
789 + group.id(),
790 + group.deviceId());
542 ConcurrentMap<GroupId, Group> extraneousIdTable = 791 ConcurrentMap<GroupId, Group> extraneousIdTable =
543 getExtraneousGroupIdTable(group.deviceId()); 792 getExtraneousGroupIdTable(group.deviceId());
544 extraneousIdTable.remove(group.id()); 793 extraneousIdTable.remove(group.id());
...@@ -551,5 +800,192 @@ public class DistributedGroupStore ...@@ -551,5 +800,192 @@ public class DistributedGroupStore
551 getExtraneousGroupIdTable(deviceId).values()); 800 getExtraneousGroupIdTable(deviceId).values());
552 } 801 }
553 802
803 + /**
804 + * ClockService that generates wallclock based timestamps.
805 + */
806 + private class GroupStoreLogicalClockManager<T, U>
807 + implements ClockService<T, U> {
808 +
809 + private final AtomicLong sequenceNumber = new AtomicLong(0);
810 +
811 + @Override
812 + public Timestamp getTimestamp(T t1, U u1) {
813 + return new MultiValuedTimestamp<>(System.currentTimeMillis(),
814 + sequenceNumber.getAndIncrement());
815 + }
816 + }
817 +
818 + /**
819 + * Map handler to receive any events when the group map is updated.
820 + */
821 + private class GroupStoreIdMapListener implements
822 + EventuallyConsistentMapListener<GroupStoreIdMapKey, StoredGroupEntry> {
823 +
824 + @Override
825 + public void event(EventuallyConsistentMapEvent<GroupStoreIdMapKey,
826 + StoredGroupEntry> mapEvent) {
827 + GroupEvent groupEvent = null;
828 + log.trace("GroupStoreIdMapListener: received groupid map event {}",
829 + mapEvent.type());
830 + if (mapEvent.type() == EventuallyConsistentMapEvent.Type.PUT) {
831 + log.trace("GroupIdMapListener: Received PUT event");
832 + if (mapEvent.value().state() == Group.GroupState.ADDED) {
833 + if (mapEvent.value().isGroupStateAddedFirstTime()) {
834 + groupEvent = new GroupEvent(Type.GROUP_ADDED,
835 + mapEvent.value());
836 + log.trace("GroupIdMapListener: Received first time "
837 + + "GROUP_ADDED state update");
838 + } else {
839 + groupEvent = new GroupEvent(Type.GROUP_UPDATED,
840 + mapEvent.value());
841 + log.trace("GroupIdMapListener: Received following "
842 + + "GROUP_ADDED state update");
843 + }
844 + }
845 + } else if (mapEvent.type() == EventuallyConsistentMapEvent.Type.REMOVE) {
846 + log.trace("GroupIdMapListener: Received REMOVE event");
847 + groupEvent = new GroupEvent(Type.GROUP_REMOVED, mapEvent.value());
848 + }
849 +
850 + if (groupEvent != null) {
851 + notifyDelegate(groupEvent);
852 + }
853 + }
854 + }
855 + /**
856 + * Message handler to receive messages from group subsystems of
857 + * other cluster members.
858 + */
859 + private final class ClusterGroupMsgHandler
860 + implements ClusterMessageHandler {
861 + @Override
862 + public void handle(ClusterMessage message) {
863 + log.trace("ClusterGroupMsgHandler: received remote group message");
864 + if (message.subject() ==
865 + GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST) {
866 + GroupStoreMessage groupOp = kryoBuilder.
867 + build().deserialize(message.payload());
868 + log.trace("received remote group operation request");
869 + if (!(mastershipService.
870 + getLocalRole(groupOp.deviceId()) !=
871 + MastershipRole.MASTER)) {
872 + log.warn("ClusterGroupMsgHandler: This node is not "
873 + + "MASTER for device {}", groupOp.deviceId());
874 + return;
875 + }
876 + if (groupOp.type() == GroupStoreMessage.Type.ADD) {
877 + log.trace("processing remote group "
878 + + "add operation request");
879 + storeGroupDescriptionInternal(groupOp.groupDesc());
880 + } else if (groupOp.type() == GroupStoreMessage.Type.UPDATE) {
881 + log.trace("processing remote group "
882 + + "update operation request");
883 + updateGroupDescriptionInternal(groupOp.deviceId(),
884 + groupOp.appCookie(),
885 + groupOp.updateType(),
886 + groupOp.updateBuckets(),
887 + groupOp.newAppCookie());
888 + } else if (groupOp.type() == GroupStoreMessage.Type.DELETE) {
889 + log.trace("processing remote group "
890 + + "delete operation request");
891 + deleteGroupDescriptionInternal(groupOp.deviceId(),
892 + groupOp.appCookie());
893 + }
894 + }
895 + }
896 + }
897 +
898 + /**
899 + * Flattened map key to be used to store group entries.
900 + */
901 + private class GroupStoreMapKey {
902 + private final DeviceId deviceId;
903 +
904 + public GroupStoreMapKey(DeviceId deviceId) {
905 + this.deviceId = deviceId;
906 + }
907 +
908 + @Override
909 + public boolean equals(Object o) {
910 + if (this == o) {
911 + return true;
912 + }
913 + if (!(o instanceof GroupStoreMapKey)) {
914 + return false;
915 + }
916 + GroupStoreMapKey that = (GroupStoreMapKey) o;
917 + return this.deviceId.equals(that.deviceId);
918 + }
919 +
920 + @Override
921 + public int hashCode() {
922 + int result = 17;
923 +
924 + result = 31 * result + Objects.hash(this.deviceId);
925 +
926 + return result;
927 + }
928 + }
554 929
930 + private class GroupStoreKeyMapKey extends GroupStoreMapKey {
931 + private final GroupKey appCookie;
932 + public GroupStoreKeyMapKey(DeviceId deviceId,
933 + GroupKey appCookie) {
934 + super(deviceId);
935 + this.appCookie = appCookie;
936 + }
937 +
938 + @Override
939 + public boolean equals(Object o) {
940 + if (this == o) {
941 + return true;
942 + }
943 + if (!(o instanceof GroupStoreKeyMapKey)) {
944 + return false;
945 + }
946 + GroupStoreKeyMapKey that = (GroupStoreKeyMapKey) o;
947 + return (super.equals(that) &&
948 + this.appCookie.equals(that.appCookie));
949 + }
950 +
951 + @Override
952 + public int hashCode() {
953 + int result = 17;
954 +
955 + result = 31 * result + super.hashCode() + Objects.hash(this.appCookie);
956 +
957 + return result;
958 + }
959 + }
960 +
961 + private class GroupStoreIdMapKey extends GroupStoreMapKey {
962 + private final GroupId groupId;
963 + public GroupStoreIdMapKey(DeviceId deviceId,
964 + GroupId groupId) {
965 + super(deviceId);
966 + this.groupId = groupId;
967 + }
968 +
969 + @Override
970 + public boolean equals(Object o) {
971 + if (this == o) {
972 + return true;
973 + }
974 + if (!(o instanceof GroupStoreIdMapKey)) {
975 + return false;
976 + }
977 + GroupStoreIdMapKey that = (GroupStoreIdMapKey) o;
978 + return (super.equals(that) &&
979 + this.groupId.equals(that.groupId));
980 + }
981 +
982 + @Override
983 + public int hashCode() {
984 + int result = 17;
985 +
986 + result = 31 * result + super.hashCode() + Objects.hash(this.groupId);
987 +
988 + return result;
989 + }
990 + }
555 } 991 }
......
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.group.impl;
17 +
18 +import org.onosproject.net.DeviceId;
19 +import org.onosproject.net.group.GroupBuckets;
20 +import org.onosproject.net.group.GroupDescription;
21 +import org.onosproject.net.group.GroupKey;
22 +import org.onosproject.net.group.GroupStore.UpdateType;
23 +
24 +/**
25 + * Format of the Group store message that is used to
26 + * communicate with the peer nodes in the cluster.
27 + */
28 +public final class GroupStoreMessage {
29 + private final DeviceId deviceId;
30 + private final GroupKey appCookie;
31 + private final GroupDescription groupDesc;
32 + private final UpdateType updateType;
33 + private final GroupBuckets updateBuckets;
34 + private final GroupKey newAppCookie;
35 + private final Type type;
36 +
37 + /**
38 + * Type of group store request.
39 + */
40 + public enum Type {
41 + ADD,
42 + UPDATE,
43 + DELETE
44 + }
45 +
46 + private GroupStoreMessage(Type type,
47 + DeviceId deviceId,
48 + GroupKey appCookie,
49 + GroupDescription groupDesc,
50 + UpdateType updateType,
51 + GroupBuckets updateBuckets,
52 + GroupKey newAppCookie) {
53 + this.type = type;
54 + this.deviceId = deviceId;
55 + this.appCookie = appCookie;
56 + this.groupDesc = groupDesc;
57 + this.updateType = updateType;
58 + this.updateBuckets = updateBuckets;
59 + this.newAppCookie = newAppCookie;
60 + }
61 +
62 + /**
63 + * Creates a group store message for group ADD request.
64 + *
65 + * @param deviceId device identifier in which group to be added
66 + * @param desc group creation parameters
67 + * @return constructed group store message
68 + */
69 + public static GroupStoreMessage createGroupAddRequestMsg(DeviceId deviceId,
70 + GroupDescription desc) {
71 + return new GroupStoreMessage(Type.ADD,
72 + deviceId,
73 + null,
74 + desc,
75 + null,
76 + null,
77 + null);
78 + }
79 +
80 + /**
81 + * Creates a group store message for group UPDATE request.
82 + *
83 + * @param deviceId the device ID
84 + * @param appCookie the current group key
85 + * @param updateType update (add or delete) type
86 + * @param updateBuckets group buckets for updates
87 + * @param newAppCookie optional new group key
88 + * @return constructed group store message
89 + */
90 + public static GroupStoreMessage createGroupUpdateRequestMsg(DeviceId deviceId,
91 + GroupKey appCookie,
92 + UpdateType updateType,
93 + GroupBuckets updateBuckets,
94 + GroupKey newAppCookie) {
95 + return new GroupStoreMessage(Type.UPDATE,
96 + deviceId,
97 + appCookie,
98 + null,
99 + updateType,
100 + updateBuckets,
101 + newAppCookie);
102 + }
103 +
104 + /**
105 + * Creates a group store message for group DELETE request.
106 + *
107 + * @param deviceId the device ID
108 + * @param appCookie the group key
109 + * @return constructed group store message
110 + */
111 + public static GroupStoreMessage createGroupDeleteRequestMsg(DeviceId deviceId,
112 + GroupKey appCookie) {
113 + return new GroupStoreMessage(Type.DELETE,
114 + deviceId,
115 + appCookie,
116 + null,
117 + null,
118 + null,
119 + null);
120 + }
121 +
122 + /**
123 + * Returns the device identifier of this group request.
124 + *
125 + * @return device identifier
126 + */
127 + public DeviceId deviceId() {
128 + return deviceId;
129 + }
130 +
131 + /**
132 + * Returns the application cookie associated with this group request.
133 + *
134 + * @return application cookie
135 + */
136 + public GroupKey appCookie() {
137 + return appCookie;
138 + }
139 +
140 + /**
141 + * Returns the group create parameters associated with this group request.
142 + *
143 + * @return group create parameters
144 + */
145 + public GroupDescription groupDesc() {
146 + return groupDesc;
147 + }
148 +
149 + /**
150 + * Returns the group buckets to be updated as part of this group request.
151 + *
152 + * @return group buckets to be updated
153 + */
154 + public GroupBuckets updateBuckets() {
155 + return updateBuckets;
156 + }
157 +
158 + /**
159 + * Returns the update group operation type.
160 + *
161 + * @return update operation type
162 + */
163 + public UpdateType updateType() {
164 + return updateType;
165 + }
166 +
167 + /**
168 + * Returns the new application cookie associated with this group operation.
169 + *
170 + * @return new application cookie
171 + */
172 + public GroupKey newAppCookie() {
173 + return newAppCookie;
174 + }
175 +
176 + /**
177 + * Returns the type of this group operation.
178 + *
179 + * @return group message type
180 + */
181 + public Type type() {
182 + return type;
183 + }
184 +}
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.group.impl;
17 +
18 +import org.onosproject.store.cluster.messaging.MessageSubject;
19 +
20 +/**
21 + * MessageSubjects used by DistributedGroupRuleStore peer-peer communication.
22 + */
23 +public final class GroupStoreMessageSubjects {
24 + private GroupStoreMessageSubjects() {}
25 +
26 + public static final MessageSubject REMOTE_GROUP_OP_REQUEST
27 + = new MessageSubject("peer-forward-group-op-req");
28 +}
...@@ -209,6 +209,13 @@ public class SimpleGroupStore ...@@ -209,6 +209,13 @@ public class SimpleGroupStore
209 null; 209 null;
210 } 210 }
211 211
212 + @Override
213 + public Group getGroup(DeviceId deviceId, GroupId groupId) {
214 + return (groupEntriesById.get(deviceId) != null) ?
215 + groupEntriesById.get(deviceId).get(groupId) :
216 + null;
217 + }
218 +
212 private int getFreeGroupIdValue(DeviceId deviceId) { 219 private int getFreeGroupIdValue(DeviceId deviceId) {
213 int freeId = groupIdGen.incrementAndGet(); 220 int freeId = groupIdGen.incrementAndGet();
214 221
...@@ -551,5 +558,4 @@ public class SimpleGroupStore ...@@ -551,5 +558,4 @@ public class SimpleGroupStore
551 getExtraneousGroupIdTable(deviceId).values()); 558 getExtraneousGroupIdTable(deviceId).values());
552 } 559 }
553 560
554 -
555 } 561 }
......
...@@ -36,6 +36,7 @@ import org.onosproject.net.flow.DefaultTrafficTreatment; ...@@ -36,6 +36,7 @@ import org.onosproject.net.flow.DefaultTrafficTreatment;
36 import org.onosproject.net.flow.TrafficTreatment; 36 import org.onosproject.net.flow.TrafficTreatment;
37 import org.onosproject.net.group.DefaultGroupBucket; 37 import org.onosproject.net.group.DefaultGroupBucket;
38 import org.onosproject.net.group.DefaultGroupDescription; 38 import org.onosproject.net.group.DefaultGroupDescription;
39 +import org.onosproject.net.group.DefaultGroupKey;
39 import org.onosproject.net.group.Group; 40 import org.onosproject.net.group.Group;
40 import org.onosproject.net.group.GroupBucket; 41 import org.onosproject.net.group.GroupBucket;
41 import org.onosproject.net.group.GroupBuckets; 42 import org.onosproject.net.group.GroupBuckets;
...@@ -70,31 +71,6 @@ public class SimpleGroupStoreTest { ...@@ -70,31 +71,6 @@ public class SimpleGroupStoreTest {
70 simpleGroupStore.deactivate(); 71 simpleGroupStore.deactivate();
71 } 72 }
72 73
73 - public class TestGroupKey implements GroupKey {
74 - private String groupId;
75 -
76 - public TestGroupKey(String id) {
77 - this.groupId = id;
78 - }
79 -
80 - public String id() {
81 - return this.groupId;
82 - }
83 -
84 - @Override
85 - public int hashCode() {
86 - return groupId.hashCode();
87 - }
88 -
89 - @Override
90 - public boolean equals(Object obj) {
91 - if (obj instanceof TestGroupKey) {
92 - return this.groupId.equals(((TestGroupKey) obj).id());
93 - }
94 - return false;
95 - }
96 - }
97 -
98 private class InternalGroupStoreDelegate 74 private class InternalGroupStoreDelegate
99 implements GroupStoreDelegate { 75 implements GroupStoreDelegate {
100 private GroupId createdGroupId = null; 76 private GroupId createdGroupId = null;
...@@ -173,20 +149,20 @@ public class SimpleGroupStoreTest { ...@@ -173,20 +149,20 @@ public class SimpleGroupStoreTest {
173 simpleGroupStore.deviceInitialAuditCompleted(D1, true); 149 simpleGroupStore.deviceInitialAuditCompleted(D1, true);
174 150
175 // Testing storeGroup operation 151 // Testing storeGroup operation
176 - TestGroupKey newKey = new TestGroupKey("group1"); 152 + GroupKey newKey = new DefaultGroupKey("group1".getBytes());
177 testStoreAndGetGroup(newKey); 153 testStoreAndGetGroup(newKey);
178 154
179 // Testing addOrUpdateGroupEntry operation from southbound 155 // Testing addOrUpdateGroupEntry operation from southbound
180 - TestGroupKey currKey = newKey; 156 + GroupKey currKey = newKey;
181 testAddGroupEntryFromSB(currKey); 157 testAddGroupEntryFromSB(currKey);
182 158
183 // Testing updateGroupDescription for ADD operation from northbound 159 // Testing updateGroupDescription for ADD operation from northbound
184 - newKey = new TestGroupKey("group1AddBuckets"); 160 + newKey = new DefaultGroupKey("group1AddBuckets".getBytes());
185 testAddBuckets(currKey, newKey); 161 testAddBuckets(currKey, newKey);
186 162
187 // Testing updateGroupDescription for REMOVE operation from northbound 163 // Testing updateGroupDescription for REMOVE operation from northbound
188 currKey = newKey; 164 currKey = newKey;
189 - newKey = new TestGroupKey("group1RemoveBuckets"); 165 + newKey = new DefaultGroupKey("group1RemoveBuckets".getBytes());
190 testRemoveBuckets(currKey, newKey); 166 testRemoveBuckets(currKey, newKey);
191 167
192 // Testing addOrUpdateGroupEntry operation from southbound 168 // Testing addOrUpdateGroupEntry operation from southbound
...@@ -201,7 +177,7 @@ public class SimpleGroupStoreTest { ...@@ -201,7 +177,7 @@ public class SimpleGroupStoreTest {
201 } 177 }
202 178
203 // Testing storeGroup operation 179 // Testing storeGroup operation
204 - private void testStoreAndGetGroup(TestGroupKey key) { 180 + private void testStoreAndGetGroup(GroupKey key) {
205 PortNumber[] ports = {PortNumber.portNumber(31), 181 PortNumber[] ports = {PortNumber.portNumber(31),
206 PortNumber.portNumber(32)}; 182 PortNumber.portNumber(32)};
207 List<PortNumber> outPorts = new ArrayList<PortNumber>(); 183 List<PortNumber> outPorts = new ArrayList<PortNumber>();
...@@ -252,7 +228,7 @@ public class SimpleGroupStoreTest { ...@@ -252,7 +228,7 @@ public class SimpleGroupStoreTest {
252 } 228 }
253 229
254 // Testing addOrUpdateGroupEntry operation from southbound 230 // Testing addOrUpdateGroupEntry operation from southbound
255 - private void testAddGroupEntryFromSB(TestGroupKey currKey) { 231 + private void testAddGroupEntryFromSB(GroupKey currKey) {
256 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 232 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
257 233
258 InternalGroupStoreDelegate addGroupEntryDelegate = 234 InternalGroupStoreDelegate addGroupEntryDelegate =
...@@ -265,7 +241,7 @@ public class SimpleGroupStoreTest { ...@@ -265,7 +241,7 @@ public class SimpleGroupStoreTest {
265 } 241 }
266 242
267 // Testing addOrUpdateGroupEntry operation from southbound 243 // Testing addOrUpdateGroupEntry operation from southbound
268 - private void testUpdateGroupEntryFromSB(TestGroupKey currKey) { 244 + private void testUpdateGroupEntryFromSB(GroupKey currKey) {
269 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 245 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
270 246
271 InternalGroupStoreDelegate updateGroupEntryDelegate = 247 InternalGroupStoreDelegate updateGroupEntryDelegate =
...@@ -278,7 +254,7 @@ public class SimpleGroupStoreTest { ...@@ -278,7 +254,7 @@ public class SimpleGroupStoreTest {
278 } 254 }
279 255
280 // Testing updateGroupDescription for ADD operation from northbound 256 // Testing updateGroupDescription for ADD operation from northbound
281 - private void testAddBuckets(TestGroupKey currKey, TestGroupKey addKey) { 257 + private void testAddBuckets(GroupKey currKey, GroupKey addKey) {
282 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 258 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
283 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 259 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
284 buckets.addAll(existingGroup.buckets().buckets()); 260 buckets.addAll(existingGroup.buckets().buckets());
...@@ -316,7 +292,7 @@ public class SimpleGroupStoreTest { ...@@ -316,7 +292,7 @@ public class SimpleGroupStoreTest {
316 } 292 }
317 293
318 // Testing updateGroupDescription for REMOVE operation from northbound 294 // Testing updateGroupDescription for REMOVE operation from northbound
319 - private void testRemoveBuckets(TestGroupKey currKey, TestGroupKey removeKey) { 295 + private void testRemoveBuckets(GroupKey currKey, GroupKey removeKey) {
320 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 296 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
321 List<GroupBucket> buckets = new ArrayList<GroupBucket>(); 297 List<GroupBucket> buckets = new ArrayList<GroupBucket>();
322 buckets.addAll(existingGroup.buckets().buckets()); 298 buckets.addAll(existingGroup.buckets().buckets());
...@@ -343,7 +319,7 @@ public class SimpleGroupStoreTest { ...@@ -343,7 +319,7 @@ public class SimpleGroupStoreTest {
343 } 319 }
344 320
345 // Testing deleteGroupDescription operation from northbound 321 // Testing deleteGroupDescription operation from northbound
346 - private void testDeleteGroup(TestGroupKey currKey) { 322 + private void testDeleteGroup(GroupKey currKey) {
347 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 323 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
348 InternalGroupStoreDelegate deleteGroupDescDelegate = 324 InternalGroupStoreDelegate deleteGroupDescDelegate =
349 new InternalGroupStoreDelegate(currKey, 325 new InternalGroupStoreDelegate(currKey,
...@@ -355,7 +331,7 @@ public class SimpleGroupStoreTest { ...@@ -355,7 +331,7 @@ public class SimpleGroupStoreTest {
355 } 331 }
356 332
357 // Testing removeGroupEntry operation from southbound 333 // Testing removeGroupEntry operation from southbound
358 - private void testRemoveGroupFromSB(TestGroupKey currKey) { 334 + private void testRemoveGroupFromSB(GroupKey currKey) {
359 Group existingGroup = simpleGroupStore.getGroup(D1, currKey); 335 Group existingGroup = simpleGroupStore.getGroup(D1, currKey);
360 InternalGroupStoreDelegate removeGroupEntryDelegate = 336 InternalGroupStoreDelegate removeGroupEntryDelegate =
361 new InternalGroupStoreDelegate(currKey, 337 new InternalGroupStoreDelegate(currKey,
...@@ -380,7 +356,7 @@ public class SimpleGroupStoreTest { ...@@ -380,7 +356,7 @@ public class SimpleGroupStoreTest {
380 356
381 ApplicationId appId = 357 ApplicationId appId =
382 new DefaultApplicationId(2, "org.groupstore.test"); 358 new DefaultApplicationId(2, "org.groupstore.test");
383 - TestGroupKey key = new TestGroupKey("group1"); 359 + GroupKey key = new DefaultGroupKey("group1".getBytes());
384 PortNumber[] ports = {PortNumber.portNumber(31), 360 PortNumber[] ports = {PortNumber.portNumber(31),
385 PortNumber.portNumber(32)}; 361 PortNumber.portNumber(32)};
386 List<PortNumber> outPorts = new ArrayList<PortNumber>(); 362 List<PortNumber> outPorts = new ArrayList<PortNumber>();
......