blob: 6d92ad8a2ea3d28841e63a6b5a4646f188da4742 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
alshabib030111e2014-09-15 15:56:42 -070019package org.onlab.onos.fwd;
20
Jonathan Hartbc4a7932014-10-21 11:46:00 -070021import static org.slf4j.LoggerFactory.getLogger;
22
23import java.util.Dictionary;
24import java.util.Set;
25
alshabib030111e2014-09-15 15:56:42 -070026import org.apache.felix.scr.annotations.Activate;
27import org.apache.felix.scr.annotations.Component;
28import org.apache.felix.scr.annotations.Deactivate;
tomc16656f2014-10-15 18:30:31 -070029import org.apache.felix.scr.annotations.Modified;
30import org.apache.felix.scr.annotations.Property;
alshabib030111e2014-09-15 15:56:42 -070031import org.apache.felix.scr.annotations.Reference;
32import org.apache.felix.scr.annotations.ReferenceCardinality;
Thomas Vachuskae0f804a2014-10-27 23:40:48 -070033import org.onlab.onos.core.ApplicationId;
34import org.onlab.onos.core.CoreService;
tomc370ebd2014-09-16 01:25:21 -070035import org.onlab.onos.net.Host;
36import org.onlab.onos.net.HostId;
37import org.onlab.onos.net.Path;
38import org.onlab.onos.net.PortNumber;
alshabib7b2748f2014-09-16 20:21:11 -070039import org.onlab.onos.net.flow.DefaultFlowRule;
40import org.onlab.onos.net.flow.DefaultTrafficSelector;
41import org.onlab.onos.net.flow.DefaultTrafficTreatment;
42import org.onlab.onos.net.flow.FlowRule;
43import org.onlab.onos.net.flow.FlowRuleService;
44import org.onlab.onos.net.flow.TrafficSelector;
45import org.onlab.onos.net.flow.TrafficTreatment;
alshabib8aef1ad2014-09-15 17:47:31 -070046import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070047import org.onlab.onos.net.packet.InboundPacket;
48import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070049import org.onlab.onos.net.packet.PacketProcessor;
50import org.onlab.onos.net.packet.PacketService;
51import org.onlab.onos.net.topology.TopologyService;
alshabib7b2748f2014-09-16 20:21:11 -070052import org.onlab.packet.Ethernet;
tomc16656f2014-10-15 18:30:31 -070053import org.osgi.service.component.ComponentContext;
tomc370ebd2014-09-16 01:25:21 -070054import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070055
tomc370ebd2014-09-16 01:25:21 -070056/**
57 * Sample reactive forwarding application.
58 */
59@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070060public class ReactiveForwarding {
61
alshabibba5ac482014-10-02 17:15:20 -070062 private static final int TIMEOUT = 10;
alshabiba0e04982014-10-03 13:03:19 -070063 private static final int PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070064
tomc370ebd2014-09-16 01:25:21 -070065 private final Logger log = getLogger(getClass());
66
alshabib030111e2014-09-15 15:56:42 -070067 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected TopologyService topologyService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected PacketService packetService;
72
alshabib8aef1ad2014-09-15 17:47:31 -070073 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected HostService hostService;
75
alshabib7b2748f2014-09-16 20:21:11 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected FlowRuleService flowRuleService;
78
alshabib92c65ad2014-10-08 21:56:05 -070079 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected CoreService coreService;
81
tomc370ebd2014-09-16 01:25:21 -070082 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070083
alshabiba68eb962014-09-24 20:34:13 -070084 private ApplicationId appId;
85
Thomas Vachuska28dfb602014-10-16 08:49:17 -070086 @Property(name = "enabled", boolValue = true,
87 label = "Enable forwarding; default is true")
tomc16656f2014-10-15 18:30:31 -070088 private boolean isEnabled = true;
89
alshabib030111e2014-09-15 15:56:42 -070090 @Activate
91 public void activate() {
alshabib92c65ad2014-10-08 21:56:05 -070092 appId = coreService.registerApplication("org.onlab.onos.fwd");
alshabibc274c902014-10-03 14:58:27 -070093 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
alshabiba68eb962014-09-24 20:34:13 -070094 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070095 }
96
97 @Deactivate
98 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070099 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -0700100 packetService.removeProcessor(processor);
101 processor = null;
tomc370ebd2014-09-16 01:25:21 -0700102 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -0700103 }
tomc370ebd2014-09-16 01:25:21 -0700104
tomc16656f2014-10-15 18:30:31 -0700105 @Modified
106 public void modified(ComponentContext context) {
107 Dictionary properties = context.getProperties();
108 String flag = (String) properties.get("enabled");
109 if (flag != null) {
110 boolean enabled = flag.equals("true");
111 if (isEnabled != enabled) {
112 isEnabled = enabled;
113 if (!isEnabled) {
114 flowRuleService.removeFlowRulesById(appId);
115 }
Thomas Vachuska28dfb602014-10-16 08:49:17 -0700116 log.info("Reconfigured. Forwarding is {}",
117 isEnabled ? "enabled" : "disabled");
tomc16656f2014-10-15 18:30:31 -0700118 }
119 }
120 }
tomc370ebd2014-09-16 01:25:21 -0700121
122 /**
123 * Packet processor responsible for forwarding packets along their paths.
124 */
125 private class ReactivePacketProcessor implements PacketProcessor {
126
127 @Override
128 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700129 // Stop processing if the packet has been handled, since we
130 // can't do any more to it.
tomc16656f2014-10-15 18:30:31 -0700131 if (!isEnabled || context.isHandled()) {
alshabib7b2748f2014-09-16 20:21:11 -0700132 return;
133 }
tomdc95b8a2014-09-17 08:07:26 -0700134
tomc370ebd2014-09-16 01:25:21 -0700135 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -0700136 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -0700137
tom642b2262014-09-17 13:52:55 -0700138 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700139
Thomas Vachuskae1bcb0b2014-10-27 17:45:10 -0700140 // Do not process link-local addresses in any way.
141 if (id.mac().isLinkLocal()) {
142 return;
143 }
144
tomc370ebd2014-09-16 01:25:21 -0700145 // Do we know who this is for? If not, flood and bail.
146 Host dst = hostService.getHost(id);
147 if (dst == null) {
148 flood(context);
149 return;
150 }
151
152 // Are we on an edge switch that our destination is on? If so,
153 // simply forward out to the destination and bail.
154 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700155 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
156 installRule(context, dst.location().port());
157 }
tomc370ebd2014-09-16 01:25:21 -0700158 return;
159 }
160
161 // Otherwise, get a set of paths that lead from here to the
162 // destination edge switch.
163 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700164 pkt.receivedFrom().deviceId(),
165 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700166 if (paths.isEmpty()) {
167 // If there are no paths, flood and bail.
168 flood(context);
169 return;
170 }
171
172 // Otherwise, pick a path that does not lead back to where we
173 // came from; if no such path, flood and bail.
174 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
175 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700176 log.warn("Doh... don't know where to go... {} -> {} received on {}",
tomc16656f2014-10-15 18:30:31 -0700177 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
178 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700179 flood(context);
180 return;
181 }
182
183 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700184 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700185 }
186 }
187
188 // Selects a path from the given set that does not lead back to the
189 // specified port.
190 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
191 for (Path path : paths) {
192 if (!path.src().port().equals(notToPort)) {
193 return path;
194 }
195 }
196 return null;
197 }
198
tom642b2262014-09-17 13:52:55 -0700199 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700200 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700201 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700202 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700203 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700204 } else {
205 context.block();
206 }
207 }
208
tom642b2262014-09-17 13:52:55 -0700209 // Sends a packet out the specified port.
210 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700211 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700212 context.send();
213 }
214
215 // Install a rule forwarding the packet to the specified port.
216 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700217 // We don't yet support bufferids in the flowservice so packet out first.
218 packetOut(context, portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700219
alshabibc274c902014-10-03 14:58:27 -0700220 // Install the flow rule to handle this type of message from now on.
221 Ethernet inPkt = context.inPacket().parsed();
222 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
223 builder.matchEthType(inPkt.getEtherType())
tomc16656f2014-10-15 18:30:31 -0700224 .matchEthSrc(inPkt.getSourceMAC())
225 .matchEthDst(inPkt.getDestinationMAC())
226 .matchInport(context.inPacket().receivedFrom().port());
alshabib7b2748f2014-09-16 20:21:11 -0700227
alshabibc274c902014-10-03 14:58:27 -0700228 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
229 treat.setOutput(portNumber);
alshabib6eb438a2014-10-01 16:39:37 -0700230
alshabibc274c902014-10-03 14:58:27 -0700231 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
Jonathan Hartbc4a7932014-10-21 11:46:00 -0700232 builder.build(), treat.build(), PRIORITY, appId, TIMEOUT, false);
alshabibc274c902014-10-03 14:58:27 -0700233
234 flowRuleService.applyFlowRules(f);
tomc370ebd2014-09-16 01:25:21 -0700235 }
236
alshabib030111e2014-09-15 15:56:42 -0700237}
238
tomc370ebd2014-09-16 01:25:21 -0700239