blob: cfef0f13a29ce28ce287e240c24a316245cc3de7 [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
sanghob35a6192015-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.ARP;
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
Pier Ventre10bd8d12016-11-26 21:05:22 -080022import org.onlab.packet.IpPrefix;
sanghob35a6192015-04-01 13:05:26 -070023import org.onlab.packet.MacAddress;
Charles Chan68aa62d2015-11-09 16:37:23 -080024import org.onlab.packet.VlanId;
Ray Milkeyb65d7842017-08-03 16:28:24 -070025import org.onosproject.net.neighbour.NeighbourMessageContext;
sanghob35a6192015-04-01 13:05:26 -070026import org.onosproject.net.ConnectPoint;
27import org.onosproject.net.DeviceId;
Pier Ventre10bd8d12016-11-26 21:05:22 -080028import org.onosproject.net.host.HostService;
Charles Chan0b4e6182015-11-03 10:42:14 -080029import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Charles Chan03a73e02016-10-24 14:52:01 -070030import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
sanghob35a6192015-04-01 13:05:26 -070031import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33
Saurav Das837e0bb2015-10-30 17:45:38 -070034import java.util.Set;
Pier Ventre10bd8d12016-11-26 21:05:22 -080035import java.util.stream.Collectors;
Saurav Das837e0bb2015-10-30 17:45:38 -070036
Ray Milkeyb65d7842017-08-03 16:28:24 -070037import static org.onosproject.net.neighbour.NeighbourMessageType.REQUEST;
sanghob35a6192015-04-01 13:05:26 -070038
Charles Chane849c192016-01-11 18:28:54 -080039/**
40 * Handler of ARP packets that responses or forwards ARP packets that
41 * are sent to the controller.
42 */
Pier Ventre735b8c82016-12-02 08:16:05 -080043public class ArpHandler extends SegmentRoutingNeighbourHandler {
sanghob35a6192015-04-01 13:05:26 -070044
45 private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
46
sanghob35a6192015-04-01 13:05:26 -070047 /**
48 * Creates an ArpHandler object.
49 *
50 * @param srManager SegmentRoutingManager object
51 */
52 public ArpHandler(SegmentRoutingManager srManager) {
Pier Ventre735b8c82016-12-02 08:16:05 -080053 super(srManager);
sanghob35a6192015-04-01 13:05:26 -070054 }
55
56 /**
57 * Processes incoming ARP packets.
Charles Chan68aa62d2015-11-09 16:37:23 -080058 *
sanghob35a6192015-04-01 13:05:26 -070059 * If it is an ARP request to router itself or known hosts,
60 * then it sends ARP response.
61 * If it is an ARP request to unknown hosts in its own subnet,
62 * then it flood the ARP request to the ports.
63 * If it is an ARP response, then set a flow rule for the host
64 * and forward any IP packets to the host in the packet buffer to the host.
Charles Chan68aa62d2015-11-09 16:37:23 -080065 * <p>
66 * Note: We handles all ARP packet in, even for those ARP packets between
67 * hosts in the same subnet.
68 * For an ARP packet with broadcast destination MAC,
69 * some switches pipelines will send it to the controller due to table miss,
Saurav Das49831642016-02-05 13:15:20 -080070 * other switches will flood the packets directly in the data plane without
Charles Chan68aa62d2015-11-09 16:37:23 -080071 * packet in.
72 * We can deal with both cases.
sanghob35a6192015-04-01 13:05:26 -070073 *
Pier Ventre10bd8d12016-11-26 21:05:22 -080074 * @param pkt incoming ARP packet and context information
75 * @param hostService the host service
sanghob35a6192015-04-01 13:05:26 -070076 */
Pier Ventre10bd8d12016-11-26 21:05:22 -080077 public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
Charles Chand2edd472016-10-17 18:03:37 -070078
Charles Chan03a73e02016-10-24 14:52:01 -070079 SegmentRoutingAppConfig appConfig = srManager.cfgService
80 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
Pier Ventre10bd8d12016-11-26 21:05:22 -080081 if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
Charles Chan03a73e02016-10-24 14:52:01 -070082 // Ignore ARP packets come from suppressed ports
Pier Ventref4b5fce2016-11-28 16:48:06 -080083 pkt.drop();
Charles Chan03a73e02016-10-24 14:52:01 -070084 return;
85 }
86
Pier Ventre10bd8d12016-11-26 21:05:22 -080087 if (!validateArpSpa(pkt)) {
Charles Chan505dfd82016-11-08 16:32:13 -080088 log.debug("Ignore ARP packet discovered on {} with unexpected src protocol address {}.",
Pier Ventre10bd8d12016-11-26 21:05:22 -080089 pkt.inPort(), pkt.sender().getIp4Address());
Pier Ventref4b5fce2016-11-28 16:48:06 -080090 pkt.drop();
Charles Chand2edd472016-10-17 18:03:37 -070091 return;
92 }
93
Pier Ventre10bd8d12016-11-26 21:05:22 -080094 if (pkt.type() == REQUEST) {
95 handleArpRequest(pkt, hostService);
sanghob35a6192015-04-01 13:05:26 -070096 } else {
Pier Ventre10bd8d12016-11-26 21:05:22 -080097 handleArpReply(pkt, hostService);
sanghob35a6192015-04-01 13:05:26 -070098 }
99 }
100
Pier Ventre10bd8d12016-11-26 21:05:22 -0800101 private void handleArpRequest(NeighbourMessageContext pkt, HostService hostService) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800102 // ARP request for router. Send ARP reply.
Pier Ventre10bd8d12016-11-26 21:05:22 -0800103 if (isArpForRouter(pkt)) {
104 MacAddress targetMac = config.getRouterMacForAGatewayIp(pkt.target().getIp4Address());
Charles Chane5e0c9a2018-03-30 12:11:34 -0700105 if (targetMac == null) {
106 log.warn("Router MAC of {} is not configured. Cannot handle ARP request from {}",
107 pkt.inPort().deviceId(), pkt.sender());
108 return;
109 }
Charles Chaneded6882018-06-29 14:28:39 -0700110 sendResponse(pkt, targetMac, hostService, true);
Charles Chaneb088e62015-10-15 10:48:13 -0700111 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800112 // NOTE: Ignore ARP packets except those target for the router
113 // We will reconsider enabling this when we have host learning support
114 /*
Pier Ventre10bd8d12016-11-26 21:05:22 -0800115 Set<Host> hosts = hostService.getHostsByIp(pkt.target());
116 if (hosts.size() > 1) {
117 log.warn("More than one host with the same ip {}", pkt.target());
118 }
119 Host targetHost = hosts.stream().findFirst().orElse(null);
Charles Chan68aa62d2015-11-09 16:37:23 -0800120 // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
Charles Chaneb088e62015-10-15 10:48:13 -0700121 if (targetHost != null) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800122 pkt.forward(targetHost.location());
Charles Chan68aa62d2015-11-09 16:37:23 -0800123 // ARP request for unknown host in the subnet. Flood in the subnet.
124 } else {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800125 flood(pkt);
Charles Chan68aa62d2015-11-09 16:37:23 -0800126 }
Charles Chan563a7812017-02-27 15:50:43 -0800127 */
Charles Chan68aa62d2015-11-09 16:37:23 -0800128 }
129 }
sanghob35a6192015-04-01 13:05:26 -0700130
Pier Ventre10bd8d12016-11-26 21:05:22 -0800131 private void handleArpReply(NeighbourMessageContext pkt, HostService hostService) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800132 // ARP reply for router. Process all pending IP packets.
Pier Ventre10bd8d12016-11-26 21:05:22 -0800133 if (isArpForRouter(pkt)) {
134 Ip4Address hostIpAddress = pkt.sender().getIp4Address();
135 srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
Charles Chan68aa62d2015-11-09 16:37:23 -0800136 } else {
Charles Chan563a7812017-02-27 15:50:43 -0800137 // NOTE: Ignore ARP packets except those target for the router
138 // We will reconsider enabling this when we have host learning support
139 /*
Pier Ventre10bd8d12016-11-26 21:05:22 -0800140 HostId targetHostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
141 Host targetHost = hostService.getHost(targetHostId);
Charles Chan68aa62d2015-11-09 16:37:23 -0800142 // ARP reply for known hosts. Forward to the host.
143 if (targetHost != null) {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800144 pkt.forward(targetHost.location());
Charles Chan68aa62d2015-11-09 16:37:23 -0800145 // ARP reply for unknown host, Flood in the subnet.
146 } else {
147 // Don't flood to non-edge ports
Charles Chan59cc16d2017-02-02 16:20:42 -0800148 if (pkt.vlan().equals(SegmentRoutingManager.INTERNAL_VLAN)) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800149 return;
150 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800151 flood(pkt);
Charles Chaneb088e62015-10-15 10:48:13 -0700152 }
Charles Chan563a7812017-02-27 15:50:43 -0800153 */
sanghob35a6192015-04-01 13:05:26 -0700154 }
155 }
156
Charles Chand2edd472016-10-17 18:03:37 -0700157 /**
158 * Check if the source protocol address of an ARP packet belongs to the same
159 * subnet configured on the port it is seen.
160 *
Pier Ventre10bd8d12016-11-26 21:05:22 -0800161 * @param pkt ARP packet and context information
Charles Chand2edd472016-10-17 18:03:37 -0700162 * @return true if the source protocol address belongs to the configured subnet
163 */
Pier Ventre10bd8d12016-11-26 21:05:22 -0800164 private boolean validateArpSpa(NeighbourMessageContext pkt) {
165 Ip4Address spa = pkt.sender().getIp4Address();
166 Set<IpPrefix> subnet = config.getPortSubnets(pkt.inPort().deviceId(), pkt.inPort().port())
167 .stream()
168 .filter(ipPrefix -> ipPrefix.isIp4() && ipPrefix.contains(spa))
169 .collect(Collectors.toSet());
170 return !subnet.isEmpty();
Charles Chand2edd472016-10-17 18:03:37 -0700171 }
172
sanghob35a6192015-04-01 13:05:26 -0700173
Pier Ventre10bd8d12016-11-26 21:05:22 -0800174 private boolean isArpForRouter(NeighbourMessageContext pkt) {
175 Ip4Address targetProtocolAddress = pkt.target().getIp4Address();
176 Set<IpAddress> gatewayIpAddresses = null;
Saurav Das4ce45962015-11-24 23:21:05 -0800177 try {
Pier Ventre10bd8d12016-11-26 21:05:22 -0800178 if (targetProtocolAddress.equals(config.getRouterIpv4(pkt.inPort().deviceId()))) {
sanghob35a6192015-04-01 13:05:26 -0700179 return true;
180 }
Pier Ventre10bd8d12016-11-26 21:05:22 -0800181 gatewayIpAddresses = config.getPortIPs(pkt.inPort().deviceId());
Saurav Das4ce45962015-11-24 23:21:05 -0800182 } catch (DeviceConfigNotFoundException e) {
183 log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
184 }
185 if (gatewayIpAddresses != null &&
186 gatewayIpAddresses.contains(targetProtocolAddress)) {
187 return true;
sanghob35a6192015-04-01 13:05:26 -0700188 }
189 return false;
190 }
191
sanghob35a6192015-04-01 13:05:26 -0700192 /**
193 * Sends an APR request for the target IP address to all ports except in-port.
194 *
195 * @param deviceId Switch device ID
196 * @param targetAddress target IP address for ARP
197 * @param inPort in-port
198 */
199 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
Pier Ventre735b8c82016-12-02 08:16:05 -0800200 byte[] senderMacAddress = new byte[MacAddress.MAC_ADDRESS_LENGTH];
201 byte[] senderIpAddress = new byte[Ip4Address.BYTE_LENGTH];
202 /*
203 * Retrieves device info.
204 */
Pier Luigia905c0c2017-01-29 12:38:48 -0800205 if (!getSenderInfo(senderMacAddress, senderIpAddress, deviceId, targetAddress)) {
206 log.warn("Aborting sendArpRequest, we cannot get all the information needed");
207 return;
208 }
Pier Ventre735b8c82016-12-02 08:16:05 -0800209 /*
210 * Creates the request.
211 */
212 Ethernet arpRequest = ARP.buildArpRequest(
213 senderMacAddress,
214 senderIpAddress,
215 targetAddress.toOctets(),
216 VlanId.NO_VID
Charles Chan68aa62d2015-11-09 16:37:23 -0800217 );
Pier Ventre735b8c82016-12-02 08:16:05 -0800218 flood(arpRequest, inPort, targetAddress);
Pier Ventre10bd8d12016-11-26 21:05:22 -0800219 }
220
sanghob35a6192015-04-01 13:05:26 -0700221}