blob: 2178247dcbb42f8b3f51b637247f840c15aa1bd2 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.fwd;
alshabib030111e2014-09-15 15:56:42 -070017
Jonathan Hartbc4a7932014-10-21 11:46:00 -070018import static org.slf4j.LoggerFactory.getLogger;
19
20import java.util.Dictionary;
21import java.util.Set;
22
alshabib030111e2014-09-15 15:56:42 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
tomc16656f2014-10-15 18:30:31 -070026import org.apache.felix.scr.annotations.Modified;
27import org.apache.felix.scr.annotations.Property;
alshabib030111e2014-09-15 15:56:42 -070028import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.Host;
33import org.onosproject.net.HostId;
34import org.onosproject.net.Path;
35import org.onosproject.net.PortNumber;
36import org.onosproject.net.flow.DefaultFlowRule;
37import org.onosproject.net.flow.DefaultTrafficSelector;
38import org.onosproject.net.flow.DefaultTrafficTreatment;
39import org.onosproject.net.flow.FlowRule;
40import org.onosproject.net.flow.FlowRuleService;
41import org.onosproject.net.flow.TrafficSelector;
42import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.host.HostService;
44import org.onosproject.net.packet.InboundPacket;
45import org.onosproject.net.packet.PacketContext;
46import org.onosproject.net.packet.PacketProcessor;
47import org.onosproject.net.packet.PacketService;
48import org.onosproject.net.topology.TopologyService;
alshabib7b2748f2014-09-16 20:21:11 -070049import org.onlab.packet.Ethernet;
tomc16656f2014-10-15 18:30:31 -070050import org.osgi.service.component.ComponentContext;
tomc370ebd2014-09-16 01:25:21 -070051import org.slf4j.Logger;
alshabib030111e2014-09-15 15:56:42 -070052
tomc370ebd2014-09-16 01:25:21 -070053/**
54 * Sample reactive forwarding application.
55 */
56@Component(immediate = true)
alshabib030111e2014-09-15 15:56:42 -070057public class ReactiveForwarding {
58
alshabibba5ac482014-10-02 17:15:20 -070059 private static final int TIMEOUT = 10;
alshabiba0e04982014-10-03 13:03:19 -070060 private static final int PRIORITY = 10;
alshabibba5ac482014-10-02 17:15:20 -070061
tomc370ebd2014-09-16 01:25:21 -070062 private final Logger log = getLogger(getClass());
63
alshabib030111e2014-09-15 15:56:42 -070064 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected TopologyService topologyService;
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected PacketService packetService;
69
alshabib8aef1ad2014-09-15 17:47:31 -070070 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected HostService hostService;
72
alshabib7b2748f2014-09-16 20:21:11 -070073 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected FlowRuleService flowRuleService;
75
alshabib92c65ad2014-10-08 21:56:05 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected CoreService coreService;
78
tomc370ebd2014-09-16 01:25:21 -070079 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
alshabib030111e2014-09-15 15:56:42 -070080
alshabiba68eb962014-09-24 20:34:13 -070081 private ApplicationId appId;
82
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -080083 @Property(name = "packetOutOnly", boolValue = false,
84 label = "Enable packet-out only forwarding; default is false")
85 private boolean packetOutOnly = false;
tomc16656f2014-10-15 18:30:31 -070086
alshabib030111e2014-09-15 15:56:42 -070087 @Activate
88 public void activate() {
Brian O'Connorabafb502014-12-02 22:26:20 -080089 appId = coreService.registerApplication("org.onosproject.fwd");
alshabibc274c902014-10-03 14:58:27 -070090 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
alshabiba68eb962014-09-24 20:34:13 -070091 log.info("Started with Application ID {}", appId.id());
alshabib030111e2014-09-15 15:56:42 -070092 }
93
94 @Deactivate
95 public void deactivate() {
alshabiba68eb962014-09-24 20:34:13 -070096 flowRuleService.removeFlowRulesById(appId);
alshabib030111e2014-09-15 15:56:42 -070097 packetService.removeProcessor(processor);
98 processor = null;
tomc370ebd2014-09-16 01:25:21 -070099 log.info("Stopped");
alshabib030111e2014-09-15 15:56:42 -0700100 }
tomc370ebd2014-09-16 01:25:21 -0700101
tomc16656f2014-10-15 18:30:31 -0700102 @Modified
103 public void modified(ComponentContext context) {
104 Dictionary properties = context.getProperties();
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800105 String flag = (String) properties.get("packetOutOnly");
tomc16656f2014-10-15 18:30:31 -0700106 if (flag != null) {
107 boolean enabled = flag.equals("true");
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800108 if (packetOutOnly != enabled) {
109 packetOutOnly = enabled;
110 log.info("Reconfigured. Packet-out only forwarding is {}",
111 packetOutOnly ? "enabled" : "disabled");
tomc16656f2014-10-15 18:30:31 -0700112 }
113 }
114 }
tomc370ebd2014-09-16 01:25:21 -0700115
116 /**
117 * Packet processor responsible for forwarding packets along their paths.
118 */
119 private class ReactivePacketProcessor implements PacketProcessor {
120
121 @Override
122 public void process(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700123 // Stop processing if the packet has been handled, since we
124 // can't do any more to it.
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800125 if (context.isHandled()) {
alshabib7b2748f2014-09-16 20:21:11 -0700126 return;
127 }
tomdc95b8a2014-09-17 08:07:26 -0700128
tomc370ebd2014-09-16 01:25:21 -0700129 InboundPacket pkt = context.inPacket();
tom642b2262014-09-17 13:52:55 -0700130 Ethernet ethPkt = pkt.parsed();
alshabib6eb438a2014-10-01 16:39:37 -0700131
Thomas Vachuska5dd52f72014-11-28 19:27:45 -0800132 // Bail if this is deemed to be a control or IPv6 multicast packet.
133 if (isControlPacket(ethPkt) || isIpv6Multicast(ethPkt)) {
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800134 return;
135 }
136
tom642b2262014-09-17 13:52:55 -0700137 HostId id = HostId.hostId(ethPkt.getDestinationMAC());
tomc370ebd2014-09-16 01:25:21 -0700138
Thomas Vachuskae1bcb0b2014-10-27 17:45:10 -0700139 // Do not process link-local addresses in any way.
140 if (id.mac().isLinkLocal()) {
141 return;
142 }
143
tomc370ebd2014-09-16 01:25:21 -0700144 // Do we know who this is for? If not, flood and bail.
145 Host dst = hostService.getHost(id);
146 if (dst == null) {
147 flood(context);
148 return;
149 }
150
151 // Are we on an edge switch that our destination is on? If so,
152 // simply forward out to the destination and bail.
153 if (pkt.receivedFrom().deviceId().equals(dst.location().deviceId())) {
alshabib6eb438a2014-10-01 16:39:37 -0700154 if (!context.inPacket().receivedFrom().port().equals(dst.location().port())) {
155 installRule(context, dst.location().port());
156 }
tomc370ebd2014-09-16 01:25:21 -0700157 return;
158 }
159
160 // Otherwise, get a set of paths that lead from here to the
161 // destination edge switch.
162 Set<Path> paths = topologyService.getPaths(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700163 pkt.receivedFrom().deviceId(),
164 dst.location().deviceId());
tomc370ebd2014-09-16 01:25:21 -0700165 if (paths.isEmpty()) {
166 // If there are no paths, flood and bail.
167 flood(context);
168 return;
169 }
170
171 // Otherwise, pick a path that does not lead back to where we
172 // came from; if no such path, flood and bail.
173 Path path = pickForwardPath(paths, pkt.receivedFrom().port());
174 if (path == null) {
tom642b2262014-09-17 13:52:55 -0700175 log.warn("Doh... don't know where to go... {} -> {} received on {}",
tomc16656f2014-10-15 18:30:31 -0700176 ethPkt.getSourceMAC(), ethPkt.getDestinationMAC(),
177 pkt.receivedFrom());
tomc370ebd2014-09-16 01:25:21 -0700178 flood(context);
179 return;
180 }
181
182 // Otherwise forward and be done with it.
alshabib7b2748f2014-09-16 20:21:11 -0700183 installRule(context, path.src().port());
tomc370ebd2014-09-16 01:25:21 -0700184 }
Thomas Vachuska01a6ec02014-11-05 09:54:09 -0800185
186 }
187
188 // Indicates whether this is a control packet, e.g. LLDP, BDDP
189 private boolean isControlPacket(Ethernet eth) {
190 short type = eth.getEtherType();
191 return type == Ethernet.TYPE_LLDP || type == Ethernet.TYPE_BSN;
tomc370ebd2014-09-16 01:25:21 -0700192 }
193
Thomas Vachuska5dd52f72014-11-28 19:27:45 -0800194 // Indicated whether this is an IPv6 multicast packet.
195 private boolean isIpv6Multicast(Ethernet eth) {
196 return eth.getEtherType() == Ethernet.TYPE_IPV6 && eth.isMulticast();
197 }
198
tomc370ebd2014-09-16 01:25:21 -0700199 // Selects a path from the given set that does not lead back to the
200 // specified port.
201 private Path pickForwardPath(Set<Path> paths, PortNumber notToPort) {
202 for (Path path : paths) {
203 if (!path.src().port().equals(notToPort)) {
204 return path;
205 }
206 }
207 return null;
208 }
209
tom642b2262014-09-17 13:52:55 -0700210 // Floods the specified packet if permissible.
tomc370ebd2014-09-16 01:25:21 -0700211 private void flood(PacketContext context) {
tomdc95b8a2014-09-17 08:07:26 -0700212 if (topologyService.isBroadcastPoint(topologyService.currentTopology(),
tomc16656f2014-10-15 18:30:31 -0700213 context.inPacket().receivedFrom())) {
tom642b2262014-09-17 13:52:55 -0700214 packetOut(context, PortNumber.FLOOD);
tomc370ebd2014-09-16 01:25:21 -0700215 } else {
216 context.block();
217 }
218 }
219
tom642b2262014-09-17 13:52:55 -0700220 // Sends a packet out the specified port.
221 private void packetOut(PacketContext context, PortNumber portNumber) {
alshabib010c31d2014-09-26 10:01:12 -0700222 context.treatmentBuilder().setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700223 context.send();
224 }
225
226 // Install a rule forwarding the packet to the specified port.
227 private void installRule(PacketContext context, PortNumber portNumber) {
tom642b2262014-09-17 13:52:55 -0700228 // We don't yet support bufferids in the flowservice so packet out first.
229 packetOut(context, portNumber);
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800230 if (!packetOutOnly) {
231 // Install the flow rule to handle this type of message from now on.
232 Ethernet inPkt = context.inPacket().parsed();
233 TrafficSelector.Builder builder = DefaultTrafficSelector.builder();
234 builder.matchEthType(inPkt.getEtherType())
235 .matchEthSrc(inPkt.getSourceMAC())
236 .matchEthDst(inPkt.getDestinationMAC())
237 .matchInport(context.inPacket().receivedFrom().port());
alshabib7b2748f2014-09-16 20:21:11 -0700238
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800239 TrafficTreatment.Builder treat = DefaultTrafficTreatment.builder();
240 treat.setOutput(portNumber);
alshabib7b2748f2014-09-16 20:21:11 -0700241
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800242 FlowRule f = new DefaultFlowRule(context.inPacket().receivedFrom().deviceId(),
243 builder.build(), treat.build(), PRIORITY, appId, TIMEOUT, false);
alshabib6eb438a2014-10-01 16:39:37 -0700244
Thomas Vachuskabd7f4b32014-12-04 20:54:55 -0800245 flowRuleService.applyFlowRules(f);
246 }
tomc370ebd2014-09-16 01:25:21 -0700247 }
248
alshabib030111e2014-09-15 15:56:42 -0700249}
250
tomc370ebd2014-09-16 01:25:21 -0700251