ad78a1ce6bd6b688cf65358ce59524ec63586dcc
[onosfw.git] /
1 /*
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  */
16 package org.onosproject.reactive.routing;
17
18 import org.apache.felix.scr.annotations.Activate;
19 import org.apache.felix.scr.annotations.Component;
20 import org.apache.felix.scr.annotations.Deactivate;
21 import org.apache.felix.scr.annotations.Reference;
22 import org.apache.felix.scr.annotations.ReferenceCardinality;
23 import org.onlab.packet.ARP;
24 import org.onlab.packet.EthType;
25 import org.onlab.packet.Ethernet;
26 import org.onlab.packet.IPv4;
27 import org.onlab.packet.Ip4Address;
28 import org.onlab.packet.IpAddress;
29 import org.onlab.packet.MacAddress;
30 import org.onosproject.core.ApplicationId;
31 import org.onosproject.core.CoreService;
32 import org.onosproject.net.ConnectPoint;
33 import org.onosproject.net.flow.DefaultTrafficSelector;
34 import org.onosproject.net.flow.DefaultTrafficTreatment;
35 import org.onosproject.net.flow.TrafficSelector;
36 import org.onosproject.net.flow.TrafficTreatment;
37 import org.onosproject.net.packet.DefaultOutboundPacket;
38 import org.onosproject.net.packet.InboundPacket;
39 import org.onosproject.net.packet.OutboundPacket;
40 import org.onosproject.net.packet.PacketContext;
41 import org.onosproject.net.packet.PacketProcessor;
42 import org.onosproject.net.packet.PacketService;
43 import org.onosproject.routing.RoutingService;
44 import org.onosproject.routing.config.RoutingConfigurationService;
45 import org.slf4j.Logger;
46
47 import java.nio.ByteBuffer;
48
49 import static org.onlab.packet.Ethernet.TYPE_ARP;
50 import static org.onlab.packet.Ethernet.TYPE_IPV4;
51 import static org.onosproject.net.packet.PacketPriority.REACTIVE;
52 import static org.slf4j.LoggerFactory.getLogger;
53
54 /**
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)
62 public 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
76     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77     protected RoutingConfigurationService config;
78
79     private ApplicationId appId;
80
81     private ReactiveRoutingProcessor processor =
82             new ReactiveRoutingProcessor();
83
84     @Activate
85     public void activate() {
86         appId = coreService.registerApplication(APP_NAME);
87         packetService.addProcessor(processor, PacketProcessor.director(2));
88         requestIntercepts();
89         log.info("SDN-IP Reactive Routing Started");
90     }
91
92     @Deactivate
93     public void deactivate() {
94         withdrawIntercepts();
95         packetService.removeProcessor(processor);
96         processor = null;
97         log.info("SDN-IP Reactive Routing Stopped");
98     }
99
100     /**
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);
107         packetService.requestPackets(selector.build(), REACTIVE, appId);
108         selector.matchEthType(TYPE_ARP);
109         packetService.requestPackets(selector.build(), REACTIVE, appId);
110     }
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);
118         packetService.cancelPackets(selector.build(), REACTIVE, appId);
119         selector = DefaultTrafficSelector.builder();
120         selector.matchEthType(TYPE_ARP);
121         packetService.cancelPackets(selector.build(), REACTIVE, appId);
122     }
123
124     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             }
133             ConnectPoint srcConnectPoint = pkt.receivedFrom();
134
135             switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
136             case ARP:
137                 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;
163             case IPV4:
164                 // 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;
183             }
184         }
185     }
186
187     /**
188      * Emits the specified packet onto the network.
189      *
190      * @param context      the packet context
191      * @param connectPoint the connect point where the packet should be
192      *                     sent out
193      */
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