blob: e818b416f1767c5ce145d5da92d5911dad2b7c6d [file] [log] [blame]
Pingping Line28ae4c2015-03-13 11:37:03 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * 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
7 *
8 * 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.
15 */
16package org.onosproject.reactive.routing;
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070017
Pingping Line28ae4c2015-03-13 11:37:03 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Pingping Linc9e16bf2015-04-10 14:42:41 -070023import org.onlab.packet.ARP;
Jonathan Hart3217d1b2015-06-30 16:08:43 -070024import org.onlab.packet.EthType;
Pingping Line28ae4c2015-03-13 11:37:03 -070025import org.onlab.packet.Ethernet;
26import org.onlab.packet.IPv4;
Pingping Linc9e16bf2015-04-10 14:42:41 -070027import org.onlab.packet.Ip4Address;
Pingping Line28ae4c2015-03-13 11:37:03 -070028import org.onlab.packet.IpAddress;
29import org.onlab.packet.MacAddress;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.packet.DefaultOutboundPacket;
38import org.onosproject.net.packet.InboundPacket;
39import org.onosproject.net.packet.OutboundPacket;
40import org.onosproject.net.packet.PacketContext;
Pingping Line28ae4c2015-03-13 11:37:03 -070041import org.onosproject.net.packet.PacketProcessor;
42import org.onosproject.net.packet.PacketService;
43import org.onosproject.routing.RoutingService;
Pingping Linc9e16bf2015-04-10 14:42:41 -070044import org.onosproject.routing.config.RoutingConfigurationService;
Pingping Line28ae4c2015-03-13 11:37:03 -070045import org.slf4j.Logger;
46
Jonathan Hart3217d1b2015-06-30 16:08:43 -070047import java.nio.ByteBuffer;
48
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070049import static org.onlab.packet.Ethernet.TYPE_ARP;
50import static org.onlab.packet.Ethernet.TYPE_IPV4;
51import static org.onosproject.net.packet.PacketPriority.REACTIVE;
Jonathan Hart3217d1b2015-06-30 16:08:43 -070052import static org.slf4j.LoggerFactory.getLogger;
53
Pingping Line28ae4c2015-03-13 11:37:03 -070054/**
55 * This is reactive routing to handle 3 cases:
56 * (1) one host wants to talk to another host, both two hosts are in
57 * SDN network.
58 * (2) one host in SDN network wants to talk to another host in Internet.
59 * (3) one host from Internet wants to talk to another host in SDN network.
60 */
61@Component(immediate = true)
62public class SdnIpReactiveRouting {
63
64 private static final String APP_NAME = "org.onosproject.reactive.routing";
65 private final Logger log = getLogger(getClass());
66
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected CoreService coreService;
69
70 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 protected PacketService packetService;
72
73 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
74 protected RoutingService routingService;
75
Pingping Linc9e16bf2015-04-10 14:42:41 -070076 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected RoutingConfigurationService config;
78
Pingping Line28ae4c2015-03-13 11:37:03 -070079 private ApplicationId appId;
80
81 private ReactiveRoutingProcessor processor =
82 new ReactiveRoutingProcessor();
83
84 @Activate
85 public void activate() {
86 appId = coreService.registerApplication(APP_NAME);
Thomas Vachuskac19d8292015-07-06 14:11:34 -070087 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070088 requestIntercepts();
Pingping Line28ae4c2015-03-13 11:37:03 -070089 log.info("SDN-IP Reactive Routing Started");
90 }
91
92 @Deactivate
93 public void deactivate() {
Aaron Kruglikov07a923d2015-07-03 13:30:57 -070094 withdrawIntercepts();
Pingping Line28ae4c2015-03-13 11:37:03 -070095 packetService.removeProcessor(processor);
96 processor = null;
97 log.info("SDN-IP Reactive Routing Stopped");
98 }
99
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700100 /**
101 * Request packet in via the PacketService.
102 */
103 private void requestIntercepts() {
104 //TODO: to support IPv6 later
105 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
106 selector.matchEthType(TYPE_IPV4);
Thomas Vachuskac19d8292015-07-06 14:11:34 -0700107 packetService.requestPackets(selector.build(), REACTIVE, appId);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700108 selector.matchEthType(TYPE_ARP);
Thomas Vachuskac19d8292015-07-06 14:11:34 -0700109 packetService.requestPackets(selector.build(), REACTIVE, appId);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700110 }
111
112 /**
113 * Cancel request for packet in via PacketService.
114 */
115 private void withdrawIntercepts() {
116 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
117 selector.matchEthType(TYPE_IPV4);
Thomas Vachuskac19d8292015-07-06 14:11:34 -0700118 packetService.cancelPackets(selector.build(), REACTIVE, appId);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700119 selector = DefaultTrafficSelector.builder();
120 selector.matchEthType(TYPE_ARP);
Thomas Vachuskac19d8292015-07-06 14:11:34 -0700121 packetService.cancelPackets(selector.build(), REACTIVE, appId);
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700122 }
123
Pingping Line28ae4c2015-03-13 11:37:03 -0700124 private class ReactiveRoutingProcessor implements PacketProcessor {
125 @Override
126 public void process(PacketContext context) {
127
128 InboundPacket pkt = context.inPacket();
129 Ethernet ethPkt = pkt.parsed();
130 if (ethPkt == null) {
131 return;
132 }
Pingping Line28ae4c2015-03-13 11:37:03 -0700133 ConnectPoint srcConnectPoint = pkt.receivedFrom();
Pingping Line28ae4c2015-03-13 11:37:03 -0700134
Jonathan Hart3217d1b2015-06-30 16:08:43 -0700135 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
136 case ARP:
Pingping Linc9e16bf2015-04-10 14:42:41 -0700137 ARP arpPacket = (ARP) ethPkt.getPayload();
138 Ip4Address targetIpAddress = Ip4Address
139 .valueOf(arpPacket.getTargetProtocolAddress());
140 // Only when it is an ARP request packet and the target IP
141 // address is a virtual gateway IP address, then it will be
142 // processed.
143 if (arpPacket.getOpCode() == ARP.OP_REQUEST
144 && config.isVirtualGatewayIpAddress(targetIpAddress)) {
145 MacAddress gatewayMacAddress =
146 config.getVirtualGatewayMacAddress();
147 if (gatewayMacAddress == null) {
148 break;
149 }
150 Ethernet eth = ARP.buildArpReply(targetIpAddress,
151 gatewayMacAddress,
152 ethPkt);
153
154 TrafficTreatment.Builder builder =
155 DefaultTrafficTreatment.builder();
156 builder.setOutput(srcConnectPoint.port());
157 packetService.emit(new DefaultOutboundPacket(
158 srcConnectPoint.deviceId(),
159 builder.build(),
160 ByteBuffer.wrap(eth.serialize())));
161 }
162 break;
Jonathan Hart3217d1b2015-06-30 16:08:43 -0700163 case IPV4:
Pingping Linc9e16bf2015-04-10 14:42:41 -0700164 // Parse packet
165 IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
166 IpAddress dstIp =
167 IpAddress.valueOf(ipv4Packet.getDestinationAddress());
168 IpAddress srcIp =
169 IpAddress.valueOf(ipv4Packet.getSourceAddress());
170 MacAddress srcMac = ethPkt.getSourceMAC();
171 routingService.packetReactiveProcessor(dstIp, srcIp,
172 srcConnectPoint, srcMac);
173
174 // TODO emit packet first or packetReactiveProcessor first
175 ConnectPoint egressConnectPoint = null;
176 egressConnectPoint = routingService.getEgressConnectPoint(dstIp);
177 if (egressConnectPoint != null) {
178 forwardPacketToDst(context, egressConnectPoint);
179 }
180 break;
181 default:
182 break;
Pingping Line28ae4c2015-03-13 11:37:03 -0700183 }
184 }
185 }
186
187 /**
188 * Emits the specified packet onto the network.
189 *
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700190 * @param context the packet context
Pingping Line28ae4c2015-03-13 11:37:03 -0700191 * @param connectPoint the connect point where the packet should be
Aaron Kruglikov07a923d2015-07-03 13:30:57 -0700192 * sent out
Pingping Line28ae4c2015-03-13 11:37:03 -0700193 */
194 private void forwardPacketToDst(PacketContext context,
195 ConnectPoint connectPoint) {
196 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
197 .setOutput(connectPoint.port()).build();
198 OutboundPacket packet =
199 new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
200 context.inPacket().unparsed());
201 packetService.emit(packet);
202 log.trace("sending packet: {}", packet);
203 }
204
205}
206