blob: 116e1cffd04f4b78507764e4c4d58ea054f05c7c [file] [log] [blame]
Hyunsun Moon90163ba2016-10-12 13:35:14 -07001/*
2 * Copyright 2017-present 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 */
16package org.onosproject.ofagent.impl;
17
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090018import com.google.common.collect.ImmutableSet;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070019import io.netty.channel.Channel;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070020import org.onosproject.net.Port;
21import org.onosproject.net.flow.FlowRule;
22import org.onosproject.net.packet.InboundPacket;
23import org.onosproject.ofagent.api.OFSwitch;
24import org.onosproject.ofagent.api.OFSwitchCapabilities;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040025import org.projectfloodlight.openflow.protocol.OFBarrierReply;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070026import org.projectfloodlight.openflow.protocol.OFControllerRole;
Daniel Parkbe6b6732016-11-11 15:52:19 +090027import org.projectfloodlight.openflow.protocol.OFEchoReply;
28import org.projectfloodlight.openflow.protocol.OFEchoRequest;
29import org.projectfloodlight.openflow.protocol.OFFactories;
30import org.projectfloodlight.openflow.protocol.OFFactory;
31import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040032import org.projectfloodlight.openflow.protocol.OFGetConfigReply;
Daniel Parkbe6b6732016-11-11 15:52:19 +090033import org.projectfloodlight.openflow.protocol.OFHello;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070034import org.projectfloodlight.openflow.protocol.OFMessage;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040035import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
36import org.projectfloodlight.openflow.protocol.OFSetConfig;
37import org.projectfloodlight.openflow.protocol.OFStatsReply;
38import org.projectfloodlight.openflow.protocol.OFStatsRequest;
39import org.projectfloodlight.openflow.protocol.OFType;
Daniel Parkbe6b6732016-11-11 15:52:19 +090040import org.projectfloodlight.openflow.protocol.OFVersion;
41import org.projectfloodlight.openflow.types.DatapathId;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040042import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070044
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090045import java.util.Collections;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070046import java.util.Set;
47import java.util.concurrent.ConcurrentHashMap;
48
49import static com.google.common.base.Preconditions.checkArgument;
50import static com.google.common.base.Preconditions.checkNotNull;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040051import static org.projectfloodlight.openflow.protocol.OFControllerRole.ROLE_EQUAL;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070052
53/**
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090054 * Implementation of the default OpenFlow switch.
Hyunsun Moon90163ba2016-10-12 13:35:14 -070055 */
56public final class DefaultOFSwitch implements OFSwitch {
57
58 private static final String ERR_CH_DUPLICATE = "Channel already exists: ";
59 private static final String ERR_CH_NOT_FOUND = "Channel not found: ";
Daniel Parkbe6b6732016-11-11 15:52:19 +090060 private static final long NUM_BUFFERS = 1024;
61 private static final short NUM_TABLES = 3;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070062
Claudine Chiue2d5acc2017-06-08 22:49:21 -040063 private final Logger log;
64
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090065 private final DatapathId dpId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070066 private final OFSwitchCapabilities capabilities;
67
Claudine Chiue2d5acc2017-06-08 22:49:21 -040068 // miss_send_len field (in OFSetConfig and OFGetConfig messages) indicates the max
69 // bytes of a packet that the switch sends to the controller
70 private int missSendLen = 0xffff;
71
Hyunsun Moon90163ba2016-10-12 13:35:14 -070072 private final ConcurrentHashMap<Channel, OFControllerRole> controllerRoleMap
73 = new ConcurrentHashMap<>();
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090074 private static final OFFactory FACTORY = OFFactories.getFactory(OFVersion.OF_13);
Hyunsun Moon90163ba2016-10-12 13:35:14 -070075
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090076 private int handshakeTransactionIds = -1;
Daniel Parkbe6b6732016-11-11 15:52:19 +090077
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090078 private DefaultOFSwitch(DatapathId dpid, OFSwitchCapabilities capabilities) {
79 this.dpId = dpid;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070080 this.capabilities = capabilities;
Claudine Chiue2d5acc2017-06-08 22:49:21 -040081 log = LoggerFactory.getLogger(getClass().getName() + " : " + dpid);
Hyunsun Moon90163ba2016-10-12 13:35:14 -070082 }
83
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090084 public static DefaultOFSwitch of(DatapathId dpid, OFSwitchCapabilities capabilities) {
85 checkNotNull(dpid, "DPID cannot be null");
86 checkNotNull(capabilities, "OF capabilities cannot be null");
87 return new DefaultOFSwitch(dpid, capabilities);
88 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -070089
90 @Override
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090091 public DatapathId dpid() {
92 return this.dpId;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070093 }
94
95 @Override
96 public OFSwitchCapabilities capabilities() {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +090097 return this.capabilities;
Hyunsun Moon90163ba2016-10-12 13:35:14 -070098 }
99
100 @Override
101 public void addControllerChannel(Channel channel) {
102 controllerRoleMap.compute(channel, (ch, existing) -> {
103 final String error = ERR_CH_DUPLICATE + channel.remoteAddress();
104 checkArgument(existing == null, error);
105 return ROLE_EQUAL;
106 });
107 }
108
109 @Override
110 public void deleteControllerChannel(Channel channel) {
111 if (controllerRoleMap.remove(channel) == null) {
112 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
113 throw new IllegalStateException(error);
114 }
115 }
116
117 @Override
118 public void setRole(Channel channel, OFControllerRole role) {
119 controllerRoleMap.compute(channel, (ch, existing) -> {
120 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
121 checkNotNull(existing, error);
122 return role;
123 });
124 }
125
126 @Override
127 public OFControllerRole role(Channel channel) {
128 OFControllerRole role = controllerRoleMap.get(channel);
129 if (role == null) {
130 final String error = ERR_CH_NOT_FOUND + channel.remoteAddress();
131 throw new IllegalStateException(error);
132 }
133 return role;
134 }
135
136 @Override
137 public Set<Channel> controllerChannels() {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900138 return ImmutableSet.copyOf(controllerRoleMap.keySet());
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700139 }
140
141 @Override
142 public void processPortAdded(Port port) {
143 // TODO generate FEATURES_REPLY message and send it to the controller
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400144 log.debug("Functionality not yet supported for {}", port);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700145 }
146
147 @Override
148 public void processPortDown(Port port) {
149 // TODO generate PORT_STATUS message and send it to the controller
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400150 log.debug("Functionality not yet supported for {}", port);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700151 }
152
153 @Override
154 public void processPortUp(Port port) {
155 // TODO generate PORT_STATUS message and send it to the controller
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400156 log.debug("Functionality not yet supported for {}", port);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700157 }
158
159 @Override
160 public void processFlowRemoved(FlowRule flowRule) {
161 // TODO generate FLOW_REMOVED message and send it to the controller
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400162 log.debug("Functionality not yet supported for {}", flowRule);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700163 }
164
165 @Override
166 public void processPacketIn(InboundPacket packet) {
167 // TODO generate PACKET_IN message and send it to the controller
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400168 log.debug("Functionality not yet supported for {}", packet);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700169 }
170
171 @Override
172 public void processControllerCommand(Channel channel, OFMessage msg) {
173 // TODO process controller command
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400174 log.debug("Functionality not yet supported for {}", msg);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700175 }
176
177 @Override
178 public void processStatsRequest(Channel channel, OFMessage msg) {
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400179 if (msg.getType() != OFType.STATS_REQUEST) {
180 log.warn("Ignoring message of type {}.", msg.getType());
181 return;
182 }
183
184 OFStatsRequest ofStatsRequest = (OFStatsRequest) msg;
185 OFStatsReply ofStatsReply = null;
186 switch (ofStatsRequest.getStatsType()) {
187 case PORT_DESC:
188 ofStatsReply = FACTORY.buildPortDescStatsReply()
189 .setXid(msg.getXid())
190 //TODO add details
191 .build();
192 break;
193 case METER_FEATURES:
194 OFMeterFeatures ofMeterFeatures = FACTORY.buildMeterFeatures()
195 .build();
196 ofStatsReply = FACTORY.buildMeterFeaturesStatsReply()
197 .setXid(msg.getXid())
198 .setFeatures(ofMeterFeatures)
199 //TODO add details
200 .build();
201 break;
202 case DESC:
203 ofStatsReply = FACTORY.buildDescStatsReply()
204 .setXid(msg.getXid())
205 .build();
206 break;
207 default:
208 log.debug("Functionality not yet supported for type {} statsType{} msg {}",
209 msg.getType(), ofStatsRequest.getStatsType(), msg);
210 break;
211 }
212
213 if (ofStatsReply != null) {
214 log.trace("request {}; reply {}", msg, ofStatsReply);
215 channel.writeAndFlush(Collections.singletonList(ofStatsReply));
216 }
217
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700218 }
219
220 @Override
221 public void processRoleRequest(Channel channel, OFMessage msg) {
222 // TODO process role request and send reply
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400223 log.debug("Functionality not yet supported for {}", msg);
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700224 }
225
226 @Override
227 public void processFeaturesRequest(Channel channel, OFMessage msg) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900228 OFFeaturesReply ofFeaturesReply = FACTORY.buildFeaturesReply()
229 .setDatapathId(dpId)
Daniel Parkbe6b6732016-11-11 15:52:19 +0900230 .setNBuffers(NUM_BUFFERS)
231 .setNTables(NUM_TABLES)
232 .setCapabilities(capabilities.ofSwitchCapabilities())
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900233 .setXid(msg.getXid())
234 .build();
235 channel.writeAndFlush(Collections.singletonList(ofFeaturesReply));
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700236 }
237
238 @Override
239 public void processLldp(Channel channel, OFMessage msg) {
240 // TODO process lldp
241 }
Daniel Parkbe6b6732016-11-11 15:52:19 +0900242
243 @Override
244 public void sendOfHello(Channel channel) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900245 OFHello ofHello = FACTORY.buildHello()
246 .setXid(this.handshakeTransactionIds--)
247 .build();
248 channel.writeAndFlush(Collections.singletonList(ofHello));
Daniel Parkbe6b6732016-11-11 15:52:19 +0900249 }
250
251 @Override
252 public void processEchoRequest(Channel channel, OFMessage msg) {
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900253 OFEchoReply ofEchoReply = FACTORY.buildEchoReply()
Daniel Parkbe6b6732016-11-11 15:52:19 +0900254 .setXid(msg.getXid())
Hyunsun Moonf4ba44f2017-03-14 03:25:52 +0900255 .setData(((OFEchoRequest) msg).getData())
256 .build();
257 channel.writeAndFlush(Collections.singletonList(ofEchoReply));
Daniel Parkbe6b6732016-11-11 15:52:19 +0900258 }
Claudine Chiue2d5acc2017-06-08 22:49:21 -0400259
260 @Override
261 public void processGetConfigRequest(Channel channel, OFMessage msg) {
262 OFGetConfigReply ofGetConfigReply = FACTORY.buildGetConfigReply()
263 .setXid(msg.getXid())
264 .setMissSendLen(missSendLen)
265 .build();
266 log.trace("request {}; reply {}", msg, ofGetConfigReply);
267 channel.writeAndFlush(Collections.singletonList(ofGetConfigReply));
268 }
269
270 @Override
271 public void processSetConfigMessage(Channel channel, OFMessage msg) {
272 OFSetConfig ofSetConfig = (OFSetConfig) msg;
273 if (missSendLen != ofSetConfig.getMissSendLen()) {
274 log.trace("Changing missSendLen from {} to {}.",
275 missSendLen, ofSetConfig.getMissSendLen());
276 missSendLen = ofSetConfig.getMissSendLen();
277 }
278
279 // SetConfig message is not acknowledged
280 }
281
282 @Override
283 public void processBarrierRequest(Channel channel, OFMessage msg) {
284 // TODO check previous state requests have been handled before issuing BarrierReply
285 OFBarrierReply ofBarrierReply = FACTORY.buildBarrierReply()
286 .setXid(msg.getXid())
287 .build();
288 log.trace("request {}; reply {}", msg, ofBarrierReply);
289 channel.writeAndFlush(Collections.singletonList(ofBarrierReply));
290 }
Hyunsun Moon90163ba2016-10-12 13:35:14 -0700291}