blob: b9ae4c4b351260b4545188edce1a759183e9da32 [file] [log] [blame]
alshabib030111e2014-09-15 15:56:42 -07001package org.onlab.onos.fwd;
2
3import org.apache.felix.scr.annotations.Activate;
4import org.apache.felix.scr.annotations.Component;
5import org.apache.felix.scr.annotations.Deactivate;
6import org.apache.felix.scr.annotations.Reference;
7import org.apache.felix.scr.annotations.ReferenceCardinality;
tomc370ebd2014-09-16 01:25:21 -07008import org.onlab.onos.net.Host;
9import org.onlab.onos.net.HostId;
10import org.onlab.onos.net.Path;
11import org.onlab.onos.net.PortNumber;
alshabib55a55d92014-09-16 11:59:31 -070012import org.onlab.onos.net.flow.instructions.Instructions;
alshabib8aef1ad2014-09-15 17:47:31 -070013import org.onlab.onos.net.host.HostService;
tomc370ebd2014-09-16 01:25:21 -070014import org.onlab.onos.net.packet.InboundPacket;
15import org.onlab.onos.net.packet.PacketContext;
alshabib030111e2014-09-15 15:56:42 -070016import org.onlab.onos.net.packet.PacketProcessor;
17import org.onlab.onos.net.packet.PacketService;
18import org.onlab.onos.net.topology.TopologyService;
tomc370ebd2014-09-16 01:25:21 -070019import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070020
tomc370ebd2014-09-16 01:25:21 -070021import java.util.Set;
22
23import static org.slf4j.LoggerFactory.getLogger;
24
25/**
26 * Sample reactive forwarding application.
27 */
28@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070029public class ReactiveForwarding {
30
tomc370ebd2014-09-16 01:25:21 -070031 private final Logger log = getLogger(getClass());
32
alshabib030111e2014-09-15 15:56:42 -070033 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
34 protected TopologyService topologyService;
35
36 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
37 protected PacketService packetService;
38
alshabib8aef1ad2014-09-15 17:47:31 -070039 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
40 protected HostService hostService;
41
tomc370ebd2014-09-16 01:25:21 -070042 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070043
44 @Activate
45 public void activate() {
alshabib030111e2014-09-15 15:56:42 -070046 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 1);
tomc370ebd2014-09-16 01:25:21 -070047 log.info("Started");
alshabib030111e2014-09-15 15:56:42 -070048 }
49
50 @Deactivate
51 public void deactivate() {
52 packetService.removeProcessor(processor);
53 processor = null;
tomc370ebd2014-09-16 01:25:21 -070054 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -070055 }
tomc370ebd2014-09-16 01:25:21 -070056
57
58 /**
59 * Packet processor responsible for forwarding packets along their paths.
60 */
61 private class ReactivePacketProcessor implements PacketProcessor {
62
63 @Override
64 public void process(PacketContext context) {
65 InboundPacket pkt = context.inPacket();
66 HostId id = HostId.hostId(pkt.parsed().getDestinationMAC());
67
68 // Do we know who this is for? If not, flood and bail.
69 Host dst = hostService.getHost(id);
70 if (dst == null) {
71 flood(context);
72 return;
73 }
74
75 // Are we on an edge switch that our destination is on? If so,
76 // simply forward out to the destination and bail.
77 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
78 forward(context, dst.location().port());
79 return;
80 }
81
82 // Otherwise, get a set of paths that lead from here to the
83 // destination edge switch.
84 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
85 context.inPacket().receivedFrom().deviceId(),
86 dst.location().deviceId());
87 if (paths.isEmpty()) {
88 // If there are no paths, flood and bail.
89 flood(context);
90 return;
91 }
92
93 // Otherwise, pick a path that does not lead back to where we
94 // came from; if no such path, flood and bail.
95 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
96 if (path == null) {
97 log.warn("Doh... don't know where to go...");
98 flood(context);
99 return;
100 }
101
102 // Otherwise forward and be done with it.
103 forward(context, path.src().port());
104 }
105 }
106
107 // Selects a path from the given set that does not lead back to the
108 // specified port.
109 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
110 for (Path path : paths) {
111 if (!path.src().port().equals(notToPort)) {
112 return path;
113 }
114 }
115 return null;
116 }
117
118 // Floods the specified packet.
119 private void flood(PacketContext context) {
120 boolean canBcast = topologyService.isBroadcastPoint(topologyService.currentTopology(),
121 context.inPacket().receivedFrom());
122 if (canBcast) {
123 forward(context, PortNumber.FLOOD);
124 } else {
125 context.block();
126 }
127 }
128
129 // Forwards the packet to the specified port.
130 private void forward(PacketContext context, PortNumber portNumber) {
131 context.treatmentBuilder().add(Instructions.createOutput(portNumber));
132 context.send();
133 }
134
alshabib030111e2014-09-15 15:56:42 -0700135}
136
tomc370ebd2014-09-16 01:25:21 -0700137