blob: 127531a334aff7a15b40afcea42b3a75c518e517 [file] [log] [blame]
Hyunsun Moon90163ba2016-10-12 13:35:14 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon90163ba2016-10-12 13:35:14 -07003 *
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 */
16package org.onosproject.ofagent.impl;
17
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090018import com.google.common.collect.ImmutableSet;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040019import com.google.common.collect.Lists;
Claudine Chiue92efea2017-10-31 13:58:44 -040020import com.google.common.collect.Sets;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070021import io.netty.channel.Channel;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040022import org.onlab.osgi.ServiceDirectory;
Claudine Chiub211b872017-09-05 17:27:00 -040023import org.onosproject.core.ApplicationId;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040024import org.onosproject.incubator.net.virtual.NetworkId;
Claudine Chiue92efea2017-10-31 13:58:44 -040025import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
Claudine Chiu20cbd452017-08-30 19:23:11 -040026import org.onosproject.incubator.net.virtual.VirtualNetworkService;
Claudine Chiu5c184e12017-08-08 21:21:38 -040027import org.onosproject.net.ConnectPoint;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040028import org.onosproject.net.DeviceId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070029import org.onosproject.net.Port;
Claudine Chiu5c184e12017-08-08 21:21:38 -040030import org.onosproject.net.PortNumber;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040031import org.onosproject.net.device.PortStatistics;
Claudine Chiu20cbd452017-08-30 19:23:11 -040032import org.onosproject.net.driver.DriverService;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040033import org.onosproject.net.flow.FlowEntry;
34import org.onosproject.net.flow.FlowRule;
Claudine Chiu20cbd452017-08-30 19:23:11 -040035import org.onosproject.net.flow.FlowRuleService;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040036import org.onosproject.net.flow.TableStatisticsEntry;
Claudine Chiub211b872017-09-05 17:27:00 -040037import org.onosproject.net.group.DefaultGroupDescription;
38import org.onosproject.net.group.DefaultGroupKey;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040039import org.onosproject.net.group.Group;
Claudine Chiub211b872017-09-05 17:27:00 -040040import org.onosproject.net.group.GroupBuckets;
41import org.onosproject.net.group.GroupDescription;
42import org.onosproject.net.group.GroupKey;
43import org.onosproject.net.group.GroupService;
44import org.onosproject.net.meter.Band;
45import org.onosproject.net.meter.DefaultBand;
46import org.onosproject.net.meter.DefaultMeterRequest;
47import org.onosproject.net.meter.Meter;
48import org.onosproject.net.meter.MeterId;
49import org.onosproject.net.meter.MeterRequest;
50import org.onosproject.net.meter.MeterService;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040051import org.onosproject.net.packet.InboundPacket;
Jovana Vuletac884b692017-11-28 16:52:35 +010052import org.onosproject.ofagent.api.OFAgent;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070053import org.onosproject.ofagent.api.OFSwitch;
54import org.onosproject.ofagent.api.OFSwitchCapabilities;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040055import org.onosproject.ofagent.api.OFSwitchService;
Claudine Chiub211b872017-09-05 17:27:00 -040056import org.onosproject.openflow.controller.Dpid;
Claudine Chiu5c184e12017-08-08 21:21:38 -040057import org.projectfloodlight.openflow.protocol.OFActionType;
Claudine Chiu20cbd452017-08-30 19:23:11 -040058import org.projectfloodlight.openflow.protocol.OFBadRequestCode;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040059import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040060import org.projectfloodlight.openflow.protocol.OFBucket;
61import org.projectfloodlight.openflow.protocol.OFBucketCounter;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070062import org.projectfloodlight.openflow.protocol.OFControllerRole;
Daniel Parkbe6b6732016-11-11 15:52:19 +090063import org.projectfloodlight.openflow.protocol.OFEchoReply;
64import org.projectfloodlight.openflow.protocol.OFEchoRequest;
65import org.projectfloodlight.openflow.protocol.OFFactories;
66import org.projectfloodlight.openflow.protocol.OFFactory;
67import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
Claudine Chiu20cbd452017-08-30 19:23:11 -040068import org.projectfloodlight.openflow.protocol.OFFlowMod;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040069import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040070import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
Claudine Chiub211b872017-09-05 17:27:00 -040071import org.projectfloodlight.openflow.protocol.OFGroupAdd;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040072import org.projectfloodlight.openflow.protocol.OFGroupDescStatsEntry;
Claudine Chiub211b872017-09-05 17:27:00 -040073import org.projectfloodlight.openflow.protocol.OFGroupMod;
74import org.projectfloodlight.openflow.protocol.OFGroupModify;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040075import org.projectfloodlight.openflow.protocol.OFGroupStatsEntry;
76import org.projectfloodlight.openflow.protocol.OFGroupType;
Daniel Parkbe6b6732016-11-11 15:52:19 +090077import org.projectfloodlight.openflow.protocol.OFHello;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070078import org.projectfloodlight.openflow.protocol.OFMessage;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040079import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
Claudine Chiub211b872017-09-05 17:27:00 -040080import org.projectfloodlight.openflow.protocol.OFMeterMod;
81import org.projectfloodlight.openflow.protocol.OFMeterModFailedCode;
Claudine Chiu5c184e12017-08-08 21:21:38 -040082import org.projectfloodlight.openflow.protocol.OFPacketIn;
83import org.projectfloodlight.openflow.protocol.OFPacketInReason;
84import org.projectfloodlight.openflow.protocol.OFPacketOut;
Claudine Chiue92efea2017-10-31 13:58:44 -040085import org.projectfloodlight.openflow.protocol.OFPortConfig;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040086import org.projectfloodlight.openflow.protocol.OFPortDesc;
Claudine Chiu20cbd452017-08-30 19:23:11 -040087import org.projectfloodlight.openflow.protocol.OFPortMod;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040088import org.projectfloodlight.openflow.protocol.OFPortReason;
Claudine Chiue92efea2017-10-31 13:58:44 -040089import org.projectfloodlight.openflow.protocol.OFPortState;
Claudine Chiu2729ffd2017-07-31 21:38:27 -040090import org.projectfloodlight.openflow.protocol.OFPortStatsEntry;
91import org.projectfloodlight.openflow.protocol.OFPortStatsRequest;
Claudine Chiu785ef2d2017-07-04 13:13:28 -040092import org.projectfloodlight.openflow.protocol.OFPortStatus;
Claudine Chiu7c6d51c2017-06-15 23:13:51 -040093import org.projectfloodlight.openflow.protocol.OFRoleReply;
94import org.projectfloodlight.openflow.protocol.OFRoleRequest;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040095import org.projectfloodlight.openflow.protocol.OFSetConfig;
96import org.projectfloodlight.openflow.protocol.OFStatsReply;
97import org.projectfloodlight.openflow.protocol.OFStatsRequest;
Claudine Chiuce8ccc62017-08-16 10:06:20 -040098import org.projectfloodlight.openflow.protocol.OFTableStatsEntry;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040099import org.projectfloodlight.openflow.protocol.OFType;
Daniel Parkbe6b6732016-11-11 15:52:19 +0900100import org.projectfloodlight.openflow.protocol.OFVersion;
Claudine Chiu5c184e12017-08-08 21:21:38 -0400101import org.projectfloodlight.openflow.protocol.action.OFAction;
102import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400103import org.projectfloodlight.openflow.protocol.errormsg.OFBadRequestErrorMsg;
Claudine Chiub211b872017-09-05 17:27:00 -0400104import org.projectfloodlight.openflow.protocol.errormsg.OFMeterModFailedErrorMsg;
Claudine Chiuce8ccc62017-08-16 10:06:20 -0400105import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
Claudine Chiu5c184e12017-08-08 21:21:38 -0400106import org.projectfloodlight.openflow.protocol.match.Match;
107import org.projectfloodlight.openflow.protocol.match.MatchField;
Claudine Chiub211b872017-09-05 17:27:00 -0400108import org.projectfloodlight.openflow.protocol.meterband.OFMeterBand;
109import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDrop;
110import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandDscpRemark;
111import org.projectfloodlight.openflow.protocol.meterband.OFMeterBandExperimenter;
Daniel Parkbe6b6732016-11-11 15:52:19 +0900112import org.projectfloodlight.openflow.types.DatapathId;
Claudine Chiuce8ccc62017-08-16 10:06:20 -0400113import org.projectfloodlight.openflow.types.OFGroup;
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400114import org.projectfloodlight.openflow.types.OFPort;
Claudine Chiuce8ccc62017-08-16 10:06:20 -0400115import org.projectfloodlight.openflow.types.TableId;
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400116import org.projectfloodlight.openflow.types.U64;
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400117import org.slf4j.Logger;
118import org.slf4j.LoggerFactory;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700119
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400120import java.util.ArrayList;
Claudine Chiub211b872017-09-05 17:27:00 -0400121import java.util.Collection;
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900122import java.util.Collections;
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400123import java.util.List;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700124import java.util.Set;
125import java.util.concurrent.ConcurrentHashMap;
Claudine Chiub211b872017-09-05 17:27:00 -0400126import java.util.stream.Collectors;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700127
128import static com.google.common.base.Preconditions.checkArgument;
129import static com.google.common.base.Preconditions.checkNotNull;
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400130import static org.projectfloodlight.openflow.protocol.OFControllerRole.ROLE_EQUAL;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700131
132/**
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900133 * Implementation of the default OpenFlow switch.
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700134 */
135public final class DefaultOFSwitch implements OFSwitch {
136
137 private static final String ERR_CH_DUPLICATE = "Channel already exists: ";
138 private static final String ERR_CH_NOT_FOUND = "Channel not found: ";
Daniel Parkbe6b6732016-11-11 15:52:19 +0900139 private static final long NUM_BUFFERS = 1024;
140 private static final short NUM_TABLES = 3;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700141
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400142 private final Logger log;
143
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400144 private final OFSwitchService ofSwitchService;
Claudine Chiue92efea2017-10-31 13:58:44 -0400145 private final VirtualNetworkAdminService virtualNetworkAdminService;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400146 private final FlowRuleService flowRuleService;
147 private final DriverService driverService;
Claudine Chiub211b872017-09-05 17:27:00 -0400148 private final GroupService groupService;
149 private final MeterService meterService;
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400150
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900151 private final DatapathId dpId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700152 private final OFSwitchCapabilities capabilities;
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400153 private final NetworkId networkId;
154 private final DeviceId deviceId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700155
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400156 // miss_send_len field (in OFSetConfig and OFGetConfig messages) indicates the max
157 // bytes of a packet that the switch sends to the controller
158 private int missSendLen = 0xffff;
159
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700160 private final ConcurrentHashMap<Channel, OFControllerRole> controllerRoleMap
161 = new ConcurrentHashMap<>();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900162 private static final OFFactory FACTORY = OFFactories.getFactory(OFVersion.OF_13);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700163
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900164 private int handshakeTransactionIds = -1;
Daniel Parkbe6b6732016-11-11 15:52:19 +0900165
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400166 private DefaultOFSwitch(DatapathId dpid, OFSwitchCapabilities capabilities,
167 NetworkId networkId, DeviceId deviceId,
Claudine Chiu20cbd452017-08-30 19:23:11 -0400168 ServiceDirectory serviceDirectory) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900169 this.dpId = dpid;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700170 this.capabilities = capabilities;
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400171 this.networkId = networkId;
172 this.deviceId = deviceId;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400173 this.ofSwitchService = serviceDirectory.get(OFSwitchService.class);
174 this.driverService = serviceDirectory.get(DriverService.class);
Claudine Chiue92efea2017-10-31 13:58:44 -0400175 this.virtualNetworkAdminService = serviceDirectory.get(VirtualNetworkAdminService.class);
Claudine Chiu20cbd452017-08-30 19:23:11 -0400176 VirtualNetworkService virtualNetworkService = serviceDirectory.get(VirtualNetworkService.class);
177 this.flowRuleService = virtualNetworkService.get(networkId, FlowRuleService.class);
Claudine Chiub211b872017-09-05 17:27:00 -0400178 this.groupService = virtualNetworkService.get(networkId, GroupService.class);
179 this.meterService = virtualNetworkService.get(networkId, MeterService.class);
Jovana Vuletac884b692017-11-28 16:52:35 +0100180
181 log = LoggerFactory.getLogger(OFAgent.TRACER_LOG_TENANT_ID_PREFIX + virtualNetworkService.getTenantId(networkId)
182 + " " + getClass().getSimpleName() + " : " + dpid);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700183 }
184
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400185 public static DefaultOFSwitch of(DatapathId dpid, OFSwitchCapabilities capabilities,
186 NetworkId networkId, DeviceId deviceId,
187 ServiceDirectory serviceDirectory) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900188 checkNotNull(dpid, "DPID cannot be null");
189 checkNotNull(capabilities, "OF capabilities cannot be null");
Claudine Chiu20cbd452017-08-30 19:23:11 -0400190 return new DefaultOFSwitch(dpid, capabilities, networkId, deviceId, serviceDirectory);
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900191 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700192
193 @Override
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900194 public DatapathId dpid() {
195 return this.dpId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700196 }
197
198 @Override
199 public OFSwitchCapabilities capabilities() {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900200 return this.capabilities;
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700201 }
202
203 @Override
204 public void addControllerChannel(Channel channel) {
205 controllerRoleMap.compute(channel, (ch, existing) -> {
206 final String error = ERR_CH_DUPLICATE + channel.remoteAddress();
207 checkArgument(existing == null, error);
208 return ROLE_EQUAL;
209 });
210 }
211
212 @Override
213 public void deleteControllerChannel(Channel channel) {
214 if (controllerRoleMap.remove(channel) == null) {
215 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
216 throw new IllegalStateException(error);
217 }
218 }
219
220 @Override
221 public void setRole(Channel channel, OFControllerRole role) {
222 controllerRoleMap.compute(channel, (ch, existing) -> {
223 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
224 checkNotNull(existing, error);
225 return role;
226 });
227 }
228
229 @Override
230 public OFControllerRole role(Channel channel) {
231 OFControllerRole role = controllerRoleMap.get(channel);
232 if (role == null) {
233 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
234 throw new IllegalStateException(error);
235 }
236 return role;
237 }
238
239 @Override
240 public Set<Channel> controllerChannels() {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900241 return ImmutableSet.copyOf(controllerRoleMap.keySet());
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700242 }
243
244 @Override
245 public void processPortAdded(Port port) {
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400246 sendPortStatus(port, OFPortReason.ADD);
247 }
248
249 @Override
250 public void processPortRemoved(Port port) {
251 sendPortStatus(port, OFPortReason.DELETE);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700252 }
253
254 @Override
255 public void processPortDown(Port port) {
Claudine Chiue92efea2017-10-31 13:58:44 -0400256 sendPortStatus(port, OFPortReason.MODIFY);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700257 }
258
259 @Override
260 public void processPortUp(Port port) {
Claudine Chiue92efea2017-10-31 13:58:44 -0400261 sendPortStatus(port, OFPortReason.MODIFY);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700262 }
263
264 @Override
265 public void processFlowRemoved(FlowRule flowRule) {
266 // TODO generate FLOW_REMOVED message and send it to the controller
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400267 log.debug("processFlowRemoved: Functionality not yet supported for {}", flowRule);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700268 }
269
270 @Override
271 public void processPacketIn(InboundPacket packet) {
272 // TODO generate PACKET_IN message and send it to the controller
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400273 log.debug("processPacketIn: Functionality not yet supported for {}", packet);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700274 }
275
Claudine Chiu20cbd452017-08-30 19:23:11 -0400276 private void processPortMod(OFPortMod portMod) {
Claudine Chiue92efea2017-10-31 13:58:44 -0400277 // process specified port
278 PortNumber portNumber = PortNumber.portNumber(portMod.getPortNo().getPortNumber());
279 boolean disablePort = portMod.getConfig().contains(OFPortConfig.PORT_DOWN);
280 log.debug("processing PORT_MOD message - setting port {} state to {}",
281 portNumber, !disablePort);
282 virtualNetworkAdminService.updatePortState(networkId, deviceId, portNumber, !disablePort);
283 // TODO what side effects (e.g. cleaning flow mods) needs to be handled?
Claudine Chiu20cbd452017-08-30 19:23:11 -0400284 }
285
286 private void processFlowMod(OFFlowMod flowMod) {
287 // convert OFFlowMod to FLowRule object
288 OFAgentVirtualFlowEntryBuilder flowEntryBuilder =
289 new OFAgentVirtualFlowEntryBuilder(deviceId, flowMod, driverService);
290 FlowEntry flowEntry = flowEntryBuilder.build();
291 flowRuleService.applyFlowRules(flowEntry);
292 }
293
Claudine Chiub211b872017-09-05 17:27:00 -0400294 // Methods that support GROUP_MOD
295
296 private GroupDescription.Type getGroupType(OFGroupType type) {
297 switch (type) {
298 case ALL:
299 return GroupDescription.Type.ALL;
300 case INDIRECT:
301 return GroupDescription.Type.INDIRECT;
302 case SELECT:
303 return GroupDescription.Type.SELECT;
304 case FF:
305 return GroupDescription.Type.FAILOVER;
306 default:
307 log.error("Unsupported OF group type : {}", type);
308 break;
309 }
310 return null;
311 }
312
313 private void processGroupMod(OFGroupMod groupMod) {
314 log.debug("processing GROUP_MOD {} message", groupMod.getCommand());
315
316 ApplicationId appId = ofSwitchService.appId();
317 GroupKey appCookie = new DefaultGroupKey(networkId.toString().getBytes());
318 switch (groupMod.getCommand()) {
319 case ADD:
320 // TODO return OFGroupModFailedCode.GROUP_EXISTS if group already exists
321 int groupId = groupMod.getGroup().getGroupNumber();
322 OFGroupAdd groupAdd = (OFGroupAdd) groupMod;
323 GroupBuckets groupAddBuckets = new OFAgentVirtualGroupBucketEntryBuilder(
324 Dpid.dpid(Dpid.uri(dpid().getLong())),
325 groupAdd.getBuckets(), groupAdd.getGroupType(), driverService)
326 .build();
327 GroupDescription groupDescription = new DefaultGroupDescription(
328 deviceId, getGroupType(groupAdd.getGroupType()), groupAddBuckets,
329 appCookie, groupId, appId);
330 groupService.addGroup(groupDescription);
331 break;
332 case MODIFY:
333 // TODO return OFGroupModFailedCode.INVALID_GROUP if group does not exist
334 OFGroupModify groupModify = (OFGroupModify) groupMod;
335 GroupBuckets groupModifyBuckets = new OFAgentVirtualGroupBucketEntryBuilder(
336 Dpid.dpid(Dpid.uri(dpid().getLong())),
337 groupModify.getBuckets(), groupModify.getGroupType(), driverService)
338 .build();
339 groupService.setBucketsForGroup(deviceId, appCookie, groupModifyBuckets,
340 appCookie, appId);
341 break;
342 case DELETE:
343 groupService.removeGroup(deviceId, appCookie, appId);
344 break;
345 default:
346 // INSERT_BUCKET, REMOVE_BUCKET are effective OF 1.5. OFAgent supports 1.3.
347 log.warn("Unsupported GROUP_MOD {} message received for switch {}",
348 groupMod.getCommand(), this);
349 }
350 }
351
352 // Methods that spport METER_MOD.
353
354 private Band band(OFMeterBand ofMeterBand) {
355 DefaultBand.Builder builder = DefaultBand.builder();
356 if (ofMeterBand instanceof OFMeterBandDrop) {
357 OFMeterBandDrop ofMeterBandDrop = (OFMeterBandDrop) ofMeterBand;
358 builder.ofType(Band.Type.DROP)
359 .burstSize(ofMeterBandDrop.getBurstSize())
360 .withRate(ofMeterBandDrop.getRate());
361 } else if (ofMeterBand instanceof OFMeterBandDscpRemark) {
362 OFMeterBandDscpRemark ofMeterBandDscpRemark = (OFMeterBandDscpRemark) ofMeterBand;
363 builder.ofType(Band.Type.REMARK)
364 .burstSize(ofMeterBandDscpRemark.getBurstSize())
365 .withRate(ofMeterBandDscpRemark.getRate())
366 .dropPrecedence(ofMeterBandDscpRemark.getPrecLevel());
367 } else if (ofMeterBand instanceof OFMeterBandExperimenter) {
368 OFMeterBandExperimenter ofMeterBandExperimenter = (OFMeterBandExperimenter) ofMeterBand;
369 builder.ofType(Band.Type.EXPERIMENTAL)
370 .burstSize(ofMeterBandExperimenter.getBurstSize())
371 .withRate(ofMeterBandExperimenter.getRate());
372 }
373 return builder.build();
374 }
375
376 private MeterRequest.Builder meterRequestBuilder(OFMeterMod meterMod) {
377 Collection<Band> bands = meterMod.getBands().stream()
378 .map(ofMeterBand -> band(ofMeterBand)).collect(Collectors.toList());
379 return DefaultMeterRequest.builder().forDevice(deviceId)
380 .withBands(bands).fromApp(ofSwitchService.appId());
381 }
382
383 private void meterModError(OFMeterMod meterMod, OFMeterModFailedCode code,
384 Channel channel) {
385 OFMeterModFailedErrorMsg errorMsg = FACTORY.errorMsgs()
386 .buildMeterModFailedErrorMsg()
387 .setXid(meterMod.getXid())
388 .setCode(code)
389 .build();
390 channel.writeAndFlush(Collections.singletonList(errorMsg));
391 log.debug("Sent meterMod error {}", code);
392 }
393
394 private void processMeterMod(OFMeterMod meterMod, Channel channel) {
395 log.debug("processing METER_MOD {} message", meterMod.getCommand());
396
397 long meterModId = meterMod.getMeterId();
398 Meter existingMeter = meterService.getMeter(deviceId, MeterId.meterId(meterModId));
399 MeterRequest meterRequest = null;
400 switch (meterMod.getCommand()) {
401 case ADD:
402 if (existingMeter != null) {
403 meterModError(meterMod, OFMeterModFailedCode.METER_EXISTS, channel);
404 return;
405 }
406 meterRequest = meterRequestBuilder(meterMod).add();
407 break;
408 case MODIFY:
409 if (existingMeter == null) {
410 meterModError(meterMod, OFMeterModFailedCode.UNKNOWN_METER, channel);
411 return;
412 }
413 meterRequest = meterRequestBuilder(meterMod).add();
414 break;
415 case DELETE:
416 // non-existing meter id will not result in OFMeterModFailedErrorMsg
417 // being sent to the controller
418 meterRequest = meterRequestBuilder(meterMod).remove();
419 break;
420 default:
421 log.warn("Unexpected message {} received for switch {}",
422 meterMod.getCommand(), this);
423 return;
424 }
425 meterService.submit(meterRequest);
426 }
427
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700428 @Override
429 public void processControllerCommand(Channel channel, OFMessage msg) {
Claudine Chiu20cbd452017-08-30 19:23:11 -0400430
431 OFControllerRole myRole = role(channel);
432 if (OFControllerRole.ROLE_SLAVE.equals(myRole)) {
433 OFBadRequestErrorMsg errorMsg = FACTORY.errorMsgs()
434 .buildBadRequestErrorMsg()
435 .setXid(msg.getXid())
436 .setCode(OFBadRequestCode.IS_SLAVE)
437 .build();
438 channel.writeAndFlush(Collections.singletonList(errorMsg));
439 return;
440 }
441
442 switch (msg.getType()) {
443 case PORT_MOD:
444 OFPortMod portMod = (OFPortMod) msg;
445 processPortMod(portMod);
446 break;
447 case FLOW_MOD:
448 OFFlowMod flowMod = (OFFlowMod) msg;
449 processFlowMod(flowMod);
450 break;
451 case GROUP_MOD:
Claudine Chiub211b872017-09-05 17:27:00 -0400452 OFGroupMod groupMod = (OFGroupMod) msg;
453 processGroupMod(groupMod);
454 break;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400455 case METER_MOD:
Claudine Chiub211b872017-09-05 17:27:00 -0400456 OFMeterMod meterMod = (OFMeterMod) msg;
457 processMeterMod(meterMod, channel);
458 break;
Claudine Chiu20cbd452017-08-30 19:23:11 -0400459 case TABLE_MOD:
460 log.debug("processControllerCommand: {} not yet supported for {}",
461 msg.getType(), msg);
462 break;
463 default:
464 log.warn("Unexpected message {} received for switch {}",
465 msg.getType(), this);
466 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700467 }
468
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400469 private void sendPortStatus(Port port, OFPortReason ofPortReason) {
470 Set<Channel> channels = controllerChannels();
471 if (channels.isEmpty()) {
472 log.trace("No channels present. Port status will not be sent.");
473 return;
474 }
475 OFPortDesc ofPortDesc = portDesc(port);
476 OFPortStatus ofPortStatus = FACTORY.buildPortStatus()
477 .setDesc(ofPortDesc)
478 .setReason(ofPortReason)
479 .build();
480 log.trace("Sending port status {}", ofPortStatus);
481 channels.forEach(channel -> {
482 channel.writeAndFlush(Collections.singletonList(ofPortStatus));
483 });
484 }
485
486 private OFPortDesc portDesc(Port port) {
487 OFPort ofPort = OFPort.of((int) port.number().toLong());
Claudine Chiue92efea2017-10-31 13:58:44 -0400488 Set<OFPortConfig> portConfigs = Sets.newHashSet();
489 Set<OFPortState> portStates = Sets.newHashSet();
490 if (!port.isEnabled()) {
491 portConfigs.add(OFPortConfig.PORT_DOWN);
492 portStates.add(OFPortState.LINK_DOWN);
493 }
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400494 OFPortDesc ofPortDesc = FACTORY.buildPortDesc()
495 .setPortNo(ofPort)
Claudine Chiue92efea2017-10-31 13:58:44 -0400496 .setState(portStates)
497 .setConfig(portConfigs)
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400498 .build();
499 return ofPortDesc;
500 }
501
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400502 private OFPortStatsEntry portStatsEntry(PortStatistics portStatistic) {
503 OFPortStatsEntry ofPortStatsEntry = FACTORY.buildPortStatsEntry()
Ray Milkey5ec42082019-02-13 09:56:07 -0800504 .setPortNo(OFPort.of((int) portStatistic.portNumber().toLong()))
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400505 .setTxBytes(U64.of(portStatistic.bytesSent()))
506 .setTxPackets(U64.of(portStatistic.packetsSent()))
507 .setTxDropped(U64.of(portStatistic.packetsTxDropped()))
508 .setTxErrors(U64.of(portStatistic.packetsTxErrors()))
509 .setRxBytes(U64.of(portStatistic.bytesReceived()))
510 .setRxPackets(U64.of(portStatistic.packetsReceived()))
511 .setRxDropped(U64.of(portStatistic.packetsRxDropped()))
512 .setRxErrors(U64.of(portStatistic.packetsRxErrors()))
513 .setDurationSec(portStatistic.durationSec())
514 .setDurationNsec(portStatistic.durationNano())
515 .build();
516 return ofPortStatsEntry;
517 }
518
Claudine Chiuce8ccc62017-08-16 10:06:20 -0400519 private OFFlowStatsEntry ofFlowStatsEntry(FlowEntry flowEntry) {
520 // TODO get match from flowEntry.selector()
521 Match.Builder matchB = FACTORY.buildMatch();
522 OFActionOutput actionOutput = FACTORY.actions()
523 .buildOutput().build();
524 // TODO get instructions from flowEntry.treatment()
525 OFInstruction instruction = FACTORY.instructions()
526 .applyActions(Collections.singletonList(actionOutput));
527 OFFlowStatsEntry ofFlowStatsEntry = FACTORY.buildFlowStatsEntry()
528 .setMatch(matchB.build())
529 .setInstructions(Collections.singletonList(instruction))
530 .setTableId(TableId.of(flowEntry.tableId()))
531 .setHardTimeout(flowEntry.hardTimeout())
532 .setIdleTimeout(flowEntry.timeout())
533 .setCookie(U64.of(flowEntry.id().value()))
534 .setPriority(flowEntry.priority())
535 .setDurationSec(flowEntry.life())
536 .setPacketCount(U64.of(flowEntry.packets()))
537 .setByteCount(U64.of(flowEntry.bytes()))
538 .build();
539 return ofFlowStatsEntry;
540 }
541
542 private OFTableStatsEntry ofFlowTableStatsEntry(TableStatisticsEntry tableStatisticsEntry) {
543 OFTableStatsEntry ofTableStatsEntry = FACTORY.buildTableStatsEntry()
544 .setTableId(TableId.of(tableStatisticsEntry.tableId()))
545 .setActiveCount(tableStatisticsEntry.activeFlowEntries())
546 .setLookupCount(U64.of(tableStatisticsEntry.packetsLookedup()))
547 .setMatchedCount(U64.of(tableStatisticsEntry.packetsLookedup()))
548 .build();
549 return ofTableStatsEntry;
550 }
551
552 private OFGroupStatsEntry ofGroupStatsEntry(Group group) {
553 List<OFBucketCounter> ofBucketCounters = Lists.newArrayList();
554 group.buckets().buckets().forEach(groupBucket -> {
555 ofBucketCounters.add(FACTORY.bucketCounter(
556 U64.of(groupBucket.packets()), U64.of(groupBucket.bytes())));
557 });
558 OFGroupStatsEntry entry = FACTORY.buildGroupStatsEntry()
559 .setGroup(OFGroup.of(group.id().id()))
560 .setDurationSec(group.life())
561 .setPacketCount(U64.of(group.packets()))
562 .setByteCount(U64.of(group.bytes()))
563 .setRefCount(group.referenceCount())
564 .setBucketStats(ofBucketCounters)
565 .build();
566 return entry;
567 }
568
569 private OFGroupDescStatsEntry ofGroupDescStatsEntry(Group group) {
570 List<OFBucket> ofBuckets = Lists.newArrayList();
571 group.buckets().buckets().forEach(groupBucket -> {
572 ofBuckets.add(FACTORY.buildBucket()
573 .setWeight(groupBucket.weight())
574 .setWatchGroup(OFGroup.of(groupBucket.watchGroup().id()))
575 .setWatchPort(OFPort.of((int) groupBucket.watchPort().toLong()))
576 .build()
577 );
578 });
579 OFGroup ofGroup = OFGroup.of(group.givenGroupId());
580 OFGroupType ofGroupType = OFGroupType.valueOf(group.type().name());
581 OFGroupDescStatsEntry entry = FACTORY.buildGroupDescStatsEntry()
582 .setGroup(ofGroup)
583 .setGroupType(ofGroupType)
584 .setBuckets(ofBuckets)
585 .build();
586 return entry;
587 }
588
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700589 @Override
590 public void processStatsRequest(Channel channel, OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400591 if (msg.getType() != OFType.STATS_REQUEST) {
592 log.warn("Ignoring message of type {}.", msg.getType());
593 return;
594 }
595
596 OFStatsRequest ofStatsRequest = (OFStatsRequest) msg;
597 OFStatsReply ofStatsReply = null;
598 switch (ofStatsRequest.getStatsType()) {
599 case PORT_DESC:
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400600 List<OFPortDesc> portDescs = new ArrayList<>();
601 Set<Port> ports = ofSwitchService.ports(networkId, deviceId);
602 ports.forEach(port -> {
603 OFPortDesc ofPortDesc = portDesc(port);
604 portDescs.add(ofPortDesc);
605 });
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400606 ofStatsReply = FACTORY.buildPortDescStatsReply()
607 .setXid(msg.getXid())
Claudine Chiu785ef2d2017-07-04 13:13:28 -0400608 .setEntries(portDescs)
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400609 //TODO add details
610 .build();
611 break;
Claudine Chiu2729ffd2017-07-31 21:38:27 -0400612 case PORT:
613 OFPortStatsRequest portStatsRequest = (OFPortStatsRequest) msg;
614 OFPort ofPort = portStatsRequest.getPortNo();
615 List<OFPortStatsEntry> portStatsEntries = new ArrayList<>();
616 List<PortStatistics> portStatistics =
617 ofSwitchService.getPortStatistics(networkId, deviceId);
618 if (ofPort.equals(OFPort.ANY)) {
619 portStatistics.forEach(portStatistic -> {
620 OFPortStatsEntry ofPortStatsEntry = portStatsEntry(portStatistic);
621 portStatsEntries.add(ofPortStatsEntry);
622 });
623 }
624 ofStatsReply = FACTORY.buildPortStatsReply()
625 .setEntries(portStatsEntries)
626 .setXid(msg.getXid())
627 .build();
628 break;
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400629 case METER_FEATURES:
630 OFMeterFeatures ofMeterFeatures = FACTORY.buildMeterFeatures()
631 .build();
632 ofStatsReply = FACTORY.buildMeterFeaturesStatsReply()
633 .setXid(msg.getXid())
634 .setFeatures(ofMeterFeatures)
635 //TODO add details
636 .build();
637 break;
Claudine Chiuce8ccc62017-08-16 10:06:20 -0400638 case FLOW:
639 List<OFFlowStatsEntry> flowStatsEntries = new ArrayList<>();
640 List<FlowEntry> flowStats = ofSwitchService.getFlowEntries(networkId, deviceId);
641 flowStats.forEach(flowEntry -> {
642 OFFlowStatsEntry ofFlowStatsEntry = ofFlowStatsEntry(flowEntry);
643 flowStatsEntries.add(ofFlowStatsEntry);
644 });
645 ofStatsReply = FACTORY.buildFlowStatsReply()
646 .setEntries(flowStatsEntries)
647 .setXid(msg.getXid())
648 .build();
649 break;
650 case TABLE:
651 List<OFTableStatsEntry> ofTableStatsEntries = new ArrayList<>();
652 List<TableStatisticsEntry> tableStats = ofSwitchService.getFlowTableStatistics(networkId, deviceId);
653 tableStats.forEach(tableStatisticsEntry -> {
654 OFTableStatsEntry ofFlowStatsEntry = ofFlowTableStatsEntry(tableStatisticsEntry);
655 ofTableStatsEntries.add(ofFlowStatsEntry);
656 });
657 ofStatsReply = FACTORY.buildTableStatsReply()
658 .setEntries(ofTableStatsEntries)
659 .setXid(msg.getXid())
660 .build();
661 break;
662 case GROUP:
663 List<Group> groupStats = ofSwitchService.getGroups(networkId, deviceId);
664 List<OFGroupStatsEntry> ofGroupStatsEntries = new ArrayList<>();
665 groupStats.forEach(group -> {
666 OFGroupStatsEntry entry = ofGroupStatsEntry(group);
667 ofGroupStatsEntries.add(entry);
668 });
669 ofStatsReply = FACTORY.buildGroupStatsReply()
670 .setEntries(ofGroupStatsEntries)
671 .setXid(msg.getXid())
672 .build();
673 break;
674 case GROUP_DESC:
675 List<OFGroupDescStatsEntry> ofGroupDescStatsEntries = new ArrayList<>();
676 List<Group> groupStats2 = ofSwitchService.getGroups(networkId, deviceId);
677 groupStats2.forEach(group -> {
678 OFGroupDescStatsEntry entry = ofGroupDescStatsEntry(group);
679 ofGroupDescStatsEntries.add(entry);
680 });
681 ofStatsReply = FACTORY.buildGroupDescStatsReply()
682 .setEntries(ofGroupDescStatsEntries)
683 .setXid(msg.getXid())
684 .build();
685 break;
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400686 case DESC:
687 ofStatsReply = FACTORY.buildDescStatsReply()
688 .setXid(msg.getXid())
689 .build();
690 break;
691 default:
692 log.debug("Functionality not yet supported for type {} statsType{} msg {}",
693 msg.getType(), ofStatsRequest.getStatsType(), msg);
694 break;
695 }
696
697 if (ofStatsReply != null) {
698 log.trace("request {}; reply {}", msg, ofStatsReply);
699 channel.writeAndFlush(Collections.singletonList(ofStatsReply));
700 }
701
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700702 }
703
704 @Override
705 public void processRoleRequest(Channel channel, OFMessage msg) {
Claudine Chiu7c6d51c2017-06-15 23:13:51 -0400706 OFRoleRequest ofRoleRequest = (OFRoleRequest) msg;
707 OFControllerRole oldRole = role(channel);
708 OFControllerRole newRole = ofRoleRequest.getRole();
709 if (oldRole.equals(newRole)) {
710 log.trace("No change needed to existing role {}", oldRole);
711 } else {
712 log.trace("Changing role from {} to {}", oldRole, newRole);
713 setRole(channel, newRole);
714 }
715 OFRoleReply ofRoleReply = FACTORY.buildRoleReply()
716 .setRole(role(channel))
717 .setXid(msg.getXid())
718 .build();
719 channel.writeAndFlush(Collections.singletonList(ofRoleReply));
720 log.trace("request {}; reply {}", msg, ofRoleReply);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700721 }
722
723 @Override
724 public void processFeaturesRequest(Channel channel, OFMessage msg) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900725 OFFeaturesReply ofFeaturesReply = FACTORY.buildFeaturesReply()
726 .setDatapathId(dpId)
Daniel Parkbe6b6732016-11-11 15:52:19 +0900727 .setNBuffers(NUM_BUFFERS)
728 .setNTables(NUM_TABLES)
729 .setCapabilities(capabilities.ofSwitchCapabilities())
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900730 .setXid(msg.getXid())
731 .build();
732 channel.writeAndFlush(Collections.singletonList(ofFeaturesReply));
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700733 }
734
735 @Override
736 public void processLldp(Channel channel, OFMessage msg) {
Claudine Chiu5c184e12017-08-08 21:21:38 -0400737 log.trace("processLldp msg{}", msg);
738
739 // For each output port, look up neighbour port.
740 // If neighbour port exists, have the neighbour switch send lldp response.
741 // Modeled after how OpenVirtex handles lldp from external controller.
742 OFPacketOut ofPacketOut = (OFPacketOut) msg;
743 List<OFAction> actions = ofPacketOut.getActions();
744 for (final OFAction action : actions) {
745 OFActionType actionType = action.getType();
746 if (actionType.equals(OFActionType.OUTPUT)) {
747 OFActionOutput ofActionOutput = (OFActionOutput) action;
748 OFPort ofPort = ofActionOutput.getPort();
749 ConnectPoint neighbourCp =
750 ofSwitchService.neighbour(networkId, deviceId,
751 PortNumber.portNumber(ofPort.getPortNumber()));
752 if (neighbourCp == null) {
753 log.trace("No neighbour found for {} {}", deviceId, ofPort);
754 continue;
755 }
756 OFSwitch neighbourSwitch = ofSwitchService.ofSwitch(networkId,
757 neighbourCp.deviceId());
758 neighbourSwitch.sendLldpResponse(ofPacketOut, neighbourCp.port());
759 }
760 }
761 }
762
763 @Override
764 public void sendLldpResponse(OFPacketOut po, PortNumber inPort) {
765 Match.Builder matchB = FACTORY.buildMatch();
766 matchB.setExact(MatchField.IN_PORT, OFPort.of((int) inPort.toLong()));
767 OFPacketIn pi = FACTORY.buildPacketIn()
768 .setBufferId(po.getBufferId())
769 .setMatch(matchB.build())
770 .setReason(OFPacketInReason.NO_MATCH)
771 .setData(po.getData())
772 .build();
773 log.trace("Sending packet in {}", pi);
774 controllerChannels().forEach(channel -> {
775 channel.writeAndFlush(Collections.singletonList(pi));
776 });
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700777 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900778
779 @Override
780 public void sendOfHello(Channel channel) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900781 OFHello ofHello = FACTORY.buildHello()
782 .setXid(this.handshakeTransactionIds--)
783 .build();
784 channel.writeAndFlush(Collections.singletonList(ofHello));
Daniel Parkbe6b6732016-11-11 15:52:19 +0900785 }
786
787 @Override
788 public void processEchoRequest(Channel channel, OFMessage msg) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900789 OFEchoReply ofEchoReply = FACTORY.buildEchoReply()
Daniel Parkbe6b6732016-11-11 15:52:19 +0900790 .setXid(msg.getXid())
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900791 .setData(((OFEchoRequest) msg).getData())
792 .build();
793 channel.writeAndFlush(Collections.singletonList(ofEchoReply));
Daniel Parkbe6b6732016-11-11 15:52:19 +0900794 }
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400795
796 @Override
797 public void processGetConfigRequest(Channel channel, OFMessage msg) {
798 OFGetConfigReply ofGetConfigReply = FACTORY.buildGetConfigReply()
799 .setXid(msg.getXid())
800 .setMissSendLen(missSendLen)
801 .build();
802 log.trace("request {}; reply {}", msg, ofGetConfigReply);
803 channel.writeAndFlush(Collections.singletonList(ofGetConfigReply));
804 }
805
806 @Override
807 public void processSetConfigMessage(Channel channel, OFMessage msg) {
808 OFSetConfig ofSetConfig = (OFSetConfig) msg;
809 if (missSendLen != ofSetConfig.getMissSendLen()) {
810 log.trace("Changing missSendLen from {} to {}.",
811 missSendLen, ofSetConfig.getMissSendLen());
812 missSendLen = ofSetConfig.getMissSendLen();
813 }
814
815 // SetConfig message is not acknowledged
816 }
817
818 @Override
819 public void processBarrierRequest(Channel channel, OFMessage msg) {
820 // TODO check previous state requests have been handled before issuing BarrierReply
821 OFBarrierReply ofBarrierReply = FACTORY.buildBarrierReply()
822 .setXid(msg.getXid())
823 .build();
824 log.trace("request {}; reply {}", msg, ofBarrierReply);
825 channel.writeAndFlush(Collections.singletonList(ofBarrierReply));
826 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700827}