blob: a477c3969ec133c364a3bd0d3dbc788674ece689 [file] [log] [blame]
sangho5afd02a2015-02-03 20:07:35 -08001/*
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
17package org.onosproject.provider.of.group.impl;
18
19import com.google.common.collect.Maps;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onosproject.core.DefaultGroupId;
26import org.onosproject.core.GroupId;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.group.DefaultGroup;
29import org.onosproject.net.group.Group;
30import org.onosproject.net.group.GroupBuckets;
31import org.onosproject.net.group.GroupDescription;
32import org.onosproject.net.group.GroupOperation;
33import org.onosproject.net.group.GroupOperations;
34import org.onosproject.net.group.GroupProvider;
35import org.onosproject.net.group.GroupProviderRegistry;
36import org.onosproject.net.group.GroupProviderService;
37import org.onosproject.net.provider.AbstractProvider;
38import org.onosproject.net.provider.ProviderId;
39import org.onosproject.openflow.controller.Dpid;
40import org.onosproject.openflow.controller.OpenFlowController;
41import org.onosproject.openflow.controller.OpenFlowEventListener;
42import org.onosproject.openflow.controller.OpenFlowSwitch;
43import org.onosproject.openflow.controller.OpenFlowSwitchListener;
44import org.onosproject.openflow.controller.RoleState;
45import org.projectfloodlight.openflow.protocol.OFErrorMsg;
46import org.projectfloodlight.openflow.protocol.OFErrorType;
47import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
48import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
49import org.projectfloodlight.openflow.protocol.OFGroupMod;
50import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
51import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
52import org.projectfloodlight.openflow.protocol.OFGroupType;
53import org.projectfloodlight.openflow.protocol.OFMessage;
54import org.projectfloodlight.openflow.protocol.OFPortStatus;
55import org.projectfloodlight.openflow.protocol.OFStatsReply;
56import org.projectfloodlight.openflow.protocol.OFStatsType;
57import org.slf4j.Logger;
58
59import java.util.Collection;
60import java.util.Map;
61import java.util.Optional;
62import java.util.concurrent.atomic.AtomicLong;
63
64import static org.slf4j.LoggerFactory.getLogger;
65
66/**
67 * Provider which uses an OpenFlow controller to handle Group.
68 */
69@Component(immediate = true)
70public class OpenFlowGroupProvider extends AbstractProvider implements GroupProvider {
71
72 private final Logger log = getLogger(getClass());
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected OpenFlowController controller;
76
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected GroupProviderRegistry providerRegistry;
79
80 private GroupProviderService providerService;
81
82 static final int POLL_INTERVAL = 10;
83
84 private final InternalGroupProvider listener = new InternalGroupProvider();
85
86 private final AtomicLong xidCounter = new AtomicLong(1);
87 private final Map<Dpid, GroupStatsCollector> collectors = Maps.newHashMap();
88 private final Map<Long, OFStatsReply> groupStats = Maps.newHashMap();
89 private final Map<Long, GroupOperation> pendingGroupOperations =
90 Maps.newConcurrentMap();
91
92 /**
93 * Creates a OpenFlow group provider.
94 */
95 public OpenFlowGroupProvider() {
96 super(new ProviderId("of", "org.onosproject.provider.group"));
97 }
98
99 @Activate
100 public void activate() {
101 providerService = providerRegistry.register(this);
102 controller.addListener(listener);
103 controller.addEventListener(listener);
104
105 for (OpenFlowSwitch sw : controller.getSwitches()) {
106 GroupStatsCollector gsc = new GroupStatsCollector(sw, POLL_INTERVAL);
107 gsc.start();
108 collectors.put(new Dpid(sw.getId()), gsc);
109 }
110
111 log.info("Started");
112 }
113
114 @Deactivate
115 public void deactivate() {
116 providerRegistry.unregister(this);
117 providerService = null;
118
119 log.info("Stopped");
120 }
121
122 @Override
123 public void performGroupOperation(DeviceId deviceId, GroupOperations groupOps) {
124 Map<OFGroupMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap();
125 final Dpid dpid = Dpid.dpid(deviceId.uri());
126 OpenFlowSwitch sw = controller.getSwitch(dpid);
127 for (GroupOperation groupOperation: groupOps.operations()) {
128 if (sw == null) {
129 log.error("SW {} is not found", sw.getStringId());
130 return;
131 }
132 final Long groupModXid = xidCounter.getAndIncrement();
133 GroupModBuilder builder =
134 GroupModBuilder.builder(groupOperation.buckets(),
135 groupOperation.groupId(),
136 groupOperation.groupType(),
137 sw.factory(),
138 Optional.of(groupModXid));
139 OFGroupMod groupMod = null;
140 switch (groupOperation.opType()) {
141 case ADD:
142 groupMod = builder.buildGroupAdd();
143 break;
144 case MODIFY:
145 groupMod = builder.buildGroupMod();
146 break;
147 case DELETE:
148 groupMod = builder.buildGroupDel();
149 break;
150 default:
151 log.error("Unsupported Group operation");
152 }
153 sw.sendMsg(groupMod);
154 pendingGroupOperations.put(groupModXid, groupOperation);
155 }
156 }
157
158 private void pushGroupMetrics(Dpid dpid, OFStatsReply statsReply) {
159 DeviceId deviceId = DeviceId.deviceId(Dpid.uri(dpid));
160
161 OFGroupStatsReply groupStatsReply = null;
162 OFGroupDescStatsReply groupDescStatsReply = null;
163
164 if (statsReply.getStatsType() == OFStatsType.GROUP) {
165 OFStatsReply reply = groupStats.get(statsReply.getXid() + 1);
166 if (reply != null) {
167 groupStatsReply = (OFGroupStatsReply) statsReply;
168 groupDescStatsReply = (OFGroupDescStatsReply) reply;
169 groupStats.remove(statsReply.getXid() + 1);
170 } else {
171 groupStats.put(statsReply.getXid(), statsReply);
172 }
173 } else if (statsReply.getStatsType() == OFStatsType.GROUP_DESC) {
174 OFStatsReply reply = groupStats.get(statsReply.getXid() - 1);
175 if (reply != null) {
176 groupStatsReply = (OFGroupStatsReply) reply;
177 groupDescStatsReply = (OFGroupDescStatsReply) statsReply;
178 groupStats.remove(statsReply.getXid() - 1);
179 } else {
180 groupStats.put(statsReply.getXid(), statsReply);
181 }
182 }
183
184 if (groupStatsReply != null && groupDescStatsReply != null) {
185 Collection<Group> groups = buildGroupMetrics(deviceId,
186 groupStatsReply, groupDescStatsReply);
187 providerService.pushGroupMetrics(deviceId, groups);
188 for (Group group: groups) {
189 pendingGroupOperations.remove(group.id());
190 }
191 }
192 }
193
194 private Collection<Group> buildGroupMetrics(DeviceId deviceId,
195 OFGroupStatsReply groupStatsReply,
196 OFGroupDescStatsReply groupDescStatsReply) {
197
198 Map<Integer, Group> groups = Maps.newHashMap();
199
200 for (OFGroupDescStatsEntry entry: groupDescStatsReply.getEntries()) {
201 int id = entry.getGroup().getGroupNumber();
202 GroupId groupId = new DefaultGroupId(id);
203 GroupDescription.Type type = getGroupType(entry.getGroupType());
204 GroupBuckets buckets = new GroupBucketEntryBuilder(entry.getBuckets(),
205 entry.getGroupType()).build();
206 DefaultGroup group = new DefaultGroup(groupId, deviceId, type, buckets);
207 groups.put(id, group);
208 }
209
210 for (OFGroupStatsEntry entry: groupStatsReply.getEntries()) {
211 int groupId = entry.getGroup().getGroupNumber();
212 DefaultGroup group = (DefaultGroup) groups.get(groupId);
213 if (group != null) {
214 group.setBytes(entry.getByteCount().getValue());
215 group.setLife(entry.getDurationSec());
216 group.setPackets(entry.getPacketCount().getValue());
217 group.setReferenceCount(entry.getRefCount());
218 }
219 }
220
221 return groups.values();
222 }
223
224 private GroupDescription.Type getGroupType(OFGroupType type) {
225 switch (type) {
226 case ALL:
227 return GroupDescription.Type.ALL;
228 case INDIRECT:
229 return GroupDescription.Type.INDIRECT;
230 case SELECT:
231 return GroupDescription.Type.SELECT;
232 case FF:
233 return GroupDescription.Type.FAILOVER;
234 default:
235 log.error("Unsupported OF group type : {}", type);
236 break;
237 }
238 return null;
239 }
240
241 private class InternalGroupProvider
242 implements OpenFlowSwitchListener, OpenFlowEventListener {
243
244 @Override
245 public void handleMessage(Dpid dpid, OFMessage msg) {
246 switch (msg.getType()) {
247 case STATS_REPLY:
248 pushGroupMetrics(dpid, (OFStatsReply) msg);
249 break;
250 case ERROR:
251 OFErrorMsg errorMsg = (OFErrorMsg) msg;
252 if (errorMsg.getErrType() == OFErrorType.GROUP_MOD_FAILED) {
253 GroupOperation operation =
254 pendingGroupOperations.get(errorMsg.getXid());
255 if (operation != null) {
256 providerService.groupOperationFailed(operation);
257 log.warn("received Error message {} from {}", msg, dpid);
258 }
259 break;
260 }
261 default:
262 log.debug("Unhandled message type: {}", msg.getType());
263 }
264 }
265
266 @Override
267 public void switchAdded(Dpid dpid) {
268 GroupStatsCollector gsc = new GroupStatsCollector(
269 controller.getSwitch(dpid), POLL_INTERVAL);
270 gsc.start();
271 collectors.put(dpid, gsc);
272 }
273
274 @Override
275 public void switchRemoved(Dpid dpid) {
276 GroupStatsCollector collector = collectors.remove(dpid);
277 if (collector != null) {
278 collector.stop();
279 }
280 }
281
282 @Override
283 public void switchChanged(Dpid dpid) {
284 }
285
286 @Override
287 public void portChanged(Dpid dpid, OFPortStatus status) {
288 }
289
290 @Override
291 public void receivedRoleReply(Dpid dpid, RoleState requested, RoleState response) {
292 }
293 }
294
295}