blob: 49a420f3bab4b7d89c38a60123f04f77780fc2da [file] [log] [blame]
alshabib030111e2014-09-15 15:56:42 -07001package org.onlab.onos.fwd;
2
Jonathan Hartbc4a7932014-10-21 11:46:00 -07003import static org.slf4j.LoggerFactory.getLogger;
4
5import java.util.Dictionary;
6import java.util.Set;
7
alshabib030111e2014-09-15 15:56:42 -07008import org.apache.felix.scr.annotations.Activate;
9import org.apache.felix.scr.annotations.Component;
10import org.apache.felix.scr.annotations.Deactivate;
tomc16656f2014-10-15 18:30:31 -070011import org.apache.felix.scr.annotations.Modified;
12import org.apache.felix.scr.annotations.Property;
alshabib030111e2014-09-15 15:56:42 -070013import org.apache.felix.scr.annotations.Reference;
14import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabiba68eb962014-09-24 20:34:13 -070015import org.onlab.onos.ApplicationId;
alshabib92c65ad2014-10-08 21:56:05 -070016import org.onlab.onos.CoreService;
tomc370ebd2014-09-16 01:25:21 -070017import org.onlab.onos.net.Host;
18import org.onlab.onos.net.HostId;
19import org.onlab.onos.net.Path;
20import org.onlab.onos.net.PortNumber;
alshabib7b2748f2014-09-16 20:21:11 -070021import org.onlab.onos.net.flow.DefaultFlowRule;
22import org.onlab.onos.net.flow.DefaultTrafficSelector;
23import org.onlab.onos.net.flow.DefaultTrafficTreatment;
24import org.onlab.onos.net.flow.FlowRule;
25import org.onlab.onos.net.flow.FlowRuleService;
26import org.onlab.onos.net.flow.TrafficSelector;
27import org.onlab.onos.net.flow.TrafficTreatment;
alshabib8aef1ad2014-09-15 17:47:31 -070028import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070029import org.onlab.onos.net.packet.InboundPacket;
30import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070031import org.onlab.onos.net.packet.PacketProcessor;
32import org.onlab.onos.net.packet.PacketService;
33import org.onlab.onos.net.topology.TopologyService;
alshabib7b2748f2014-09-16 20:21:11 -070034import org.onlab.packet.Ethernet;
tomc16656f2014-10-15 18:30:31 -070035import org.osgi.service.component.ComponentContext;
tomc370ebd2014-09-16 01:25:21 -070036import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070037
tomc370ebd2014-09-16 01:25:21 -070038/**
39 * Sample reactive forwarding application.
40 */
41@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070042public class ReactiveForwarding {
43
alshabibba5ac482014-10-02 17:15:20 -070044 private static final int TIMEOUT = 10;
alshabiba0e04982014-10-03 13:03:19 -070045 private static final int PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070046
tomc370ebd2014-09-16 01:25:21 -070047 private final Logger log = getLogger(getClass());
48
alshabib030111e2014-09-15 15:56:42 -070049 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
50 protected TopologyService topologyService;
51
52 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected PacketService packetService;
54
alshabib8aef1ad2014-09-15 17:47:31 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected HostService hostService;
57
alshabib7b2748f2014-09-16 20:21:11 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected FlowRuleService flowRuleService;
60
alshabib92c65ad2014-10-08 21:56:05 -070061 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
62 protected CoreService coreService;
63
tomc370ebd2014-09-16 01:25:21 -070064 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070065
alshabiba68eb962014-09-24 20:34:13 -070066 private ApplicationId appId;
67
Thomas Vachuska28dfb602014-10-16 08:49:17 -070068 @Property(name = "enabled", boolValue = true,
69 label = "Enable forwarding; default is true")
tomc16656f2014-10-15 18:30:31 -070070 private boolean isEnabled = true;
71
alshabib030111e2014-09-15 15:56:42 -070072 @Activate
73 public void activate() {
alshabib92c65ad2014-10-08 21:56:05 -070074 appId = coreService.registerApplication("org.onlab.onos.fwd");
alshabibc274c902014-10-03 14:58:27 -070075 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
alshabiba68eb962014-09-24 20:34:13 -070076 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070077 }
78
79 @Deactivate
80 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070081 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -070082 packetService.removeProcessor(processor);
83 processor = null;
tomc370ebd2014-09-16 01:25:21 -070084 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -070085 }
tomc370ebd2014-09-16 01:25:21 -070086
tomc16656f2014-10-15 18:30:31 -070087 @Modified
88 public void modified(ComponentContext context) {
89 Dictionary properties = context.getProperties();
90 String flag = (String) properties.get("enabled");
91 if (flag != null) {
92 boolean enabled = flag.equals("true");
93 if (isEnabled != enabled) {
94 isEnabled = enabled;
95 if (!isEnabled) {
96 flowRuleService.removeFlowRulesById(appId);
97 }
Thomas Vachuska28dfb602014-10-16 08:49:17 -070098 log.info("Reconfigured. Forwarding is {}",
99 isEnabled ? "enabled" : "disabled");
tomc16656f2014-10-15 18:30:31 -0700100 }
101 }
102 }
tomc370ebd2014-09-16 01:25:21 -0700103
104 /**
105 * Packet processor responsible for forwarding packets along their paths.
106 */
107 private class ReactivePacketProcessor implements PacketProcessor {
108
109 @Override
110 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700111 // Stop processing if the packet has been handled, since we
112 // can't do any more to it.
tomc16656f2014-10-15 18:30:31 -0700113 if (!isEnabled || context.isHandled()) {
alshabib7b2748f2014-09-16 20:21:11 -0700114 return;
115 }
tomdc95b8a2014-09-17 08:07:26 -0700116
tomc370ebd2014-09-16 01:25:21 -0700117 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -0700118 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -0700119
tom642b2262014-09-17 13:52:55 -0700120 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700121
122 // Do we know who this is for? If not, flood and bail.
123 Host dst = hostService.getHost(id);
124 if (dst == null) {
125 flood(context);
126 return;
127 }
128
129 // Are we on an edge switch that our destination is on? If so,
130 // simply forward out to the destination and bail.
131 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700132 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
133 installRule(context, dst.location().port());
134 }
tomc370ebd2014-09-16 01:25:21 -0700135 return;
136 }
137
138 // Otherwise, get a set of paths that lead from here to the
139 // destination edge switch.
140 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700141 pkt.receivedFrom().deviceId(),
142 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700143 if (paths.isEmpty()) {
144 // If there are no paths, flood and bail.
145 flood(context);
146 return;
147 }
148
149 // Otherwise, pick a path that does not lead back to where we
150 // came from; if no such path, flood and bail.
151 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
152 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700153 log.warn("Doh... don't know where to go... {} -> {} received on {}",
tomc16656f2014-10-15 18:30:31 -0700154 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
155 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700156 flood(context);
157 return;
158 }
159
160 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700161 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700162 }
163 }
164
165 // Selects a path from the given set that does not lead back to the
166 // specified port.
167 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
168 for (Path path : paths) {
169 if (!path.src().port().equals(notToPort)) {
170 return path;
171 }
172 }
173 return null;
174 }
175
tom642b2262014-09-17 13:52:55 -0700176 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700177 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700178 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700179 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700180 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700181 } else {
182 context.block();
183 }
184 }
185
tom642b2262014-09-17 13:52:55 -0700186 // Sends a packet out the specified port.
187 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700188 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700189 context.send();
190 }
191
192 // Install a rule forwarding the packet to the specified port.
193 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700194 // We don't yet support bufferids in the flowservice so packet out first.
195 packetOut(context, portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700196
alshabibc274c902014-10-03 14:58:27 -0700197 // Install the flow rule to handle this type of message from now on.
198 Ethernet inPkt = context.inPacket().parsed();
199 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
200 builder.matchEthType(inPkt.getEtherType())
tomc16656f2014-10-15 18:30:31 -0700201 .matchEthSrc(inPkt.getSourceMAC())
202 .matchEthDst(inPkt.getDestinationMAC())
203 .matchInport(context.inPacket().receivedFrom().port());
alshabib7b2748f2014-09-16 20:21:11 -0700204
alshabibc274c902014-10-03 14:58:27 -0700205 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
206 treat.setOutput(portNumber);
alshabib6eb438a2014-10-01 16:39:37 -0700207
alshabibc274c902014-10-03 14:58:27 -0700208 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
Jonathan Hartbc4a7932014-10-21 11:46:00 -0700209 builder.build(), treat.build(), PRIORITY, appId, TIMEOUT, false);
alshabibc274c902014-10-03 14:58:27 -0700210
211 flowRuleService.applyFlowRules(f);
tomc370ebd2014-09-16 01:25:21 -0700212 }
213
alshabib030111e2014-09-15 15:56:42 -0700214}
215
tomc370ebd2014-09-16 01:25:21 -0700216