blob: c445ac487299d8d7d380ed563c613cbbd7c02a08 [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sangho80f11cb2015-04-01 13:05:26 -07003 *
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.segmentrouting;
17
18import org.onlab.packet.Ethernet;
Pier Ventreb6b81d52016-12-02 08:16:05 -080019import org.onlab.packet.IP;
sangho80f11cb2015-04-01 13:05:26 -070020import org.onlab.packet.IPv4;
Pier Ventreb6b81d52016-12-02 08:16:05 -080021import org.onlab.packet.IPv6;
sangho80f11cb2015-04-01 13:05:26 -070022import org.onlab.packet.Ip4Address;
Pier Ventre1a655962016-11-28 16:48:06 -080023import org.onlab.packet.Ip6Address;
Pier Ventreb6b81d52016-12-02 08:16:05 -080024import org.onlab.packet.IpAddress;
sangho80f11cb2015-04-01 13:05:26 -070025import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.Host;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficTreatment;
30import org.onosproject.net.packet.DefaultOutboundPacket;
sangho80f11cb2015-04-01 13:05:26 -070031import org.onosproject.net.packet.OutboundPacket;
Charles Chan319d1a22015-11-03 10:42:14 -080032import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
33import org.onosproject.segmentrouting.config.DeviceConfiguration;
sangho80f11cb2015-04-01 13:05:26 -070034import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
37import java.nio.ByteBuffer;
38import java.util.concurrent.ConcurrentHashMap;
39import java.util.concurrent.ConcurrentLinkedQueue;
40
41import static com.google.common.base.Preconditions.checkNotNull;
Pier Ventreb6b81d52016-12-02 08:16:05 -080042import static org.onlab.packet.IpAddress.Version.INET6;
sangho80f11cb2015-04-01 13:05:26 -070043
Charles Chanb7f75ac2016-01-11 18:28:54 -080044/**
45 * Handler of IP packets that forwards IP packets that are sent to the controller,
46 * except the ICMP packets which are processed by @link{IcmpHandler}.
47 */
sangho80f11cb2015-04-01 13:05:26 -070048public class IpHandler {
49
50 private static Logger log = LoggerFactory.getLogger(IpHandler.class);
51 private SegmentRoutingManager srManager;
sangho9b169e32015-04-14 16:27:13 -070052 private DeviceConfiguration config;
Pier Ventreb6b81d52016-12-02 08:16:05 -080053 private ConcurrentHashMap<IpAddress, ConcurrentLinkedQueue<IP>> ipPacketQueue;
sangho80f11cb2015-04-01 13:05:26 -070054
55 /**
56 * Creates an IpHandler object.
57 *
58 * @param srManager SegmentRoutingManager object
59 */
60 public IpHandler(SegmentRoutingManager srManager) {
61 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -070062 this.config = checkNotNull(srManager.deviceConfiguration);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070063 ipPacketQueue = new ConcurrentHashMap<>();
sangho80f11cb2015-04-01 13:05:26 -070064 }
65
66 /**
Pier Ventreb6b81d52016-12-02 08:16:05 -080067 * Enqueues the packet using the destination address as key.
68 *
69 * @param ipPacket the ip packet to store
70 * @param destinationAddress the destination address
71 */
72 private void enqueuePacket(IP ipPacket, IpAddress destinationAddress) {
73
74 ipPacketQueue
75 .computeIfAbsent(destinationAddress, a -> new ConcurrentLinkedQueue<>())
76 .add(ipPacket);
77
78 }
79
80 /**
81 * Dequeues the packet using the destination address as key.
82 *
83 * @param ipPacket the ip packet to remove
84 * @param destinationAddress the destination address
85 */
86 public void dequeuePacket(IP ipPacket, IpAddress destinationAddress) {
87
88 if (ipPacketQueue.get(destinationAddress) == null) {
89 return;
90 }
91 ipPacketQueue.get(destinationAddress).remove(ipPacket);
92 }
93
94 /**
95 * Forwards the packet to a given host and deque the packet.
96 *
97 * @param deviceId the target device
98 * @param eth the packet to send
99 * @param dest the target host
100 */
101 private void forwardToHost(DeviceId deviceId, Ethernet eth, Host dest) {
102 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
103 setOutput(dest.location().port()).build();
104 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
105 treatment, ByteBuffer.wrap(eth.serialize()));
106 srManager.packetService.emit(packet);
107 }
108
109 //////////////////////
110 // IPv4 Handling //
111 ////////////////////
112
113 /**
sangho80f11cb2015-04-01 13:05:26 -0700114 * Processes incoming IP packets.
115 *
116 * If it is an IP packet for known host, then forward it to the host.
117 * If it is an IP packet for unknown host in subnet, then send an ARP request
118 * to the subnet.
119 *
120 * @param pkt incoming packet
Pier Ventreb6b81d52016-12-02 08:16:05 -0800121 * @param connectPoint the target device
sangho80f11cb2015-04-01 13:05:26 -0700122 */
Pier Ventreb6b81d52016-12-02 08:16:05 -0800123 public void processPacketIn(IPv4 pkt, ConnectPoint connectPoint) {
sangho80f11cb2015-04-01 13:05:26 -0700124
sangho80f11cb2015-04-01 13:05:26 -0700125 DeviceId deviceId = connectPoint.deviceId();
Pier Ventreb6b81d52016-12-02 08:16:05 -0800126 Ip4Address destinationAddress = Ip4Address.valueOf(pkt.getDestinationAddress());
sangho80f11cb2015-04-01 13:05:26 -0700127
128 // IP packet for know hosts
129 if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
130 forwardPackets(deviceId, destinationAddress);
131
Pier Ventreb6b81d52016-12-02 08:16:05 -0800132 // IP packet for unknown host in one of the configured subnets of the router
sangho80f11cb2015-04-01 13:05:26 -0700133 } else if (config.inSameSubnet(deviceId, destinationAddress)) {
134 srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint);
135
136 // IP packets for unknown host
137 } else {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800138 log.debug("IPv4 packet for unknown host {} which is not in the subnet",
sangho80f11cb2015-04-01 13:05:26 -0700139 destinationAddress);
140 // Do nothing
141 }
142 }
143
144 /**
145 * Adds the IP packet to a buffer.
146 * The packets are forwarded to corresponding destination when the destination
147 * MAC address is known via ARP response.
148 *
149 * @param ipPacket IP packet to add to the buffer
150 */
151 public void addToPacketBuffer(IPv4 ipPacket) {
152
Saurav Das2d94d312015-11-24 23:21:05 -0800153 // Better not buffer TCP packets due to out-of-order packet transfer
sangho80f11cb2015-04-01 13:05:26 -0700154 if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
155 return;
156 }
Pier Ventreb6b81d52016-12-02 08:16:05 -0800157 IpAddress destIpAddress = IpAddress.valueOf(ipPacket.getDestinationAddress());
158 enqueuePacket(ipPacket, destIpAddress);
sangho80f11cb2015-04-01 13:05:26 -0700159 }
160
161 /**
162 * Forwards IP packets in the buffer to the destination IP address.
163 * It is called when the controller finds the destination MAC address
Saurav Das88979182015-10-19 14:37:36 -0700164 * via ARP responses.
sangho80f11cb2015-04-01 13:05:26 -0700165 *
166 * @param deviceId switch device ID
167 * @param destIpAddress destination IP address
168 */
169 public void forwardPackets(DeviceId deviceId, Ip4Address destIpAddress) {
Srikanth Vavilapallic56a2f32015-06-05 11:40:14 -0700170 if (ipPacketQueue.get(destIpAddress) == null) {
171 return;
172 }
Pier Ventreb6b81d52016-12-02 08:16:05 -0800173 for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
174 if (ipPacket.getVersion() == ((byte) 4)) {
175 IPv4 ipv4Packet = (IPv4) ipPacket;
176 Ip4Address destAddress = Ip4Address.valueOf(ipv4Packet.getDestinationAddress());
177 if (config.inSameSubnet(deviceId, destAddress)) {
178 ipv4Packet.setTtl((byte) (ipv4Packet.getTtl() - 1));
179 ipv4Packet.setChecksum((short) 0);
180 for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
181 Ethernet eth = new Ethernet();
182 eth.setDestinationMACAddress(dest.mac());
183 try {
184 eth.setSourceMACAddress(config.getDeviceMac(deviceId));
185 } catch (DeviceConfigNotFoundException e) {
186 log.warn(e.getMessage()
187 + " Skipping forwardPackets for this destination.");
188 continue;
189 }
190 eth.setEtherType(Ethernet.TYPE_IPV4);
191 eth.setPayload(ipv4Packet);
192 forwardToHost(deviceId, eth, dest);
193 ipPacketQueue.get(destIpAddress).remove(ipPacket);
Charles Chan319d1a22015-11-03 10:42:14 -0800194 }
sanghofb7c7292015-04-13 15:15:58 -0700195 ipPacketQueue.get(destIpAddress).remove(ipPacket);
sangho80f11cb2015-04-01 13:05:26 -0700196 }
197 }
198 }
199 }
sangho9b169e32015-04-14 16:27:13 -0700200
Pier Ventre1a655962016-11-28 16:48:06 -0800201 //////////////////////
202 // IPv6 Handling //
203 ////////////////////
204
205 /**
Pier Ventreb6b81d52016-12-02 08:16:05 -0800206 * Processes incoming IPv6 packets.
207 *
208 * If it is an IPv6 packet for known host, then forward it to the host.
209 * If it is an IPv6 packet for unknown host in subnet, then send an NDP request
210 * to the subnet.
211 *
212 * @param pkt incoming packet
213 * @param connectPoint the target device
214 */
215 public void processPacketIn(IPv6 pkt, ConnectPoint connectPoint) {
216
217 DeviceId deviceId = connectPoint.deviceId();
218 Ip6Address destinationAddress = Ip6Address.valueOf(pkt.getDestinationAddress());
219
220 // IPv6 packet for know hosts
221 if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
222 forwardPackets(deviceId, destinationAddress);
223
224 // IPv6 packet for unknown host in one of the configured subnets of the router
225 } else if (config.inSameSubnet(deviceId, destinationAddress)) {
226 srManager.icmpHandler.sendNdpRequest(deviceId, destinationAddress, connectPoint);
227
228 // IPv6 packets for unknown host
229 } else {
230 log.debug("IPv6 packet for unknown host {} which is not in the subnet",
231 destinationAddress);
232 }
233 }
234
235 /**
236 * Adds the IPv6 packet to a buffer.
237 * The packets are forwarded to corresponding destination when the destination
238 * MAC address is known via NDP response.
239 *
240 * @param ipPacket IP packet to add to the buffer
241 */
242 public void addToPacketBuffer(IPv6 ipPacket) {
243
244 // Better not buffer TCP packets due to out-of-order packet transfer
245 if (ipPacket.getNextHeader() == IPv6.PROTOCOL_TCP) {
246 return;
247 }
248 IpAddress destIpAddress = IpAddress.valueOf(INET6, ipPacket.getDestinationAddress());
249 enqueuePacket(ipPacket, destIpAddress);
250 }
251
252 /**
Pier Ventre1a655962016-11-28 16:48:06 -0800253 * Forwards IP packets in the buffer to the destination IP address.
254 * It is called when the controller finds the destination MAC address
255 * via NDP replies.
256 *
257 * @param deviceId the target device
258 * @param destIpAddress the destination ip address
259 */
260 public void forwardPackets(DeviceId deviceId, Ip6Address destIpAddress) {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800261 if (ipPacketQueue.get(destIpAddress) == null) {
262 return;
263 }
264 for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
265 if (ipPacket.getVersion() == ((byte) 6)) {
266 IPv6 ipv6Packet = (IPv6) ipPacket;
267 Ip6Address destAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
268 if (config.inSameSubnet(deviceId, destAddress)) {
269 ipv6Packet.setHopLimit((byte) (ipv6Packet.getHopLimit() - 1));
270 for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
271 Ethernet eth = new Ethernet();
272 eth.setDestinationMACAddress(dest.mac());
273 try {
274 eth.setSourceMACAddress(config.getDeviceMac(deviceId));
275 } catch (DeviceConfigNotFoundException e) {
276 log.warn(e.getMessage()
277 + " Skipping forwardPackets for this destination.");
278 continue;
279 }
280 eth.setEtherType(Ethernet.TYPE_IPV6);
281 eth.setPayload(ipv6Packet);
282 forwardToHost(deviceId, eth, dest);
283 ipPacketQueue.get(destIpAddress).remove(ipPacket);
284 }
285 ipPacketQueue.get(destIpAddress).remove(ipPacket);
286 }
287 }
288 ipPacketQueue.get(destIpAddress).remove(ipPacket);
289 }
Pier Ventre1a655962016-11-28 16:48:06 -0800290 }
291
sangho80f11cb2015-04-01 13:05:26 -0700292}