blob: e5eac738a232ece3bb594cf77a20e9d8042b524b [file] [log] [blame]
alshabib030111e2014-09-15 15:56:42 -07001package org.onlab.onos.fwd;
2
alshabibe9d3a322014-09-23 15:18:33 -07003import static org.slf4j.LoggerFactory.getLogger;
4
5import java.util.Set;
6
alshabib030111e2014-09-15 15:56:42 -07007import org.apache.felix.scr.annotations.Activate;
8import org.apache.felix.scr.annotations.Component;
9import org.apache.felix.scr.annotations.Deactivate;
10import org.apache.felix.scr.annotations.Reference;
11import org.apache.felix.scr.annotations.ReferenceCardinality;
alshabiba68eb962014-09-24 20:34:13 -070012import org.onlab.onos.ApplicationId;
alshabib92c65ad2014-10-08 21:56:05 -070013import org.onlab.onos.CoreService;
tomc370ebd2014-09-16 01:25:21 -070014import org.onlab.onos.net.Host;
15import org.onlab.onos.net.HostId;
16import org.onlab.onos.net.Path;
17import org.onlab.onos.net.PortNumber;
alshabib7b2748f2014-09-16 20:21:11 -070018import org.onlab.onos.net.flow.DefaultFlowRule;
19import org.onlab.onos.net.flow.DefaultTrafficSelector;
20import org.onlab.onos.net.flow.DefaultTrafficTreatment;
21import org.onlab.onos.net.flow.FlowRule;
22import org.onlab.onos.net.flow.FlowRuleService;
23import org.onlab.onos.net.flow.TrafficSelector;
24import org.onlab.onos.net.flow.TrafficTreatment;
alshabib8aef1ad2014-09-15 17:47:31 -070025import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070026import org.onlab.onos.net.packet.InboundPacket;
27import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070028import org.onlab.onos.net.packet.PacketProcessor;
29import org.onlab.onos.net.packet.PacketService;
30import org.onlab.onos.net.topology.TopologyService;
alshabib7b2748f2014-09-16 20:21:11 -070031import org.onlab.packet.Ethernet;
tomc370ebd2014-09-16 01:25:21 -070032import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070033
tomc370ebd2014-09-16 01:25:21 -070034/**
35 * Sample reactive forwarding application.
36 */
37@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070038public class ReactiveForwarding {
39
alshabibba5ac482014-10-02 17:15:20 -070040 private static final int TIMEOUT = 10;
alshabiba0e04982014-10-03 13:03:19 -070041 private static final int PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070042
tomc370ebd2014-09-16 01:25:21 -070043 private final Logger log = getLogger(getClass());
44
alshabib030111e2014-09-15 15:56:42 -070045 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
46 protected TopologyService topologyService;
47
48 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
49 protected PacketService packetService;
50
alshabib8aef1ad2014-09-15 17:47:31 -070051 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
52 protected HostService hostService;
53
alshabib7b2748f2014-09-16 20:21:11 -070054 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 protected FlowRuleService flowRuleService;
56
alshabib92c65ad2014-10-08 21:56:05 -070057 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 protected CoreService coreService;
59
tomc370ebd2014-09-16 01:25:21 -070060 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070061
alshabiba68eb962014-09-24 20:34:13 -070062 private ApplicationId appId;
63
alshabib030111e2014-09-15 15:56:42 -070064 @Activate
65 public void activate() {
alshabib92c65ad2014-10-08 21:56:05 -070066 appId = coreService.registerApplication("org.onlab.onos.fwd");
alshabibc274c902014-10-03 14:58:27 -070067 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
alshabiba68eb962014-09-24 20:34:13 -070068 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070069 }
70
71 @Deactivate
72 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070073 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -070074 packetService.removeProcessor(processor);
75 processor = null;
tomc370ebd2014-09-16 01:25:21 -070076 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -070077 }
tomc370ebd2014-09-16 01:25:21 -070078
79
80 /**
81 * Packet processor responsible for forwarding packets along their paths.
82 */
83 private class ReactivePacketProcessor implements PacketProcessor {
84
85 @Override
86 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -070087 // Stop processing if the packet has been handled, since we
88 // can't do any more to it.
alshabib7b2748f2014-09-16 20:21:11 -070089 if (context.isHandled()) {
90 return;
91 }
tomdc95b8a2014-09-17 08:07:26 -070092
tomc370ebd2014-09-16 01:25:21 -070093 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -070094 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -070095
tom642b2262014-09-17 13:52:55 -070096 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -070097
98 // Do we know who this is for? If not, flood and bail.
99 Host dst = hostService.getHost(id);
100 if (dst == null) {
101 flood(context);
102 return;
103 }
104
105 // Are we on an edge switch that our destination is on? If so,
106 // simply forward out to the destination and bail.
107 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700108 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
109 installRule(context, dst.location().port());
110 }
tomc370ebd2014-09-16 01:25:21 -0700111 return;
112 }
113
114 // Otherwise, get a set of paths that lead from here to the
115 // destination edge switch.
116 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700117 pkt.receivedFrom().deviceId(),
118 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700119 if (paths.isEmpty()) {
120 // If there are no paths, flood and bail.
121 flood(context);
122 return;
123 }
124
125 // Otherwise, pick a path that does not lead back to where we
126 // came from; if no such path, flood and bail.
127 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
128 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700129 log.warn("Doh... don't know where to go... {} -> {} received on {}",
alshabibe9d3a322014-09-23 15:18:33 -0700130 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
131 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700132 flood(context);
133 return;
134 }
135
136 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700137 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700138 }
139 }
140
141 // Selects a path from the given set that does not lead back to the
142 // specified port.
143 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
144 for (Path path : paths) {
145 if (!path.src().port().equals(notToPort)) {
146 return path;
147 }
148 }
149 return null;
150 }
151
tom642b2262014-09-17 13:52:55 -0700152 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700153 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700154 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700155 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700156 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700157 } else {
158 context.block();
159 }
160 }
161
tom642b2262014-09-17 13:52:55 -0700162 // Sends a packet out the specified port.
163 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700164 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700165 context.send();
166 }
167
168 // Install a rule forwarding the packet to the specified port.
169 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700170 // We don't yet support bufferids in the flowservice so packet out first.
171 packetOut(context, portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700172
alshabib7b2748f2014-09-16 20:21:11 -0700173
alshabib7b2748f2014-09-16 20:21:11 -0700174
alshabibc274c902014-10-03 14:58:27 -0700175 // Install the flow rule to handle this type of message from now on.
176 Ethernet inPkt = context.inPacket().parsed();
177 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
178 builder.matchEthType(inPkt.getEtherType())
179 .matchEthSrc(inPkt.getSourceMAC())
180 .matchEthDst(inPkt.getDestinationMAC())
181 .matchInport(context.inPacket().receivedFrom().port());
alshabib7b2748f2014-09-16 20:21:11 -0700182
alshabibc274c902014-10-03 14:58:27 -0700183 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
184 treat.setOutput(portNumber);
alshabib6eb438a2014-10-01 16:39:37 -0700185
alshabibc274c902014-10-03 14:58:27 -0700186 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
187 builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
188
189 flowRuleService.applyFlowRules(f);
190
tomc370ebd2014-09-16 01:25:21 -0700191 }
192
alshabib030111e2014-09-15 15:56:42 -0700193}
194
tomc370ebd2014-09-16 01:25:21 -0700195