blob: 2cbfcc448f504f4eafa8d883addf729dfba2c414 [file] [log] [blame]
toma9a77c22014-10-03 17:05:20 -07001package org.onlab.onos.ifwd;
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;
toma9a77c22014-10-03 17:05:20 -07008import org.onlab.onos.net.Host;
9import org.onlab.onos.net.HostId;
10import org.onlab.onos.net.PortNumber;
11import org.onlab.onos.net.flow.DefaultTrafficSelector;
12import org.onlab.onos.net.flow.DefaultTrafficTreatment;
13import org.onlab.onos.net.flow.TrafficSelector;
14import org.onlab.onos.net.flow.TrafficTreatment;
15import org.onlab.onos.net.host.HostService;
16import org.onlab.onos.net.intent.HostToHostIntent;
tom9b4030d2014-10-06 10:39:03 -070017import org.onlab.onos.net.intent.Intent;
toma9a77c22014-10-03 17:05:20 -070018import org.onlab.onos.net.intent.IntentId;
19import org.onlab.onos.net.intent.IntentService;
Brian O'Connor958d3812014-10-03 19:46:23 -070020import org.onlab.onos.net.packet.DefaultOutboundPacket;
toma9a77c22014-10-03 17:05:20 -070021import org.onlab.onos.net.packet.InboundPacket;
Brian O'Connor958d3812014-10-03 19:46:23 -070022import org.onlab.onos.net.packet.OutboundPacket;
toma9a77c22014-10-03 17:05:20 -070023import org.onlab.onos.net.packet.PacketContext;
24import org.onlab.onos.net.packet.PacketProcessor;
25import org.onlab.onos.net.packet.PacketService;
26import org.onlab.onos.net.topology.TopologyService;
27import org.onlab.packet.Ethernet;
28import org.slf4j.Logger;
29
tom9b4030d2014-10-06 10:39:03 -070030import java.util.Map;
31import java.util.concurrent.ConcurrentHashMap;
32
tom0511a522014-10-04 12:06:02 -070033import static org.slf4j.LoggerFactory.getLogger;
34
toma9a77c22014-10-03 17:05:20 -070035/**
36 * WORK-IN-PROGRESS: Sample reactive forwarding application using intent framework.
37 */
38@Component(immediate = true)
39public class IntentReactiveForwarding {
40
toma9a77c22014-10-03 17:05:20 -070041 private final Logger log = getLogger(getClass());
42
43 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
44 protected TopologyService topologyService;
45
46 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
47 protected PacketService packetService;
48
49 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
50 protected IntentService intentService;
51
52 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
53 protected HostService hostService;
54
55 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
56
toma9a77c22014-10-03 17:05:20 -070057 private static long intentId = 1;
58
tom9b4030d2014-10-06 10:39:03 -070059 private Map<HostIdPair, IntentId> intents = new ConcurrentHashMap<>();
60
toma9a77c22014-10-03 17:05:20 -070061 @Activate
62 public void activate() {
toma9a77c22014-10-03 17:05:20 -070063 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
tom0511a522014-10-04 12:06:02 -070064 log.info("Started");
toma9a77c22014-10-03 17:05:20 -070065 }
66
67 @Deactivate
68 public void deactivate() {
69 packetService.removeProcessor(processor);
70 processor = null;
71 log.info("Stopped");
72 }
73
toma9a77c22014-10-03 17:05:20 -070074 /**
75 * Packet processor responsible for forwarding packets along their paths.
76 */
77 private class ReactivePacketProcessor implements PacketProcessor {
78
79 @Override
80 public void process(PacketContext context) {
81 // Stop processing if the packet has been handled, since we
82 // can't do any more to it.
83 if (context.isHandled()) {
84 return;
85 }
86
87 InboundPacket pkt = context.inPacket();
88 Ethernet ethPkt = pkt.parsed();
89
90 HostId srcId = HostId.hostId(ethPkt.getSourceMAC());
91 HostId dstId = HostId.hostId(ethPkt.getDestinationMAC());
92
93 // Do we know who this is for? If not, flood and bail.
94 Host dst = hostService.getHost(dstId);
95 if (dst == null) {
96 flood(context);
97 return;
98 }
99
tom9b4030d2014-10-06 10:39:03 -0700100 // Install a new intent only if we have not installed one already
101 HostIdPair key = new HostIdPair(srcId, dstId);
102 if (!intents.containsKey(key)) {
103 // Otherwise forward and be done with it.
104 intents.put(key, setUpConnectivity(context, srcId, dstId).getId());
105 }
Brian O'Connor958d3812014-10-03 19:46:23 -0700106 forwardPacketToDst(context, dst);
toma9a77c22014-10-03 17:05:20 -0700107 }
108 }
109
110 // Floods the specified packet if permissible.
111 private void flood(PacketContext context) {
112 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
113 context.inPacket().receivedFrom())) {
114 packetOut(context, PortNumber.FLOOD);
115 } else {
116 context.block();
117 }
118 }
119
120 // Sends a packet out the specified port.
121 private void packetOut(PacketContext context, PortNumber portNumber) {
122 context.treatmentBuilder().setOutput(portNumber);
123 context.send();
124 }
125
Brian O'Connor958d3812014-10-03 19:46:23 -0700126 private void forwardPacketToDst(PacketContext context, Host dst) {
127 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(dst.location().port()).build();
128 OutboundPacket packet = new DefaultOutboundPacket(dst.location().deviceId(),
tom0511a522014-10-04 12:06:02 -0700129 treatment, context.inPacket().unparsed());
Brian O'Connor958d3812014-10-03 19:46:23 -0700130 packetService.emit(packet);
131 log.info("sending packet: {}", packet);
132 }
133
toma9a77c22014-10-03 17:05:20 -0700134 // Install a rule forwarding the packet to the specified port.
tom9b4030d2014-10-06 10:39:03 -0700135 private Intent setUpConnectivity(PacketContext context, HostId srcId, HostId dstId) {
toma9a77c22014-10-03 17:05:20 -0700136 TrafficSelector selector = DefaultTrafficSelector.builder().build();
137 TrafficTreatment treatment = DefaultTrafficTreatment.builder().build();
138
139 HostToHostIntent intent =
140 new HostToHostIntent(new IntentId(intentId++), srcId, dstId,
141 selector, treatment);
toma9a77c22014-10-03 17:05:20 -0700142 intentService.submit(intent);
tom9b4030d2014-10-06 10:39:03 -0700143 return intent;
toma9a77c22014-10-03 17:05:20 -0700144 }
145
tom9b4030d2014-10-06 10:39:03 -0700146
147 private class HostIdPair {
148 HostId one;
149 HostId two;
150
151 HostIdPair(HostId one, HostId two) {
152 boolean oneFirst = one.hashCode() < two.hashCode();
153 this.one = oneFirst ? one : two;
154 this.two = oneFirst ? two : one;
155 }
156 }
toma9a77c22014-10-03 17:05:20 -0700157}