blob: eac3c186f75a8972333e7468897622f968e84f39 [file] [log] [blame]
alshabib1cc04f72014-09-16 16:09:58 -07001package org.onlab.onos.provider.of.flow.impl;
2
3import static org.slf4j.LoggerFactory.getLogger;
4
alshabib19fdc122014-10-03 11:38:19 -07005import java.util.List;
alshabibeec3a062014-09-17 18:01:26 -07006import java.util.Map;
7
alshabib1cc04f72014-09-16 16:09:58 -07008import org.apache.felix.scr.annotations.Activate;
9import org.apache.felix.scr.annotations.Component;
10import org.apache.felix.scr.annotations.Deactivate;
11import org.apache.felix.scr.annotations.Reference;
12import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabiba68eb962014-09-24 20:34:13 -070013import org.onlab.onos.ApplicationId;
alshabiba7f7ca82014-09-22 11:41:23 -070014import org.onlab.onos.net.DeviceId;
alshabib1c319ff2014-10-04 20:29:09 -070015import org.onlab.onos.net.flow.FlowEntry;
alshabib1cc04f72014-09-16 16:09:58 -070016import org.onlab.onos.net.flow.FlowRule;
17import org.onlab.onos.net.flow.FlowRuleProvider;
18import org.onlab.onos.net.flow.FlowRuleProviderRegistry;
19import org.onlab.onos.net.flow.FlowRuleProviderService;
20import org.onlab.onos.net.provider.AbstractProvider;
21import org.onlab.onos.net.provider.ProviderId;
22import org.onlab.onos.net.topology.TopologyService;
tom9c94c5b2014-09-17 13:14:42 -070023import org.onlab.onos.openflow.controller.Dpid;
24import org.onlab.onos.openflow.controller.OpenFlowController;
alshabibeec3a062014-09-17 18:01:26 -070025import org.onlab.onos.openflow.controller.OpenFlowEventListener;
tom9c94c5b2014-09-17 13:14:42 -070026import org.onlab.onos.openflow.controller.OpenFlowSwitch;
alshabibce4e5782014-09-17 14:56:42 -070027import org.onlab.onos.openflow.controller.OpenFlowSwitchListener;
Ayaka Koshibeab91cc42014-09-25 10:20:52 -070028import org.onlab.onos.openflow.controller.RoleState;
alshabib19fdc122014-10-03 11:38:19 -070029import org.projectfloodlight.openflow.protocol.OFActionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070030import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
alshabib5c370ff2014-09-18 10:12:14 -070031import org.projectfloodlight.openflow.protocol.OFFlowStatsEntry;
32import org.projectfloodlight.openflow.protocol.OFFlowStatsReply;
alshabib19fdc122014-10-03 11:38:19 -070033import org.projectfloodlight.openflow.protocol.OFInstructionType;
alshabib8f1cf4a2014-09-17 14:44:48 -070034import org.projectfloodlight.openflow.protocol.OFMessage;
35import org.projectfloodlight.openflow.protocol.OFPortStatus;
alshabib5c370ff2014-09-18 10:12:14 -070036import org.projectfloodlight.openflow.protocol.OFStatsReply;
alshabib54ce5892014-09-23 17:50:51 -070037import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
alshabib5c370ff2014-09-18 10:12:14 -070038import org.projectfloodlight.openflow.protocol.OFStatsType;
alshabib19fdc122014-10-03 11:38:19 -070039import org.projectfloodlight.openflow.protocol.OFVersion;
40import org.projectfloodlight.openflow.protocol.action.OFAction;
41import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
42import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
43import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
44import org.projectfloodlight.openflow.types.OFPort;
alshabib1cc04f72014-09-16 16:09:58 -070045import org.slf4j.Logger;
46
alshabib54ce5892014-09-23 17:50:51 -070047import com.google.common.collect.ArrayListMultimap;
alshabib5c370ff2014-09-18 10:12:14 -070048import com.google.common.collect.Maps;
alshabib54ce5892014-09-23 17:50:51 -070049import com.google.common.collect.Multimap;
alshabibeec3a062014-09-17 18:01:26 -070050
alshabib1cc04f72014-09-16 16:09:58 -070051/**
52 * Provider which uses an OpenFlow controller to detect network
53 * end-station hosts.
54 */
55@Component(immediate = true)
56public class OpenFlowRuleProvider extends AbstractProvider implements FlowRuleProvider {
57
58 private final Logger log = getLogger(getClass());
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected FlowRuleProviderRegistry providerRegistry;
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected OpenFlowController controller;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected TopologyService topologyService;
68
69 private FlowRuleProviderService providerService;
70
alshabibeec3a062014-09-17 18:01:26 -070071 private final InternalFlowProvider listener = new InternalFlowProvider();
72
alshabib1cc04f72014-09-16 16:09:58 -070073 /**
74 * Creates an OpenFlow host provider.
75 */
76 public OpenFlowRuleProvider() {
tom7e02cda2014-09-18 12:05:46 -070077 super(new ProviderId("of", "org.onlab.onos.provider.openflow"));
alshabib1cc04f72014-09-16 16:09:58 -070078 }
79
80 @Activate
81 public void activate() {
82 providerService = providerRegistry.register(this);
alshabibeec3a062014-09-17 18:01:26 -070083 controller.addListener(listener);
84 controller.addEventListener(listener);
alshabib1cc04f72014-09-16 16:09:58 -070085 log.info("Started");
86 }
87
88 @Deactivate
89 public void deactivate() {
90 providerRegistry.unregister(this);
91 providerService = null;
92
93 log.info("Stopped");
94 }
95 @Override
96 public void applyFlowRule(FlowRule... flowRules) {
alshabib35edb1a2014-09-16 17:44:44 -070097 for (int i = 0; i < flowRules.length; i++) {
98 applyRule(flowRules[i]);
99 }
alshabib1cc04f72014-09-16 16:09:58 -0700100 }
101
alshabib35edb1a2014-09-16 17:44:44 -0700102 private void applyRule(FlowRule flowRule) {
103 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
alshabib8f1cf4a2014-09-17 14:44:48 -0700104 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowMod());
alshabib35edb1a2014-09-16 17:44:44 -0700105 }
106
alshabib35edb1a2014-09-16 17:44:44 -0700107
alshabib35edb1a2014-09-16 17:44:44 -0700108
alshabib1cc04f72014-09-16 16:09:58 -0700109 @Override
110 public void removeFlowRule(FlowRule... flowRules) {
alshabib219ebaa2014-09-22 15:41:24 -0700111 for (int i = 0; i < flowRules.length; i++) {
112 removeRule(flowRules[i]);
113 }
alshabib1cc04f72014-09-16 16:09:58 -0700114
115 }
116
alshabib219ebaa2014-09-22 15:41:24 -0700117 private void removeRule(FlowRule flowRule) {
118 OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri()));
119 sw.sendMsg(new FlowModBuilder(flowRule, sw.factory()).buildFlowDel());
120 }
121
alshabiba68eb962014-09-24 20:34:13 -0700122 @Override
123 public void removeRulesById(ApplicationId id, FlowRule... flowRules) {
124 // TODO: optimize using the ApplicationId
125 removeFlowRule(flowRules);
126 }
127
alshabib219ebaa2014-09-22 15:41:24 -0700128
alshabib1cc04f72014-09-16 16:09:58 -0700129 //TODO: InternalFlowRuleProvider listening to stats and error and flowremoved.
130 // possibly barriers as well. May not be internal at all...
alshabib8f1cf4a2014-09-17 14:44:48 -0700131 private class InternalFlowProvider
132 implements OpenFlowSwitchListener, OpenFlowEventListener {
133
alshabibeec3a062014-09-17 18:01:26 -0700134 private final Map<Dpid, FlowStatsCollector> collectors = Maps.newHashMap();
alshabib1c319ff2014-10-04 20:29:09 -0700135 private final Multimap<DeviceId, FlowEntry> completeEntries =
alshabib54ce5892014-09-23 17:50:51 -0700136 ArrayListMultimap.create();
alshabib8f1cf4a2014-09-17 14:44:48 -0700137
138 @Override
139 public void switchAdded(Dpid dpid) {
alshabibba5ac482014-10-02 17:15:20 -0700140 FlowStatsCollector fsc = new FlowStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
alshabibeec3a062014-09-17 18:01:26 -0700141 fsc.start();
142 collectors.put(dpid, fsc);
alshabib8f1cf4a2014-09-17 14:44:48 -0700143 }
144
145 @Override
146 public void switchRemoved(Dpid dpid) {
alshabibeec3a062014-09-17 18:01:26 -0700147 collectors.remove(dpid).stop();
alshabib8f1cf4a2014-09-17 14:44:48 -0700148 }
149
150 @Override
151 public void portChanged(Dpid dpid, OFPortStatus status) {
152 //TODO: Decide whether to evict flows internal store.
153 }
154
155 @Override
156 public void handleMessage(Dpid dpid, OFMessage msg) {
157 switch (msg.getType()) {
158 case FLOW_REMOVED:
alshabibeec3a062014-09-17 18:01:26 -0700159 //TODO: make this better
alshabib8f1cf4a2014-09-17 14:44:48 -0700160 OFFlowRemoved removed = (OFFlowRemoved) msg;
alshabib6b5cfec2014-09-18 17:42:18 -0700161
alshabib1c319ff2014-10-04 20:29:09 -0700162 FlowEntry fr = new FlowEntryBuilder(dpid, removed).build();
alshabib8f1cf4a2014-09-17 14:44:48 -0700163 providerService.flowRemoved(fr);
164 break;
165 case STATS_REPLY:
alshabib97044902014-09-18 14:52:16 -0700166 pushFlowMetrics(dpid, (OFStatsReply) msg);
alshabibeec3a062014-09-17 18:01:26 -0700167 break;
alshabib8f1cf4a2014-09-17 14:44:48 -0700168 case BARRIER_REPLY:
169 case ERROR:
170 default:
alshabib6eb438a2014-10-01 16:39:37 -0700171 log.debug("Unhandled message type: {}", msg.getType());
alshabib8f1cf4a2014-09-17 14:44:48 -0700172 }
173
174 }
175
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700176 @Override
177 public void roleAssertFailed(Dpid dpid, RoleState role) {
178 // TODO Auto-generated method stub
179
180 }
181
alshabib54ce5892014-09-23 17:50:51 -0700182 private synchronized void pushFlowMetrics(Dpid dpid, OFStatsReply stats) {
alshabib5c370ff2014-09-18 10:12:14 -0700183 if (stats.getStatsType() != OFStatsType.FLOW) {
184 return;
185 }
alshabib54ce5892014-09-23 17:50:51 -0700186 DeviceId did = DeviceId.deviceId(Dpid.uri(dpid));
alshabib5c370ff2014-09-18 10:12:14 -0700187 final OFFlowStatsReply replies = (OFFlowStatsReply) stats;
alshabib54ce5892014-09-23 17:50:51 -0700188 //final List<FlowRule> entries = Lists.newLinkedList();
189
alshabib5c370ff2014-09-18 10:12:14 -0700190 for (OFFlowStatsEntry reply : replies.getEntries()) {
alshabib19fdc122014-10-03 11:38:19 -0700191 if (!tableMissRule(dpid, reply)) {
alshabib1c319ff2014-10-04 20:29:09 -0700192 completeEntries.put(did, new FlowEntryBuilder(dpid, reply).build());
alshabib19fdc122014-10-03 11:38:19 -0700193 }
alshabib5c370ff2014-09-18 10:12:14 -0700194 }
alshabib54ce5892014-09-23 17:50:51 -0700195
196 if (!stats.getFlags().contains(OFStatsReplyFlags.REPLY_MORE)) {
197 log.debug("sending flowstats to core {}", completeEntries.get(did));
198 providerService.pushFlowMetrics(did, completeEntries.get(did));
199 completeEntries.removeAll(did);
200 }
alshabib5c370ff2014-09-18 10:12:14 -0700201 }
202
alshabib19fdc122014-10-03 11:38:19 -0700203 private boolean tableMissRule(Dpid dpid, OFFlowStatsEntry reply) {
204 // TODO NEED TO FIND A BETTER WAY TO AVOID DOING THIS
205 if (reply.getVersion().equals(OFVersion.OF_10) ||
206 reply.getMatch().getMatchFields().iterator().hasNext()) {
207 return false;
208 }
209 for (OFInstruction ins : reply.getInstructions()) {
210 if (ins.getType() == OFInstructionType.APPLY_ACTIONS) {
211 OFInstructionApplyActions apply = (OFInstructionApplyActions) ins;
212 List<OFAction> acts = apply.getActions();
213 for (OFAction act : acts) {
214 if (act.getType() == OFActionType.OUTPUT) {
215 OFActionOutput out = (OFActionOutput) act;
216 if (out.getPort() == OFPort.CONTROLLER) {
217 return true;
218 }
219 }
220 }
221 }
222 }
223 return false;
224 }
225
alshabib8f1cf4a2014-09-17 14:44:48 -0700226 }
alshabib1cc04f72014-09-16 16:09:58 -0700227
228
alshabiba68eb962014-09-24 20:34:13 -0700229
230
alshabib1cc04f72014-09-16 16:09:58 -0700231}