Srikanth Vavilapalli
Committed by Gerrit Code Review

ONOS-985: Sample integration test application for group subsystem

Change-Id: I68352f922e5c7a0800fcc4fa839955769bf925a6
Showing 20 changed files with 1203 additions and 19 deletions
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2014 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0"
18 + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
20 + <modelVersion>4.0.0</modelVersion>
21 +
22 + <parent>
23 + <groupId>org.onosproject</groupId>
24 + <artifactId>onos-apps</artifactId>
25 + <version>1.1.0-SNAPSHOT</version>
26 + <relativePath>../pom.xml</relativePath>
27 + </parent>
28 +
29 + <artifactId>onos-app-grouphandler</artifactId>
30 + <packaging>bundle</packaging>
31 +
32 + <description>ONOS sample application using group service</description>
33 +
34 + <dependencies>
35 + <dependency>
36 + <groupId>org.onosproject</groupId>
37 + <artifactId>onos-api</artifactId>
38 + <version>${project.version}</version>
39 + </dependency>
40 + <dependency>
41 + <groupId>org.onosproject</groupId>
42 + <artifactId>onlab-osgi</artifactId>
43 + <version>${project.version}</version>
44 + </dependency>
45 + <dependency>
46 + <groupId>org.onosproject</groupId>
47 + <artifactId>onlab-nio</artifactId>
48 + <version>${project.version}</version>
49 + </dependency>
50 + <dependency>
51 + <groupId>org.onosproject</groupId>
52 + <artifactId>onlab-netty</artifactId>
53 + <version>${project.version}</version>
54 + </dependency>
55 + <dependency>
56 + <groupId>org.apache.karaf.shell</groupId>
57 + <artifactId>org.apache.karaf.shell.console</artifactId>
58 + </dependency>
59 + <dependency>
60 + <groupId>org.onosproject</groupId>
61 + <artifactId>onlab-misc</artifactId>
62 + </dependency>
63 + <dependency>
64 + <groupId>com.google.guava</groupId>
65 + <artifactId>guava</artifactId>
66 + </dependency>
67 + <dependency>
68 + <groupId>org.osgi</groupId>
69 + <artifactId>org.osgi.core</artifactId>
70 + </dependency>
71 + </dependencies>
72 +</project>
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.grouphandler;
17 +
18 +import java.util.Arrays;
19 +import java.util.HashSet;
20 +import java.util.List;
21 +import java.util.Set;
22 +
23 +import org.onosproject.core.ApplicationId;
24 +import org.onosproject.net.DeviceId;
25 +import org.onosproject.net.Link;
26 +import org.onosproject.net.flow.DefaultTrafficTreatment;
27 +import org.onosproject.net.flow.TrafficTreatment;
28 +import org.onosproject.net.group.DefaultGroupBucket;
29 +import org.onosproject.net.group.GroupBucket;
30 +import org.onosproject.net.group.GroupBuckets;
31 +import org.onosproject.net.group.GroupService;
32 +import org.onosproject.net.link.LinkService;
33 +
34 +/**
35 + * Default ECMP group handler creation module for an edge device.
36 + * This component creates a set of ECMP groups for every neighbor
37 + * that this device is connected to.
38 + * For example, consider a network of 4 devices: D0 (Segment ID: 100),
39 + * D1 (Segment ID: 101), D2 (Segment ID: 102) and D3 (Segment ID: 103),
40 + * where D0 and D3 are edge devices and D1 and D2 are transit devices.
41 + * Assume device D0 is connected to 2 neighbors (D1 and D2 ).
42 + * The following groups will be created in D0:
43 + * 1) all ports to D1 + with no label push,
44 + * 2) all ports to D1 + with label 102 pushed,
45 + * 3) all ports to D1 + with label 103 pushed,
46 + * 4) all ports to D2 + with no label push,
47 + * 5) all ports to D2 + with label 101 pushed,
48 + * 6) all ports to D2 + with label 103 pushed,
49 + * 7) all ports to D1 and D2 + with label 103 pushed
50 + */
51 +public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
52 +
53 + protected DefaultEdgeGroupHandler(DeviceId deviceId,
54 + ApplicationId appId,
55 + DeviceProperties config,
56 + LinkService linkService,
57 + GroupService groupService) {
58 + super(deviceId, appId, config, linkService, groupService);
59 + }
60 +
61 + @Override
62 + public void createGroups() {
63 + log.debug("Creating default groups "
64 + + "for edge device {}", deviceId);
65 + Set<DeviceId> neighbors = devicePortMap.keySet();
66 + if (neighbors == null || neighbors.isEmpty()) {
67 + return;
68 + }
69 +
70 + // Create all possible Neighbor sets from this router
71 + Set<Set<DeviceId>> powerSet = getPowerSetOfNeighbors(neighbors);
72 + log.trace("createGroupsAtEdgeRouter: The size of neighbor powerset "
73 + + "for sw {} is {}", deviceId, powerSet.size());
74 + Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
75 + for (Set<DeviceId> combo : powerSet) {
76 + if (combo.isEmpty()) {
77 + continue;
78 + }
79 + List<Integer> groupSegmentIds =
80 + getSegmentIdsTobePairedWithNeighborSet(combo);
81 + for (Integer sId : groupSegmentIds) {
82 + NeighborSet ns = new NeighborSet(combo, sId);
83 + log.trace("createGroupsAtEdgeRouter: sw {} "
84 + + "combo {} sId {} ns {}",
85 + deviceId, combo, sId, ns);
86 + nsSet.add(ns);
87 + }
88 + }
89 + log.trace("createGroupsAtEdgeRouter: The neighborset "
90 + + "with label for sw {} is {}",
91 + deviceId, nsSet);
92 +
93 + createGroupsFromNeighborsets(nsSet);
94 + }
95 +
96 + @Override
97 + protected void newNeighbor(Link newNeighborLink) {
98 + log.debug("New Neighbor: Updating groups "
99 + + "for edge device {}", deviceId);
100 + // Recompute neighbor power set
101 + addNeighborAtPort(newNeighborLink.dst().deviceId(),
102 + newNeighborLink.src().port());
103 + // Compute new neighbor sets due to the addition of new neighbor
104 + Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
105 + newNeighborLink.dst().deviceId(),
106 + devicePortMap.keySet());
107 + createGroupsFromNeighborsets(nsSet);
108 + }
109 +
110 + @Override
111 + protected void newPortToExistingNeighbor(Link newNeighborLink) {
112 + log.debug("New port to existing neighbor: Updating "
113 + + "groups for edge device {}", deviceId);
114 + addNeighborAtPort(newNeighborLink.dst().deviceId(),
115 + newNeighborLink.src().port());
116 + Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
117 + newNeighborLink.dst().deviceId(),
118 + devicePortMap.keySet());
119 + for (NeighborSet ns : nsSet) {
120 + // Create the new bucket to be updated
121 + TrafficTreatment.Builder tBuilder =
122 + DefaultTrafficTreatment.builder();
123 + tBuilder.setOutput(newNeighborLink.src().port())
124 + .setEthDst(deviceConfig.getDeviceMac(
125 + newNeighborLink.dst().deviceId()))
126 + .setEthSrc(nodeMacAddr)
127 + .pushMpls()
128 + .setMpls(ns.getEdgeLabel());
129 + GroupBucket updatedBucket = DefaultGroupBucket.
130 + createSelectGroupBucket(tBuilder.build());
131 + GroupBuckets updatedBuckets = new GroupBuckets(
132 + Arrays.asList(updatedBucket));
133 + log.debug("newPortToExistingNeighborAtEdgeRouter: "
134 + + "groupService.addBucketsToGroup for neighborset{}", ns);
135 + groupService.addBucketsToGroup(deviceId, ns, updatedBuckets, ns, appId);
136 + }
137 + }
138 +
139 + @Override
140 + protected Set<NeighborSet> computeImpactedNeighborsetForPortEvent(
141 + DeviceId impactedNeighbor,
142 + Set<DeviceId> updatedNeighbors) {
143 + Set<Set<DeviceId>> powerSet = getPowerSetOfNeighbors(updatedNeighbors);
144 +
145 + Set<DeviceId> tmp = new HashSet<DeviceId>();
146 + tmp.addAll(updatedNeighbors);
147 + tmp.remove(impactedNeighbor);
148 + Set<Set<DeviceId>> tmpPowerSet = getPowerSetOfNeighbors(tmp);
149 +
150 + // Compute the impacted neighbor sets
151 + powerSet.removeAll(tmpPowerSet);
152 +
153 + Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
154 + for (Set<DeviceId> combo : powerSet) {
155 + if (combo.isEmpty()) {
156 + continue;
157 + }
158 + List<Integer> groupSegmentIds =
159 + getSegmentIdsTobePairedWithNeighborSet(combo);
160 + for (Integer sId : groupSegmentIds) {
161 + NeighborSet ns = new NeighborSet(combo, sId);
162 + log.trace("computeImpactedNeighborsetForPortEvent: sw {} "
163 + + "combo {} sId {} ns {}",
164 + deviceId, combo, sId, ns);
165 + nsSet.add(ns);
166 + }
167 + }
168 + log.trace("computeImpactedNeighborsetForPortEvent: The neighborset "
169 + + "with label for sw {} is {}",
170 + deviceId, nsSet);
171 + return nsSet;
172 + }
173 +
174 +}
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.grouphandler;
17 +
18 +import static org.slf4j.LoggerFactory.getLogger;
19 +
20 +import java.util.Arrays;
21 +import java.util.HashMap;
22 +import java.util.List;
23 +
24 +import org.apache.felix.scr.annotations.Activate;
25 +import org.apache.felix.scr.annotations.Component;
26 +import org.apache.felix.scr.annotations.Deactivate;
27 +import org.apache.felix.scr.annotations.Reference;
28 +import org.apache.felix.scr.annotations.ReferenceCardinality;
29 +import org.onlab.packet.MacAddress;
30 +import org.onosproject.core.ApplicationId;
31 +import org.onosproject.core.CoreService;
32 +import org.onosproject.net.Device;
33 +import org.onosproject.net.DeviceId;
34 +import org.onosproject.net.device.DeviceEvent;
35 +import org.onosproject.net.device.DeviceListener;
36 +import org.onosproject.net.device.DeviceService;
37 +import org.onosproject.net.group.GroupService;
38 +import org.onosproject.net.link.LinkEvent;
39 +import org.onosproject.net.link.LinkListener;
40 +import org.onosproject.net.link.LinkService;
41 +import org.onosproject.net.topology.TopologyService;
42 +import org.slf4j.Logger;
43 +
44 +/**
45 + * Sample application to verify group subsystem end to end.
46 + * This application expects a network of maximum of six connected
47 + * devices for the test to work. For every device in the network,
48 + * this test application launches a default group handler function
49 + * that creates ECMP groups for every neighbor the device is
50 + * connected to.
51 + */
52 +@Component(immediate = true)
53 +public class DefaultGroupHandlerApp {
54 +
55 + private final Logger log = getLogger(getClass());
56 +
57 + private final DeviceProperties config = new DeviceConfiguration();
58 + private ApplicationId appId;
59 + private HashMap<DeviceId, DefaultGroupHandler> dghMap =
60 + new HashMap<DeviceId, DefaultGroupHandler>();
61 +
62 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 + protected TopologyService topologyService;
64 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 + protected DeviceService deviceService;
66 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 + protected LinkService linkService;
68 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 + protected GroupService groupService;
70 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 + protected CoreService coreService;
72 +
73 + private DeviceListener deviceListener = new InternalDeviceListener();
74 + private LinkListener linkListener = new InternalLinkListener();
75 +
76 + @Activate
77 + public void activate() {
78 + appId = coreService.registerApplication("org.onosproject.defaultgrouphandler");
79 + log.info("DefaultGroupHandlerApp Activating");
80 + deviceService.addListener(deviceListener);
81 + linkService.addListener(linkListener);
82 + for (Device device: deviceService.getDevices()) {
83 + log.debug("Initiating default group handling for {}", device.id());
84 + DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(device.id(),
85 + appId,
86 + config,
87 + linkService,
88 + groupService);
89 + dgh.createGroups();
90 + dghMap.put(device.id(), dgh);
91 + }
92 + log.info("Activated");
93 + }
94 +
95 + @Deactivate
96 + public void deactivate() {
97 + dghMap.clear();
98 + }
99 +
100 + public class DeviceConfiguration implements DeviceProperties {
101 + private final List<Integer> allSegmentIds =
102 + Arrays.asList(101, 102, 103, 104, 105, 106);
103 + private HashMap<DeviceId, Integer> deviceSegmentIdMap =
104 + new HashMap<DeviceId, Integer>() {
105 + {
106 + put(DeviceId.deviceId("of:0000000000000001"), 101);
107 + put(DeviceId.deviceId("of:0000000000000002"), 102);
108 + put(DeviceId.deviceId("of:0000000000000003"), 103);
109 + put(DeviceId.deviceId("of:0000000000000004"), 104);
110 + put(DeviceId.deviceId("of:0000000000000005"), 105);
111 + put(DeviceId.deviceId("of:0000000000000006"), 106);
112 + }
113 + };
114 + private final HashMap<DeviceId, MacAddress> deviceMacMap =
115 + new HashMap<DeviceId, MacAddress>() {
116 + {
117 + put(DeviceId.deviceId("of:0000000000000001"),
118 + MacAddress.valueOf("00:00:00:00:00:01"));
119 + put(DeviceId.deviceId("of:0000000000000002"),
120 + MacAddress.valueOf("00:00:00:00:00:02"));
121 + put(DeviceId.deviceId("of:0000000000000003"),
122 + MacAddress.valueOf("00:00:00:00:00:03"));
123 + put(DeviceId.deviceId("of:0000000000000004"),
124 + MacAddress.valueOf("00:00:00:00:00:04"));
125 + put(DeviceId.deviceId("of:0000000000000005"),
126 + MacAddress.valueOf("00:00:00:00:00:05"));
127 + put(DeviceId.deviceId("of:0000000000000006"),
128 + MacAddress.valueOf("00:00:00:00:00:06"));
129 + }
130 + };
131 +
132 + @Override
133 + public int getSegmentId(DeviceId deviceId) {
134 + if (deviceSegmentIdMap.get(deviceId) != null) {
135 + log.debug("getSegmentId for device{} is {}",
136 + deviceId,
137 + deviceSegmentIdMap.get(deviceId));
138 + return deviceSegmentIdMap.get(deviceId);
139 + } else {
140 + throw new IllegalStateException();
141 + }
142 + }
143 + @Override
144 + public MacAddress getDeviceMac(DeviceId deviceId) {
145 + if (deviceMacMap.get(deviceId) != null) {
146 + log.debug("getDeviceMac for device{} is {}",
147 + deviceId,
148 + deviceMacMap.get(deviceId));
149 + return deviceMacMap.get(deviceId);
150 + } else {
151 + throw new IllegalStateException();
152 + }
153 + }
154 + @Override
155 + public boolean isEdgeDevice(DeviceId deviceId) {
156 + return true;
157 + }
158 + @Override
159 + public List<Integer> getAllDeviceSegmentIds() {
160 + return allSegmentIds;
161 + }
162 + }
163 +
164 + private class InternalDeviceListener implements DeviceListener {
165 +
166 + @Override
167 + public void event(DeviceEvent event) {
168 + switch (event.type()) {
169 + case DEVICE_ADDED:
170 + log.debug("Initiating default group handling for {}", event.subject().id());
171 + DefaultGroupHandler dgh = DefaultGroupHandler.createGroupHandler(
172 + event.subject().id(),
173 + appId,
174 + config,
175 + linkService,
176 + groupService);
177 + dgh.createGroups();
178 + dghMap.put(event.subject().id(), dgh);
179 + break;
180 + case PORT_REMOVED:
181 + if (dghMap.get(event.subject().id()) != null) {
182 + dghMap.get(event.subject().id()).portDown(event.port().number());
183 + }
184 + break;
185 + default:
186 + break;
187 + }
188 +
189 + }
190 + }
191 +
192 + private class InternalLinkListener implements LinkListener {
193 +
194 + @Override
195 + public void event(LinkEvent event) {
196 + switch (event.type()) {
197 + case LINK_ADDED:
198 + if (dghMap.get(event.subject().src().deviceId()) != null) {
199 + dghMap.get(event.subject().src().deviceId()).linkUp(event.subject());
200 + }
201 + break;
202 + default:
203 + break;
204 + }
205 + }
206 +
207 + }
208 +}
...\ No newline at end of file ...\ No newline at end of file
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.grouphandler;
17 +
18 +import java.util.Arrays;
19 +import java.util.HashSet;
20 +import java.util.Set;
21 +
22 +import org.onosproject.core.ApplicationId;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.Link;
25 +import org.onosproject.net.flow.DefaultTrafficTreatment;
26 +import org.onosproject.net.flow.TrafficTreatment;
27 +import org.onosproject.net.group.DefaultGroupBucket;
28 +import org.onosproject.net.group.GroupBucket;
29 +import org.onosproject.net.group.GroupBuckets;
30 +import org.onosproject.net.group.GroupService;
31 +import org.onosproject.net.link.LinkService;
32 +
33 +/**
34 + * Default ECMP group handler creation module for a transit device.
35 + * This component creates a set of ECMP groups for every neighbor
36 + * that this device is connected to.
37 + * For example, consider a network of 4 devices: D0 (Segment ID: 100),
38 + * D1 (Segment ID: 101), D2 (Segment ID: 102) and D3 (Segment ID: 103),
39 + * where D0 and D3 are edge devices and D1 and D2 are transit devices.
40 + * Assume transit device D1 is connected to 2 neighbors (D0 and D3 ).
41 + * The following groups will be created in D1:
42 + * 1) all ports to D0 + with no label push,
43 + * 2) all ports to D3 + with no label push,
44 + */
45 +public class DefaultTransitGroupHandler extends DefaultGroupHandler {
46 +
47 + protected DefaultTransitGroupHandler(DeviceId deviceId,
48 + ApplicationId appId,
49 + DeviceProperties config,
50 + LinkService linkService,
51 + GroupService groupService) {
52 + super(deviceId, appId, config, linkService, groupService);
53 + }
54 +
55 + @Override
56 + public void createGroups() {
57 + Set<DeviceId> neighbors = devicePortMap.keySet();
58 + if (neighbors == null || neighbors.isEmpty()) {
59 + return;
60 + }
61 +
62 + // Create all possible Neighbor sets from this router
63 + // NOTE: Avoid any pairings of edge routers only
64 + Set<Set<DeviceId>> sets = getPowerSetOfNeighbors(neighbors);
65 + sets = filterEdgeRouterOnlyPairings(sets);
66 + log.debug("createGroupsAtTransitRouter: The size of neighbor powerset "
67 + + "for sw {} is {}", deviceId, sets.size());
68 + Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
69 + for (Set<DeviceId> combo : sets) {
70 + if (combo.isEmpty()) {
71 + continue;
72 + }
73 + NeighborSet ns = new NeighborSet(combo);
74 + log.debug("createGroupsAtTransitRouter: sw {} combo {} ns {}",
75 + deviceId, combo, ns);
76 + nsSet.add(ns);
77 + }
78 + log.debug("createGroupsAtTransitRouter: The neighborset with label "
79 + + "for sw {} is {}", deviceId, nsSet);
80 +
81 + createGroupsFromNeighborsets(nsSet);
82 + }
83 +
84 + @Override
85 + protected void newNeighbor(Link newNeighborLink) {
86 + log.debug("New Neighbor: Updating groups for "
87 + + "transit device {}", deviceId);
88 + // Recompute neighbor power set
89 + addNeighborAtPort(newNeighborLink.dst().deviceId(),
90 + newNeighborLink.src().port());
91 + // Compute new neighbor sets due to the addition of new neighbor
92 + Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
93 + newNeighborLink.dst().deviceId(),
94 + devicePortMap.keySet());
95 + createGroupsFromNeighborsets(nsSet);
96 + }
97 +
98 + @Override
99 + protected void newPortToExistingNeighbor(Link newNeighborLink) {
100 + log.debug("New port to existing neighbor: Updating "
101 + + "groups for transit device {}", deviceId);
102 + addNeighborAtPort(newNeighborLink.dst().deviceId(),
103 + newNeighborLink.src().port());
104 + Set<NeighborSet> nsSet = computeImpactedNeighborsetForPortEvent(
105 + newNeighborLink.dst().deviceId(),
106 + devicePortMap.keySet());
107 + for (NeighborSet ns : nsSet) {
108 + // Create the new bucket to be updated
109 + TrafficTreatment.Builder tBuilder =
110 + DefaultTrafficTreatment.builder();
111 + tBuilder.setOutput(newNeighborLink.src().port())
112 + .setEthDst(deviceConfig.getDeviceMac(
113 + newNeighborLink.dst().deviceId()))
114 + .setEthSrc(nodeMacAddr)
115 + .pushMpls()
116 + .setMpls(ns.getEdgeLabel());
117 + GroupBucket updatedBucket = DefaultGroupBucket.
118 + createSelectGroupBucket(tBuilder.build());
119 + GroupBuckets updatedBuckets = new GroupBuckets(
120 + Arrays.asList(updatedBucket));
121 + log.debug("newPortToExistingNeighborAtEdgeRouter: "
122 + + "groupService.addBucketsToGroup for neighborset{}", ns);
123 + groupService.addBucketsToGroup(deviceId, ns, updatedBuckets, ns, appId);
124 + }
125 + }
126 +
127 + @Override
128 + protected Set<NeighborSet> computeImpactedNeighborsetForPortEvent(
129 + DeviceId impactedNeighbor,
130 + Set<DeviceId> updatedNeighbors) {
131 + Set<Set<DeviceId>> powerSet = getPowerSetOfNeighbors(updatedNeighbors);
132 +
133 + Set<DeviceId> tmp = updatedNeighbors;
134 + tmp.remove(impactedNeighbor);
135 + Set<Set<DeviceId>> tmpPowerSet = getPowerSetOfNeighbors(tmp);
136 +
137 + // Compute the impacted neighbor sets
138 + powerSet.removeAll(tmpPowerSet);
139 +
140 + powerSet = filterEdgeRouterOnlyPairings(powerSet);
141 + Set<NeighborSet> nsSet = new HashSet<NeighborSet>();
142 + for (Set<DeviceId> combo : powerSet) {
143 + if (combo.isEmpty()) {
144 + continue;
145 + }
146 + NeighborSet ns = new NeighborSet(combo);
147 + log.debug("createGroupsAtTransitRouter: sw {} combo {} ns {}",
148 + deviceId, combo, ns);
149 + nsSet.add(ns);
150 + }
151 + log.debug("computeImpactedNeighborsetForPortEvent: The neighborset with label "
152 + + "for sw {} is {}", deviceId, nsSet);
153 +
154 + return nsSet;
155 + }
156 +
157 + private Set<Set<DeviceId>> filterEdgeRouterOnlyPairings(Set<Set<DeviceId>> sets) {
158 + Set<Set<DeviceId>> fiteredSets = new HashSet<Set<DeviceId>>();
159 + for (Set<DeviceId> deviceSubSet : sets) {
160 + if (deviceSubSet.size() > 1) {
161 + boolean avoidEdgeRouterPairing = true;
162 + for (DeviceId device : deviceSubSet) {
163 + if (!deviceConfig.isEdgeDevice(device)) {
164 + avoidEdgeRouterPairing = false;
165 + break;
166 + }
167 + }
168 + if (!avoidEdgeRouterPairing) {
169 + fiteredSets.add(deviceSubSet);
170 + }
171 + } else {
172 + fiteredSets.add(deviceSubSet);
173 + }
174 + }
175 + return fiteredSets;
176 + }
177 +}
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.grouphandler;
17 +
18 +import java.util.List;
19 +
20 +import org.onlab.packet.MacAddress;
21 +import org.onosproject.net.DeviceId;
22 +
23 +/**
24 + * Mechanism through which group handler module retrieves
25 + * the device specific attributes such as segment ID,
26 + * Mac address...etc from group handler applications.
27 + */
28 +public interface DeviceProperties {
29 + /**
30 + * Returns the segment id of a device to be used in group creation.
31 + *
32 + * @param deviceId device identifier
33 + * @return segment id of a device
34 + */
35 + int getSegmentId(DeviceId deviceId);
36 + /**
37 + * Returns the Mac address of a device to be used in group creation.
38 + *
39 + * @param deviceId device identifier
40 + * @return mac address of a device
41 + */
42 + MacAddress getDeviceMac(DeviceId deviceId);
43 + /**
44 + * Indicates whether a device is edge device or transit/core device.
45 + *
46 + * @param deviceId device identifier
47 + * @return boolean
48 + */
49 + boolean isEdgeDevice(DeviceId deviceId);
50 + /**
51 + * Returns all segment IDs to be considered in building auto
52 + *
53 + * created groups.
54 + * @return list of segment IDs
55 + */
56 + List<Integer> getAllDeviceSegmentIds();
57 +}
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.grouphandler;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import org.onosproject.net.PortNumber;
21 +import org.onosproject.net.group.GroupKey;
22 +
23 +/**
24 + * Representation of policy group bucket identifier. Not exposed to
25 + * the application and only to be used internally.
26 + */
27 +public class GroupBucketIdentifier {
28 + private int label;
29 + private BucketOutputType type;
30 + private PortNumber outPort;
31 + private GroupKey outGroup;
32 +
33 + protected enum BucketOutputType {
34 + PORT,
35 + GROUP
36 + }
37 +
38 + protected GroupBucketIdentifier(int label,
39 + PortNumber outPort) {
40 + this.label = label;
41 + this.type = BucketOutputType.PORT;
42 + this.outPort = checkNotNull(outPort);
43 + this.outGroup = null;
44 + }
45 +
46 + protected GroupBucketIdentifier(int label,
47 + GroupKey outGroup) {
48 + this.label = label;
49 + this.type = BucketOutputType.GROUP;
50 + this.outPort = null;
51 + this.outGroup = checkNotNull(outGroup);
52 + }
53 +
54 + protected int label() {
55 + return this.label;
56 + }
57 +
58 + protected BucketOutputType type() {
59 + return this.type;
60 + }
61 +
62 + protected PortNumber outPort() {
63 + return this.outPort;
64 + }
65 +
66 + protected GroupKey outGroup() {
67 + return this.outGroup;
68 + }
69 +}
70 +
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.grouphandler;
18 +
19 +import static com.google.common.base.Preconditions.checkNotNull;
20 +
21 +import java.util.HashSet;
22 +import java.util.Objects;
23 +import java.util.Set;
24 +
25 +import org.onosproject.net.DeviceId;
26 +import org.onosproject.net.group.GroupKey;
27 +
28 +/**
29 + * Representation of a set of neighbor switch dpids along with edge node
30 + * label. Meant to be used as a lookup-key in a hash-map to retrieve an
31 + * ECMP-group that hashes packets to a set of ports connecting to the
32 + * neighbors in this set.
33 + */
34 +public class NeighborSet implements GroupKey {
35 + private final Set<DeviceId> neighbors;
36 + private final int edgeLabel;
37 +
38 + /**
39 + * Constructor with set of neighbors. Edge label is
40 + * default to -1.
41 + *
42 + * @param neighbors set of neighbors to be part of neighbor set
43 + */
44 + public NeighborSet(Set<DeviceId> neighbors) {
45 + checkNotNull(neighbors);
46 + this.edgeLabel = -1;
47 + this.neighbors = new HashSet<DeviceId>();
48 + this.neighbors.addAll(neighbors);
49 + }
50 +
51 + /**
52 + * Constructor with set of neighbors and edge label.
53 + *
54 + * @param neighbors set of neighbors to be part of neighbor set
55 + * @param edgeLabel label to be pushed as part of group operation
56 + */
57 + public NeighborSet(Set<DeviceId> neighbors, int edgeLabel) {
58 + checkNotNull(neighbors);
59 + this.edgeLabel = edgeLabel;
60 + this.neighbors = new HashSet<DeviceId>();
61 + this.neighbors.addAll(neighbors);
62 + }
63 +
64 + /**
65 + * Default constructor for kryo serialization.
66 + */
67 + public NeighborSet() {
68 + this.edgeLabel = -1;
69 + this.neighbors = new HashSet<DeviceId>();
70 + }
71 +
72 + /**
73 + * Gets the neighbors part of neighbor set.
74 + *
75 + * @return set of neighbor identifiers
76 + */
77 + public Set<DeviceId> getDeviceIds() {
78 + return neighbors;
79 + }
80 +
81 + /**
82 + * Gets the label associated with neighbor set.
83 + *
84 + * @return integer
85 + */
86 + public int getEdgeLabel() {
87 + return edgeLabel;
88 + }
89 +
90 + // The list of neighbor ids and label are used for comparison.
91 + @Override
92 + public boolean equals(Object o) {
93 + if (this == o) {
94 + return true;
95 + }
96 + if (!(o instanceof NeighborSet)) {
97 + return false;
98 + }
99 + NeighborSet that = (NeighborSet) o;
100 + return (this.neighbors.containsAll(that.neighbors) &&
101 + that.neighbors.containsAll(this.neighbors) &&
102 + (this.edgeLabel == that.edgeLabel));
103 + }
104 +
105 + // The list of neighbor ids and label are used for comparison.
106 + @Override
107 + public int hashCode() {
108 + int result = 17;
109 + int combinedHash = 0;
110 + for (DeviceId d : neighbors) {
111 + combinedHash = combinedHash + Objects.hash(d);
112 + }
113 + result = 31 * result + combinedHash + Objects.hash(edgeLabel);
114 +
115 + return result;
116 + }
117 +
118 + @Override
119 + public String toString() {
120 + return " Neighborset Sw: " + neighbors
121 + + " and Label: " + edgeLabel;
122 + }
123 +}
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.grouphandler;
17 +
18 +import java.util.List;
19 +
20 +import org.onosproject.net.group.GroupKey;
21 +
22 +/**
23 + * Representation of policy based group identifiers.
24 + * Opaque to group handler applications and only the outermost
25 + * policy group identifier in a chain is visible to the applications.
26 + */
27 +public class PolicyGroupIdentifier implements GroupKey {
28 + private String id;
29 + private List<PolicyGroupParams> inputParams;
30 + private List<GroupBucketIdentifier> bucketIds;
31 +
32 + /**
33 + * Constructor.
34 + *
35 + * @param id unique identifier associated with the policy group
36 + * @param input policy group params associated with this group
37 + * @param bucketIds buckets associated with this group
38 + */
39 + protected PolicyGroupIdentifier(String id,
40 + List<PolicyGroupParams> input,
41 + List<GroupBucketIdentifier> bucketIds) {
42 + this.id = id;
43 + this.inputParams = input;
44 + this.bucketIds = bucketIds;
45 + }
46 +
47 + /**
48 + * Returns the bucket identifier list associated with the policy
49 + * group identifier.
50 + *
51 + * @return list of bucket identifier
52 + */
53 + protected List<GroupBucketIdentifier> bucketIds() {
54 + return this.bucketIds;
55 + }
56 +
57 + @Override
58 + public int hashCode() {
59 + int result = 17;
60 + int combinedHash = 0;
61 + for (PolicyGroupParams input:inputParams) {
62 + combinedHash = combinedHash + input.hashCode();
63 + }
64 + for (GroupBucketIdentifier bucketId:bucketIds) {
65 + combinedHash = combinedHash + bucketId.hashCode();
66 + }
67 + result = 31 * result + combinedHash;
68 +
69 + return result;
70 + }
71 +
72 + @Override
73 + public boolean equals(Object obj) {
74 + if (this == obj) {
75 + return true;
76 + }
77 +
78 + if (obj instanceof PolicyGroupIdentifier) {
79 + PolicyGroupIdentifier that = (PolicyGroupIdentifier) obj;
80 + boolean result = this.id.equals(that.id);
81 + result = result &&
82 + this.inputParams.containsAll(that.inputParams) &&
83 + that.inputParams.containsAll(this.inputParams);
84 + result = result &&
85 + this.bucketIds.containsAll(that.bucketIds) &&
86 + that.bucketIds.containsAll(this.bucketIds);
87 + return result;
88 + }
89 +
90 + return false;
91 + }
92 +}
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.grouphandler;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import java.util.List;
21 +import java.util.Objects;
22 +
23 +import org.onosproject.net.PortNumber;
24 +
25 +/**
26 + * Representation of parameters used to create policy based groups.
27 + */
28 +public class PolicyGroupParams {
29 + private final List<PortNumber> ports;
30 + private final List<Integer> labelStack;
31 +
32 + /**
33 + * Constructor.
34 + *
35 + * @param labelStack mpls label stack to be applied on the ports
36 + * @param ports ports to be part of the policy group
37 + */
38 + public PolicyGroupParams(List<Integer> labelStack,
39 + List<PortNumber> ports) {
40 + this.ports = checkNotNull(ports);
41 + this.labelStack = checkNotNull(labelStack);
42 + }
43 +
44 + /**
45 + * Returns the ports associated with the policy group params.
46 + *
47 + * @return list of port numbers
48 + */
49 + public List<PortNumber> getPorts() {
50 + return ports;
51 + }
52 +
53 + /**
54 + * Returns the label stack associated with the policy group params.
55 + *
56 + * @return list of integers
57 + */
58 + public List<Integer> getLabelStack() {
59 + return labelStack;
60 + }
61 +
62 + @Override
63 + public int hashCode() {
64 + int result = 17;
65 + int combinedHash = 0;
66 + for (PortNumber port:ports) {
67 + combinedHash = combinedHash + port.hashCode();
68 + }
69 + combinedHash = combinedHash + Objects.hash(labelStack);
70 + result = 31 * result + combinedHash;
71 +
72 + return result;
73 + }
74 +
75 + @Override
76 + public boolean equals(Object obj) {
77 + if (this == obj) {
78 + return true;
79 + }
80 +
81 + if (obj instanceof PolicyGroupParams) {
82 + PolicyGroupParams that = (PolicyGroupParams) obj;
83 + boolean result = this.labelStack.equals(that.labelStack);
84 + result = result &&
85 + this.ports.containsAll(that.ports) &&
86 + that.ports.containsAll(this.ports);
87 + return result;
88 + }
89 +
90 + return false;
91 + }
92 +}
...@@ -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 static com.google.common.base.MoreObjects.toStringHelper;
18 import static org.slf4j.LoggerFactory.getLogger; 19 import static org.slf4j.LoggerFactory.getLogger;
19 20
20 import java.util.Objects; 21 import java.util.Objects;
...@@ -205,4 +206,13 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -205,4 +206,13 @@ public class DefaultGroup extends DefaultGroupDescription
205 } 206 }
206 return false; 207 return false;
207 } 208 }
209 +
210 + @Override
211 + public String toString() {
212 + return toStringHelper(this)
213 + .add("description", super.toString())
214 + .add("groupid", id)
215 + .add("state", state)
216 + .toString();
217 + }
208 } 218 }
......
...@@ -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 static com.google.common.base.MoreObjects.toStringHelper;
18 import static com.google.common.base.Preconditions.checkArgument; 19 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkNotNull;
20 21
...@@ -212,4 +213,11 @@ public final class DefaultGroupBucket implements GroupBucket { ...@@ -212,4 +213,11 @@ public final class DefaultGroupBucket implements GroupBucket {
212 return false; 213 return false;
213 } 214 }
214 215
216 + @Override
217 + public String toString() {
218 + return toStringHelper(this)
219 + .add("type", type)
220 + .add("treatment", treatment)
221 + .toString();
222 + }
215 } 223 }
......
...@@ -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 static com.google.common.base.MoreObjects.toStringHelper;
18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkNotNull;
19 20
20 import java.util.Objects; 21 import java.util.Objects;
...@@ -168,4 +169,13 @@ public class DefaultGroupDescription implements GroupDescription { ...@@ -168,4 +169,13 @@ public class DefaultGroupDescription implements GroupDescription {
168 return false; 169 return false;
169 } 170 }
170 171
172 + @Override
173 + public String toString() {
174 + return toStringHelper(this)
175 + .add("deviceId", deviceId)
176 + .add("type", type)
177 + .add("buckets", buckets)
178 + .add("appId", appId)
179 + .toString();
180 + }
171 } 181 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -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 static com.google.common.base.MoreObjects.toStringHelper;
18 import static com.google.common.base.Preconditions.checkNotNull; 19 import static com.google.common.base.Preconditions.checkNotNull;
19 20
20 import java.util.List; 21 import java.util.List;
...@@ -66,4 +67,10 @@ public final class GroupBuckets { ...@@ -66,4 +67,10 @@ public final class GroupBuckets {
66 return false; 67 return false;
67 } 68 }
68 69
70 + @Override
71 + public String toString() {
72 + return toStringHelper(this)
73 + .add("buckets", buckets)
74 + .toString();
75 + }
69 } 76 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -132,8 +132,9 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { ...@@ -132,8 +132,9 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> {
132 * Indicates the first group audit is completed. 132 * Indicates the first group audit is completed.
133 * 133 *
134 * @param deviceId the device ID 134 * @param deviceId the device ID
135 + * @param completed initial audit status
135 */ 136 */
136 - void deviceInitialAuditCompleted(DeviceId deviceId); 137 + void deviceInitialAuditCompleted(DeviceId deviceId, boolean completed);
137 138
138 /** 139 /**
139 * Retrieves the initial group audit status for a device. 140 * Retrieves the initial group audit status for a device.
......
...@@ -32,6 +32,9 @@ import org.onosproject.core.ApplicationId; ...@@ -32,6 +32,9 @@ import org.onosproject.core.ApplicationId;
32 import org.onosproject.event.AbstractListenerRegistry; 32 import org.onosproject.event.AbstractListenerRegistry;
33 import org.onosproject.event.EventDeliveryService; 33 import org.onosproject.event.EventDeliveryService;
34 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
35 +import org.onosproject.net.device.DeviceEvent;
36 +import org.onosproject.net.device.DeviceListener;
37 +import org.onosproject.net.device.DeviceService;
35 import org.onosproject.net.group.Group; 38 import org.onosproject.net.group.Group;
36 import org.onosproject.net.group.GroupBuckets; 39 import org.onosproject.net.group.GroupBuckets;
37 import org.onosproject.net.group.GroupDescription; 40 import org.onosproject.net.group.GroupDescription;
...@@ -67,17 +70,22 @@ public class GroupManager ...@@ -67,17 +70,22 @@ public class GroupManager
67 private final AbstractListenerRegistry<GroupEvent, GroupListener> 70 private final AbstractListenerRegistry<GroupEvent, GroupListener>
68 listenerRegistry = new AbstractListenerRegistry<>(); 71 listenerRegistry = new AbstractListenerRegistry<>();
69 private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate(); 72 private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate();
73 + private final DeviceListener deviceListener = new InternalDeviceListener();
70 74
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 75 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected GroupStore store; 76 protected GroupStore store;
73 77
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 + protected DeviceService deviceService;
80 +
81 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected EventDeliveryService eventDispatcher; 82 protected EventDeliveryService eventDispatcher;
76 83
77 @Activate 84 @Activate
78 public void activate() { 85 public void activate() {
79 store.setDelegate(delegate); 86 store.setDelegate(delegate);
80 eventDispatcher.addSink(GroupEvent.class, listenerRegistry); 87 eventDispatcher.addSink(GroupEvent.class, listenerRegistry);
88 + deviceService.addListener(deviceListener);
81 log.info("Started"); 89 log.info("Started");
82 } 90 }
83 91
...@@ -232,6 +240,8 @@ public class GroupManager ...@@ -232,6 +240,8 @@ public class GroupManager
232 GroupOperations groupOps = null; 240 GroupOperations groupOps = null;
233 switch (event.type()) { 241 switch (event.type()) {
234 case GROUP_ADD_REQUESTED: 242 case GROUP_ADD_REQUESTED:
243 + log.debug("GROUP_ADD_REQUESTED for Group {} on device {}",
244 + group.id(), group.deviceId());
235 GroupOperation groupAddOp = GroupOperation. 245 GroupOperation groupAddOp = GroupOperation.
236 createAddGroupOperation(group.id(), 246 createAddGroupOperation(group.id(),
237 group.type(), 247 group.type(),
...@@ -242,6 +252,8 @@ public class GroupManager ...@@ -242,6 +252,8 @@ public class GroupManager
242 break; 252 break;
243 253
244 case GROUP_UPDATE_REQUESTED: 254 case GROUP_UPDATE_REQUESTED:
255 + log.debug("GROUP_UPDATE_REQUESTED for Group {} on device {}",
256 + group.id(), group.deviceId());
245 GroupOperation groupModifyOp = GroupOperation. 257 GroupOperation groupModifyOp = GroupOperation.
246 createModifyGroupOperation(group.id(), 258 createModifyGroupOperation(group.id(),
247 group.type(), 259 group.type(),
...@@ -252,6 +264,8 @@ public class GroupManager ...@@ -252,6 +264,8 @@ public class GroupManager
252 break; 264 break;
253 265
254 case GROUP_REMOVE_REQUESTED: 266 case GROUP_REMOVE_REQUESTED:
267 + log.debug("GROUP_REMOVE_REQUESTED for Group {} on device {}",
268 + group.id(), group.deviceId());
255 GroupOperation groupDeleteOp = GroupOperation. 269 GroupOperation groupDeleteOp = GroupOperation.
256 createDeleteGroupOperation(group.id(), 270 createDeleteGroupOperation(group.id(),
257 group.type()); 271 group.type());
...@@ -294,10 +308,14 @@ public class GroupManager ...@@ -294,10 +308,14 @@ public class GroupManager
294 GroupProvider gp = getProvider(group.deviceId()); 308 GroupProvider gp = getProvider(group.deviceId());
295 switch (group.state()) { 309 switch (group.state()) {
296 case PENDING_DELETE: 310 case PENDING_DELETE:
311 + log.debug("Group {} delete confirmation from device {}",
312 + group, group.deviceId());
297 store.removeGroupEntry(group); 313 store.removeGroupEntry(group);
298 break; 314 break;
299 case ADDED: 315 case ADDED:
300 case PENDING_ADD: 316 case PENDING_ADD:
317 + log.debug("Group {} is in store but not on device {}",
318 + group, group.deviceId());
301 GroupOperation groupAddOp = GroupOperation. 319 GroupOperation groupAddOp = GroupOperation.
302 createAddGroupOperation(group.id(), 320 createAddGroupOperation(group.id(),
303 group.type(), 321 group.type(),
...@@ -314,7 +332,8 @@ public class GroupManager ...@@ -314,7 +332,8 @@ public class GroupManager
314 332
315 333
316 private void extraneousGroup(Group group) { 334 private void extraneousGroup(Group group) {
317 - log.debug("Group {} is on switch but not in store.", group); 335 + log.debug("Group {} is on device {} but not in store.",
336 + group, group.deviceId());
318 checkValidity(); 337 checkValidity();
319 store.addOrUpdateExtraneousGroupEntry(group); 338 store.addOrUpdateExtraneousGroupEntry(group);
320 } 339 }
...@@ -322,13 +341,16 @@ public class GroupManager ...@@ -322,13 +341,16 @@ public class GroupManager
322 private void groupAdded(Group group) { 341 private void groupAdded(Group group) {
323 checkValidity(); 342 checkValidity();
324 343
325 - log.trace("Group {}", group); 344 + log.trace("Group {} Added or Updated in device {}",
345 + group, group.deviceId());
326 store.addOrUpdateGroupEntry(group); 346 store.addOrUpdateGroupEntry(group);
327 } 347 }
328 348
329 @Override 349 @Override
330 public void pushGroupMetrics(DeviceId deviceId, 350 public void pushGroupMetrics(DeviceId deviceId,
331 Collection<Group> groupEntries) { 351 Collection<Group> groupEntries) {
352 + log.trace("Received group metrics from device {}",
353 + deviceId);
332 boolean deviceInitialAuditStatus = 354 boolean deviceInitialAuditStatus =
333 store.deviceInitialAuditStatus(deviceId); 355 store.deviceInitialAuditStatus(deviceId);
334 Set<Group> southboundGroupEntries = 356 Set<Group> southboundGroupEntries =
...@@ -338,31 +360,75 @@ public class GroupManager ...@@ -338,31 +360,75 @@ public class GroupManager
338 Set<Group> extraneousStoredEntries = 360 Set<Group> extraneousStoredEntries =
339 Sets.newHashSet(store.getExtraneousGroups(deviceId)); 361 Sets.newHashSet(store.getExtraneousGroups(deviceId));
340 362
363 + log.trace("Displaying all southboundGroupEntries for device {}", deviceId);
364 + for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
365 + Group group = it.next();
366 + log.trace("Group {} in device {}", group, deviceId);
367 + }
368 +
369 + log.trace("Displaying all stored group entries for device {}", deviceId);
370 + for (Iterator<Group> it = storedGroupEntries.iterator(); it.hasNext();) {
371 + Group group = it.next();
372 + log.trace("Stored Group {} for device {}", group, deviceId);
373 + }
374 +
341 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) { 375 for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) {
342 Group group = it.next(); 376 Group group = it.next();
343 if (storedGroupEntries.remove(group)) { 377 if (storedGroupEntries.remove(group)) {
344 // we both have the group, let's update some info then. 378 // we both have the group, let's update some info then.
379 + log.trace("Group AUDIT: group {} exists "
380 + + "in both planes for device {}",
381 + group.id(), deviceId);
345 groupAdded(group); 382 groupAdded(group);
346 it.remove(); 383 it.remove();
347 } 384 }
348 } 385 }
349 for (Group group : southboundGroupEntries) { 386 for (Group group : southboundGroupEntries) {
350 // there are groups in the switch that aren't in the store 387 // there are groups in the switch that aren't in the store
388 + log.trace("Group AUDIT: extraneous group {} exists "
389 + + "in data plane for device {}",
390 + group.id(), deviceId);
351 extraneousStoredEntries.remove(group); 391 extraneousStoredEntries.remove(group);
352 extraneousGroup(group); 392 extraneousGroup(group);
353 } 393 }
354 for (Group group : storedGroupEntries) { 394 for (Group group : storedGroupEntries) {
355 // there are groups in the store that aren't in the switch 395 // there are groups in the store that aren't in the switch
396 + log.trace("Group AUDIT: group {} missing "
397 + + "in data plane for device {}",
398 + group.id(), deviceId);
356 groupMissing(group); 399 groupMissing(group);
357 } 400 }
358 for (Group group : extraneousStoredEntries) { 401 for (Group group : extraneousStoredEntries) {
359 // there are groups in the extraneous store that 402 // there are groups in the extraneous store that
360 // aren't in the switch 403 // aren't in the switch
404 + log.trace("Group AUDIT: clearing extransoeus group {} "
405 + + "from store for device {}",
406 + group.id(), deviceId);
361 store.removeExtraneousGroupEntry(group); 407 store.removeExtraneousGroupEntry(group);
362 } 408 }
363 409
364 if (!deviceInitialAuditStatus) { 410 if (!deviceInitialAuditStatus) {
365 - store.deviceInitialAuditCompleted(deviceId); 411 + log.debug("Group AUDIT: Setting device {} initial "
412 + + "AUDIT completed", deviceId);
413 + store.deviceInitialAuditCompleted(deviceId, true);
414 + }
415 + }
416 + }
417 +
418 + private class InternalDeviceListener implements DeviceListener {
419 +
420 + @Override
421 + public void event(DeviceEvent event) {
422 + switch (event.type()) {
423 + case DEVICE_REMOVED:
424 + log.debug("Clearing device {} initial "
425 + + "AUDIT completed status as device is going down",
426 + event.subject().id());
427 + store.deviceInitialAuditCompleted(event.subject().id(), false);
428 + break;
429 +
430 + default:
431 + break;
366 } 432 }
367 } 433 }
368 } 434 }
......
...@@ -261,6 +261,11 @@ public class SimpleGroupStore ...@@ -261,6 +261,11 @@ public class SimpleGroupStore
261 } 261 }
262 262
263 private void storeGroupDescriptionInternal(GroupDescription groupDesc) { 263 private void storeGroupDescriptionInternal(GroupDescription groupDesc) {
264 + // Check if a group is existing with the same key
265 + if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
266 + return;
267 + }
268 +
264 // Get a new group identifier 269 // Get a new group identifier
265 GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); 270 GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
266 // Create a group entry object 271 // Create a group entry object
...@@ -448,29 +453,41 @@ public class SimpleGroupStore ...@@ -448,29 +453,41 @@ public class SimpleGroupStore
448 } 453 }
449 454
450 @Override 455 @Override
451 - public void deviceInitialAuditCompleted(DeviceId deviceId) { 456 + public void deviceInitialAuditCompleted(DeviceId deviceId,
457 + boolean completed) {
452 synchronized (deviceAuditStatus) { 458 synchronized (deviceAuditStatus) {
453 - deviceAuditStatus.putIfAbsent(deviceId, true); 459 + if (completed) {
454 - // Execute all pending group requests 460 + log.debug("deviceInitialAuditCompleted: AUDIT "
455 - ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests = 461 + + "completed for device {}", deviceId);
456 - getPendingGroupKeyTable(deviceId); 462 + deviceAuditStatus.put(deviceId, true);
457 - for (Group group:pendingGroupRequests.values()) { 463 + // Execute all pending group requests
458 - GroupDescription tmp = new DefaultGroupDescription( 464 + ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests =
459 - group.deviceId(), 465 + getPendingGroupKeyTable(deviceId);
460 - group.type(), 466 + for (Group group:pendingGroupRequests.values()) {
461 - group.buckets(), 467 + GroupDescription tmp = new DefaultGroupDescription(
462 - group.appCookie(), 468 + group.deviceId(),
463 - group.appId()); 469 + group.type(),
464 - storeGroupDescriptionInternal(tmp); 470 + group.buckets(),
471 + group.appCookie(),
472 + group.appId());
473 + storeGroupDescriptionInternal(tmp);
474 + }
475 + getPendingGroupKeyTable(deviceId).clear();
476 + } else {
477 + if (deviceAuditStatus.get(deviceId)) {
478 + log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
479 + + "status for device {}", deviceId);
480 + deviceAuditStatus.put(deviceId, false);
481 + }
465 } 482 }
466 - getPendingGroupKeyTable(deviceId).clear();
467 } 483 }
468 } 484 }
469 485
470 @Override 486 @Override
471 public boolean deviceInitialAuditStatus(DeviceId deviceId) { 487 public boolean deviceInitialAuditStatus(DeviceId deviceId) {
472 synchronized (deviceAuditStatus) { 488 synchronized (deviceAuditStatus) {
473 - return (deviceAuditStatus.get(deviceId) != null) ? true : false; 489 + return (deviceAuditStatus.get(deviceId) != null)
490 + ? deviceAuditStatus.get(deviceId) : false;
474 } 491 }
475 } 492 }
476 493
......