blob: c1f77b7ee3555cf68bba2942b906b1e9ddc899c6 [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;
sangho80f11cb2015-04-01 13:05:26 -070033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
36import java.nio.ByteBuffer;
37import java.util.concurrent.ConcurrentHashMap;
38import java.util.concurrent.ConcurrentLinkedQueue;
39
40import static com.google.common.base.Preconditions.checkNotNull;
Pier Ventreb6b81d52016-12-02 08:16:05 -080041import static org.onlab.packet.IpAddress.Version.INET6;
sangho80f11cb2015-04-01 13:05:26 -070042
Charles Chanb7f75ac2016-01-11 18:28:54 -080043/**
44 * Handler of IP packets that forwards IP packets that are sent to the controller,
45 * except the ICMP packets which are processed by @link{IcmpHandler}.
46 */
sangho80f11cb2015-04-01 13:05:26 -070047public class IpHandler {
48
49 private static Logger log = LoggerFactory.getLogger(IpHandler.class);
50 private SegmentRoutingManager srManager;
sangho9b169e32015-04-14 16:27:13 -070051 private DeviceConfiguration config;
Pier Ventreb6b81d52016-12-02 08:16:05 -080052 private ConcurrentHashMap<IpAddress, ConcurrentLinkedQueue<IP>> ipPacketQueue;
sangho80f11cb2015-04-01 13:05:26 -070053
54 /**
55 * Creates an IpHandler object.
56 *
57 * @param srManager SegmentRoutingManager object
58 */
59 public IpHandler(SegmentRoutingManager srManager) {
60 this.srManager = srManager;
sangho9b169e32015-04-14 16:27:13 -070061 this.config = checkNotNull(srManager.deviceConfiguration);
Sho SHIMIZU47b8aa22015-09-11 11:19:11 -070062 ipPacketQueue = new ConcurrentHashMap<>();
sangho80f11cb2015-04-01 13:05:26 -070063 }
64
65 /**
Pier Ventreb6b81d52016-12-02 08:16:05 -080066 * Enqueues the packet using the destination address as key.
67 *
68 * @param ipPacket the ip packet to store
69 * @param destinationAddress the destination address
70 */
71 private void enqueuePacket(IP ipPacket, IpAddress destinationAddress) {
72
73 ipPacketQueue
74 .computeIfAbsent(destinationAddress, a -> new ConcurrentLinkedQueue<>())
75 .add(ipPacket);
76
77 }
78
79 /**
80 * Dequeues the packet using the destination address as key.
81 *
82 * @param ipPacket the ip packet to remove
83 * @param destinationAddress the destination address
84 */
85 public void dequeuePacket(IP ipPacket, IpAddress destinationAddress) {
86
87 if (ipPacketQueue.get(destinationAddress) == null) {
88 return;
89 }
90 ipPacketQueue.get(destinationAddress).remove(ipPacket);
91 }
92
93 /**
94 * Forwards the packet to a given host and deque the packet.
95 *
96 * @param deviceId the target device
97 * @param eth the packet to send
98 * @param dest the target host
99 */
100 private void forwardToHost(DeviceId deviceId, Ethernet eth, Host dest) {
101 TrafficTreatment treatment = DefaultTrafficTreatment.builder().
102 setOutput(dest.location().port()).build();
103 OutboundPacket packet = new DefaultOutboundPacket(deviceId,
104 treatment, ByteBuffer.wrap(eth.serialize()));
105 srManager.packetService.emit(packet);
106 }
107
108 //////////////////////
109 // IPv4 Handling //
110 ////////////////////
111
112 /**
sangho80f11cb2015-04-01 13:05:26 -0700113 * Processes incoming IP packets.
114 *
115 * If it is an IP packet for known host, then forward it to the host.
116 * If it is an IP packet for unknown host in subnet, then send an ARP request
117 * to the subnet.
118 *
119 * @param pkt incoming packet
Pier Ventreb6b81d52016-12-02 08:16:05 -0800120 * @param connectPoint the target device
sangho80f11cb2015-04-01 13:05:26 -0700121 */
Pier Ventreb6b81d52016-12-02 08:16:05 -0800122 public void processPacketIn(IPv4 pkt, ConnectPoint connectPoint) {
sangho80f11cb2015-04-01 13:05:26 -0700123
sangho80f11cb2015-04-01 13:05:26 -0700124 DeviceId deviceId = connectPoint.deviceId();
Pier Ventreb6b81d52016-12-02 08:16:05 -0800125 Ip4Address destinationAddress = Ip4Address.valueOf(pkt.getDestinationAddress());
sangho80f11cb2015-04-01 13:05:26 -0700126
127 // IP packet for know hosts
128 if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
129 forwardPackets(deviceId, destinationAddress);
130
Pier Ventreb6b81d52016-12-02 08:16:05 -0800131 // IP packet for unknown host in one of the configured subnets of the router
sangho80f11cb2015-04-01 13:05:26 -0700132 } else if (config.inSameSubnet(deviceId, destinationAddress)) {
133 srManager.arpHandler.sendArpRequest(deviceId, destinationAddress, connectPoint);
134
135 // IP packets for unknown host
136 } else {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800137 log.debug("IPv4 packet for unknown host {} which is not in the subnet",
sangho80f11cb2015-04-01 13:05:26 -0700138 destinationAddress);
139 // Do nothing
140 }
141 }
142
143 /**
144 * Adds the IP packet to a buffer.
145 * The packets are forwarded to corresponding destination when the destination
146 * MAC address is known via ARP response.
147 *
148 * @param ipPacket IP packet to add to the buffer
149 */
150 public void addToPacketBuffer(IPv4 ipPacket) {
151
Saurav Das2d94d312015-11-24 23:21:05 -0800152 // Better not buffer TCP packets due to out-of-order packet transfer
sangho80f11cb2015-04-01 13:05:26 -0700153 if (ipPacket.getProtocol() == IPv4.PROTOCOL_TCP) {
154 return;
155 }
Pier Ventreb6b81d52016-12-02 08:16:05 -0800156 IpAddress destIpAddress = IpAddress.valueOf(ipPacket.getDestinationAddress());
157 enqueuePacket(ipPacket, destIpAddress);
sangho80f11cb2015-04-01 13:05:26 -0700158 }
159
160 /**
161 * Forwards IP packets in the buffer to the destination IP address.
162 * It is called when the controller finds the destination MAC address
Saurav Das88979182015-10-19 14:37:36 -0700163 * via ARP responses.
sangho80f11cb2015-04-01 13:05:26 -0700164 *
165 * @param deviceId switch device ID
166 * @param destIpAddress destination IP address
167 */
168 public void forwardPackets(DeviceId deviceId, Ip4Address destIpAddress) {
Srikanth Vavilapallic56a2f32015-06-05 11:40:14 -0700169 if (ipPacketQueue.get(destIpAddress) == null) {
170 return;
171 }
Pier Ventreb6b81d52016-12-02 08:16:05 -0800172 for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
173 if (ipPacket.getVersion() == ((byte) 4)) {
174 IPv4 ipv4Packet = (IPv4) ipPacket;
175 Ip4Address destAddress = Ip4Address.valueOf(ipv4Packet.getDestinationAddress());
176 if (config.inSameSubnet(deviceId, destAddress)) {
177 ipv4Packet.setTtl((byte) (ipv4Packet.getTtl() - 1));
178 ipv4Packet.setChecksum((short) 0);
179 for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
180 Ethernet eth = new Ethernet();
181 eth.setDestinationMACAddress(dest.mac());
182 try {
183 eth.setSourceMACAddress(config.getDeviceMac(deviceId));
184 } catch (DeviceConfigNotFoundException e) {
185 log.warn(e.getMessage()
186 + " Skipping forwardPackets for this destination.");
187 continue;
188 }
189 eth.setEtherType(Ethernet.TYPE_IPV4);
190 eth.setPayload(ipv4Packet);
191 forwardToHost(deviceId, eth, dest);
192 ipPacketQueue.get(destIpAddress).remove(ipPacket);
Charles Chan319d1a22015-11-03 10:42:14 -0800193 }
sanghofb7c7292015-04-13 15:15:58 -0700194 ipPacketQueue.get(destIpAddress).remove(ipPacket);
sangho80f11cb2015-04-01 13:05:26 -0700195 }
196 }
197 }
198 }
sangho9b169e32015-04-14 16:27:13 -0700199
Pier Ventre1a655962016-11-28 16:48:06 -0800200 //////////////////////
201 // IPv6 Handling //
202 ////////////////////
203
204 /**
Pier Ventreb6b81d52016-12-02 08:16:05 -0800205 * Processes incoming IPv6 packets.
206 *
207 * If it is an IPv6 packet for known host, then forward it to the host.
208 * If it is an IPv6 packet for unknown host in subnet, then send an NDP request
209 * to the subnet.
210 *
211 * @param pkt incoming packet
212 * @param connectPoint the target device
213 */
214 public void processPacketIn(IPv6 pkt, ConnectPoint connectPoint) {
215
216 DeviceId deviceId = connectPoint.deviceId();
217 Ip6Address destinationAddress = Ip6Address.valueOf(pkt.getDestinationAddress());
218
219 // IPv6 packet for know hosts
220 if (!srManager.hostService.getHostsByIp(destinationAddress).isEmpty()) {
221 forwardPackets(deviceId, destinationAddress);
222
223 // IPv6 packet for unknown host in one of the configured subnets of the router
224 } else if (config.inSameSubnet(deviceId, destinationAddress)) {
225 srManager.icmpHandler.sendNdpRequest(deviceId, destinationAddress, connectPoint);
226
227 // IPv6 packets for unknown host
228 } else {
229 log.debug("IPv6 packet for unknown host {} which is not in the subnet",
230 destinationAddress);
231 }
232 }
233
234 /**
235 * Adds the IPv6 packet to a buffer.
236 * The packets are forwarded to corresponding destination when the destination
237 * MAC address is known via NDP response.
238 *
239 * @param ipPacket IP packet to add to the buffer
240 */
241 public void addToPacketBuffer(IPv6 ipPacket) {
242
243 // Better not buffer TCP packets due to out-of-order packet transfer
244 if (ipPacket.getNextHeader() == IPv6.PROTOCOL_TCP) {
245 return;
246 }
247 IpAddress destIpAddress = IpAddress.valueOf(INET6, ipPacket.getDestinationAddress());
248 enqueuePacket(ipPacket, destIpAddress);
249 }
250
251 /**
Pier Ventre1a655962016-11-28 16:48:06 -0800252 * Forwards IP packets in the buffer to the destination IP address.
253 * It is called when the controller finds the destination MAC address
254 * via NDP replies.
255 *
256 * @param deviceId the target device
257 * @param destIpAddress the destination ip address
258 */
259 public void forwardPackets(DeviceId deviceId, Ip6Address destIpAddress) {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800260 if (ipPacketQueue.get(destIpAddress) == null) {
261 return;
262 }
263 for (IP ipPacket : ipPacketQueue.get(destIpAddress)) {
264 if (ipPacket.getVersion() == ((byte) 6)) {
265 IPv6 ipv6Packet = (IPv6) ipPacket;
266 Ip6Address destAddress = Ip6Address.valueOf(ipv6Packet.getDestinationAddress());
267 if (config.inSameSubnet(deviceId, destAddress)) {
268 ipv6Packet.setHopLimit((byte) (ipv6Packet.getHopLimit() - 1));
269 for (Host dest : srManager.hostService.getHostsByIp(destIpAddress)) {
270 Ethernet eth = new Ethernet();
271 eth.setDestinationMACAddress(dest.mac());
272 try {
273 eth.setSourceMACAddress(config.getDeviceMac(deviceId));
274 } catch (DeviceConfigNotFoundException e) {
275 log.warn(e.getMessage()
276 + " Skipping forwardPackets for this destination.");
277 continue;
278 }
279 eth.setEtherType(Ethernet.TYPE_IPV6);
280 eth.setPayload(ipv6Packet);
281 forwardToHost(deviceId, eth, dest);
282 ipPacketQueue.get(destIpAddress).remove(ipPacket);
283 }
284 ipPacketQueue.get(destIpAddress).remove(ipPacket);
285 }
286 }
287 ipPacketQueue.get(destIpAddress).remove(ipPacket);
288 }
Pier Ventre1a655962016-11-28 16:48:06 -0800289 }
290
sangho80f11cb2015-04-01 13:05:26 -0700291}