blob: 5857438bfe406ccd5d2cc1501a75136eda68da8e [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;
tomc370ebd2014-09-16 01:25:21 -070013import org.onlab.onos.net.Host;
14import org.onlab.onos.net.HostId;
15import org.onlab.onos.net.Path;
16import org.onlab.onos.net.PortNumber;
alshabib7b2748f2014-09-16 20:21:11 -070017import org.onlab.onos.net.flow.DefaultFlowRule;
18import org.onlab.onos.net.flow.DefaultTrafficSelector;
19import org.onlab.onos.net.flow.DefaultTrafficTreatment;
20import org.onlab.onos.net.flow.FlowRule;
21import org.onlab.onos.net.flow.FlowRuleService;
22import org.onlab.onos.net.flow.TrafficSelector;
23import org.onlab.onos.net.flow.TrafficTreatment;
alshabib8aef1ad2014-09-15 17:47:31 -070024import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070025import org.onlab.onos.net.packet.InboundPacket;
26import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070027import org.onlab.onos.net.packet.PacketProcessor;
28import org.onlab.onos.net.packet.PacketService;
alshabibb5522ff2014-09-29 19:20:00 -070029import org.onlab.onos.net.proxyarp.ProxyArpService;
alshabib030111e2014-09-15 15:56:42 -070030import org.onlab.onos.net.topology.TopologyService;
alshabibb5522ff2014-09-29 19:20:00 -070031import org.onlab.packet.ARP;
alshabib7b2748f2014-09-16 20:21:11 -070032import org.onlab.packet.Ethernet;
tomc370ebd2014-09-16 01:25:21 -070033import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070034
tomc370ebd2014-09-16 01:25:21 -070035/**
36 * Sample reactive forwarding application.
37 */
38@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070039public class ReactiveForwarding {
40
alshabibba5ac482014-10-02 17:15:20 -070041 private static final int TIMEOUT = 10;
alshabiba0e04982014-10-03 13:03:19 -070042 private static final int PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070043
tomc370ebd2014-09-16 01:25:21 -070044 private final Logger log = getLogger(getClass());
45
alshabib030111e2014-09-15 15:56:42 -070046 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
47 protected TopologyService topologyService;
48
49 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
50 protected PacketService packetService;
51
alshabib8aef1ad2014-09-15 17:47:31 -070052 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected HostService hostService;
54
alshabib7b2748f2014-09-16 20:21:11 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
56 protected FlowRuleService flowRuleService;
57
alshabibb5522ff2014-09-29 19:20:00 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 protected ProxyArpService proxyArpService;
60
tomc370ebd2014-09-16 01:25:21 -070061 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070062
alshabiba68eb962014-09-24 20:34:13 -070063 private ApplicationId appId;
64
alshabib030111e2014-09-15 15:56:42 -070065 @Activate
66 public void activate() {
alshabiba68eb962014-09-24 20:34:13 -070067 appId = ApplicationId.getAppId();
alshabib030111e2014-09-15 15:56:42 -070068 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1);
alshabiba68eb962014-09-24 20:34:13 -070069 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070070 }
71
72 @Deactivate
73 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070074 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -070075 packetService.removeProcessor(processor);
76 processor = null;
tomc370ebd2014-09-16 01:25:21 -070077 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -070078 }
tomc370ebd2014-09-16 01:25:21 -070079
80
81 /**
82 * Packet processor responsible for forwarding packets along their paths.
83 */
84 private class ReactivePacketProcessor implements PacketProcessor {
85
86 @Override
87 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -070088 // Stop processing if the packet has been handled, since we
89 // can't do any more to it.
alshabib7b2748f2014-09-16 20:21:11 -070090 if (context.isHandled()) {
91 return;
92 }
tomdc95b8a2014-09-17 08:07:26 -070093
tomc370ebd2014-09-16 01:25:21 -070094 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -070095 Ethernet ethPkt = pkt.parsed();
alshabibb5522ff2014-09-29 19:20:00 -070096 if (ethPkt.getEtherType() == Ethernet.TYPE_ARP) {
97 ARP arp = (ARP) ethPkt.getPayload();
98 if (arp.getOpCode() == ARP.OP_REPLY) {
99 proxyArpService.forward(ethPkt);
100 } else if (arp.getOpCode() == ARP.OP_REQUEST) {
101 proxyArpService.reply(ethPkt);
102 }
103 context.block();
104 return;
105 }
alshabib6eb438a2014-10-01 16:39:37 -0700106
tom642b2262014-09-17 13:52:55 -0700107 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700108
109 // Do we know who this is for? If not, flood and bail.
110 Host dst = hostService.getHost(id);
111 if (dst == null) {
112 flood(context);
113 return;
114 }
115
116 // Are we on an edge switch that our destination is on? If so,
117 // simply forward out to the destination and bail.
118 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700119 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
120 installRule(context, dst.location().port());
121 }
tomc370ebd2014-09-16 01:25:21 -0700122 return;
123 }
124
125 // Otherwise, get a set of paths that lead from here to the
126 // destination edge switch.
127 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700128 pkt.receivedFrom().deviceId(),
129 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700130 if (paths.isEmpty()) {
131 // If there are no paths, flood and bail.
132 flood(context);
133 return;
134 }
135
136 // Otherwise, pick a path that does not lead back to where we
137 // came from; if no such path, flood and bail.
138 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
139 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700140 log.warn("Doh... don't know where to go... {} -> {} received on {}",
alshabibe9d3a322014-09-23 15:18:33 -0700141 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
142 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700143 flood(context);
144 return;
145 }
146
147 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700148 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700149 }
150 }
151
152 // Selects a path from the given set that does not lead back to the
153 // specified port.
154 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
155 for (Path path : paths) {
156 if (!path.src().port().equals(notToPort)) {
157 return path;
158 }
159 }
160 return null;
161 }
162
tom642b2262014-09-17 13:52:55 -0700163 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700164 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700165 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700166 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700167 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700168 } else {
169 context.block();
170 }
171 }
172
tom642b2262014-09-17 13:52:55 -0700173 // Sends a packet out the specified port.
174 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700175 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700176 context.send();
177 }
178
179 // Install a rule forwarding the packet to the specified port.
180 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700181 // We don't yet support bufferids in the flowservice so packet out first.
182 packetOut(context, portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700183
alshabib6eb438a2014-10-01 16:39:37 -0700184 if (context.inPacket().parsed().getEtherType() == Ethernet.TYPE_IPV4) {
alshabib7b2748f2014-09-16 20:21:11 -0700185
alshabib6eb438a2014-10-01 16:39:37 -0700186 // Install the flow rule to handle this type of message from now on.
187 Ethernet inPkt = context.inPacket().parsed();
tom9a693fd2014-10-03 11:32:19 -0700188 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
alshabib6eb438a2014-10-01 16:39:37 -0700189 builder.matchEthType(inPkt.getEtherType())
alshabibba5ac482014-10-02 17:15:20 -0700190 .matchEthSrc(inPkt.getSourceMAC())
191 .matchEthDst(inPkt.getDestinationMAC())
192 .matchInport(context.inPacket().receivedFrom().port());
alshabib7b2748f2014-09-16 20:21:11 -0700193
tom9a693fd2014-10-03 11:32:19 -0700194 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
alshabib6eb438a2014-10-01 16:39:37 -0700195 treat.setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700196
alshabib6eb438a2014-10-01 16:39:37 -0700197 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
alshabiba0e04982014-10-03 13:03:19 -0700198 builder.build(), treat.build(), PRIORITY, appId, TIMEOUT);
alshabib6eb438a2014-10-01 16:39:37 -0700199
200 flowRuleService.applyFlowRules(f);
201 }
tomc370ebd2014-09-16 01:25:21 -0700202 }
203
alshabib030111e2014-09-15 15:56:42 -0700204}
205
tomc370ebd2014-09-16 01:25:21 -0700206