blob: 06bcfcb7cbd965ce0a1d9ab7f6526fafadc4a29e [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;
24import org.onlab.onos.net.flow.criteria.Criteria;
alshabib55a55d92014-09-16 11:59:31 -070025import org.onlab.onos.net.flow.instructions.Instructions;
alshabib8aef1ad2014-09-15 17:47:31 -070026import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070027import org.onlab.onos.net.packet.InboundPacket;
28import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070029import org.onlab.onos.net.packet.PacketProcessor;
30import org.onlab.onos.net.packet.PacketService;
31import org.onlab.onos.net.topology.TopologyService;
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
tomc370ebd2014-09-16 01:25:21 -070041 private final Logger log = getLogger(getClass());
42
alshabib030111e2014-09-15 15:56:42 -070043 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
44 protected TopologyService topologyService;
45
46 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
47 protected PacketService packetService;
48
alshabib8aef1ad2014-09-15 17:47:31 -070049 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
50 protected HostService hostService;
51
alshabib7b2748f2014-09-16 20:21:11 -070052 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected FlowRuleService flowRuleService;
54
tomc370ebd2014-09-16 01:25:21 -070055 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070056
alshabiba68eb962014-09-24 20:34:13 -070057 private ApplicationId appId;
58
alshabib030111e2014-09-15 15:56:42 -070059 @Activate
60 public void activate() {
alshabiba68eb962014-09-24 20:34:13 -070061 appId = ApplicationId.getAppId();
alshabib030111e2014-09-15 15:56:42 -070062 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1);
alshabiba68eb962014-09-24 20:34:13 -070063 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070064 }
65
66 @Deactivate
67 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070068 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -070069 packetService.removeProcessor(processor);
70 processor = null;
tomc370ebd2014-09-16 01:25:21 -070071 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -070072 }
tomc370ebd2014-09-16 01:25:21 -070073
74
75 /**
76 * Packet processor responsible for forwarding packets along their paths.
77 */
78 private class ReactivePacketProcessor implements PacketProcessor {
79
80 @Override
81 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -070082 // Stop processing if the packet has been handled, since we
83 // can't do any more to it.
alshabib7b2748f2014-09-16 20:21:11 -070084 if (context.isHandled()) {
85 return;
86 }
tomdc95b8a2014-09-17 08:07:26 -070087
tomc370ebd2014-09-16 01:25:21 -070088 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -070089 Ethernet ethPkt = pkt.parsed();
90 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -070091
92 // Do we know who this is for? If not, flood and bail.
93 Host dst = hostService.getHost(id);
94 if (dst == null) {
95 flood(context);
96 return;
97 }
98
99 // Are we on an edge switch that our destination is on? If so,
100 // simply forward out to the destination and bail.
101 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib7b2748f2014-09-16 20:21:11 -0700102 installRule(context, dst.location().port());
tomc370ebd2014-09-16 01:25:21 -0700103 return;
104 }
105
106 // Otherwise, get a set of paths that lead from here to the
107 // destination edge switch.
108 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700109 pkt.receivedFrom().deviceId(),
110 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700111 if (paths.isEmpty()) {
112 // If there are no paths, flood and bail.
113 flood(context);
114 return;
115 }
116
117 // Otherwise, pick a path that does not lead back to where we
118 // came from; if no such path, flood and bail.
119 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
120 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700121 log.warn("Doh... don't know where to go... {} -> {} received on {}",
alshabibe9d3a322014-09-23 15:18:33 -0700122 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
123 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700124 flood(context);
125 return;
126 }
127
128 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700129 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700130 }
131 }
132
133 // Selects a path from the given set that does not lead back to the
134 // specified port.
135 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
136 for (Path path : paths) {
137 if (!path.src().port().equals(notToPort)) {
138 return path;
139 }
140 }
141 return null;
142 }
143
tom642b2262014-09-17 13:52:55 -0700144 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700145 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700146 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
alshabibe9d3a322014-09-23 15:18:33 -0700147 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700148 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700149 } else {
150 context.block();
151 }
152 }
153
tom642b2262014-09-17 13:52:55 -0700154 // Sends a packet out the specified port.
155 private void packetOut(PacketContext context, PortNumber portNumber) {
156 context.treatmentBuilder().add(Instructions.createOutput(portNumber));
alshabib7b2748f2014-09-16 20:21:11 -0700157 context.send();
158 }
159
160 // Install a rule forwarding the packet to the specified port.
161 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700162 // We don't yet support bufferids in the flowservice so packet out first.
163 packetOut(context, portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700164
tom642b2262014-09-17 13:52:55 -0700165 // Install the flow rule to handle this type of message from now on.
alshabib7b2748f2014-09-16 20:21:11 -0700166 Ethernet inPkt = context.inPacket().parsed();
167 TrafficSelector.Builder builder = new DefaultTrafficSelector.Builder();
168 builder.add(Criteria.matchEthType(inPkt.getEtherType()))
alshabibe9d3a322014-09-23 15:18:33 -0700169 .add(Criteria.matchEthSrc(inPkt.getSourceMAC()))
170 .add(Criteria.matchEthDst(inPkt.getDestinationMAC()))
171 .add(Criteria.matchInPort(context.inPacket().receivedFrom().port()));
alshabib7b2748f2014-09-16 20:21:11 -0700172
173 TrafficTreatment.Builder treat = new DefaultTrafficTreatment.Builder();
174 treat.add(Instructions.createOutput(portNumber));
175
176 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
alshabiba68eb962014-09-24 20:34:13 -0700177 builder.build(), treat.build(), 0, appId);
alshabib7b2748f2014-09-16 20:21:11 -0700178
179 flowRuleService.applyFlowRules(f);
tomc370ebd2014-09-16 01:25:21 -0700180 }
181
alshabib030111e2014-09-15 15:56:42 -0700182}
183
tomc370ebd2014-09-16 01:25:21 -0700184