blob: 8ef889f25d883b317078214160c35d53ddcbfbee [file] [log] [blame]
sangho80f11cb2015-04-01 13:05:26 -07001/*
Brian O'Connor43b53542016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
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.ARP;
19import org.onlab.packet.Ethernet;
20import org.onlab.packet.Ip4Address;
21import org.onlab.packet.IpAddress;
Pier Ventreb6a7f342016-11-26 21:05:22 -080022import org.onlab.packet.IpPrefix;
sangho80f11cb2015-04-01 13:05:26 -070023import org.onlab.packet.MacAddress;
Charles Chanf4586112015-11-09 16:37:23 -080024import org.onlab.packet.VlanId;
Pier Ventreb6a7f342016-11-26 21:05:22 -080025import org.onosproject.incubator.net.neighbour.NeighbourMessageContext;
sangho80f11cb2015-04-01 13:05:26 -070026import org.onosproject.net.ConnectPoint;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.Host;
Pier Ventreb6a7f342016-11-26 21:05:22 -080029import org.onosproject.net.HostId;
Pier Ventreb6a7f342016-11-26 21:05:22 -080030import org.onosproject.net.host.HostService;
Charles Chan319d1a22015-11-03 10:42:14 -080031import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Charles Chandebfea32016-10-24 14:52:01 -070032import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
sangho80f11cb2015-04-01 13:05:26 -070033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
Saurav Dasc28b3432015-10-30 17:45:38 -070036import java.util.Set;
Pier Ventreb6a7f342016-11-26 21:05:22 -080037import java.util.stream.Collectors;
Saurav Dasc28b3432015-10-30 17:45:38 -070038
Pier Ventreb6a7f342016-11-26 21:05:22 -080039import static org.onosproject.incubator.net.neighbour.NeighbourMessageType.REQUEST;
sangho80f11cb2015-04-01 13:05:26 -070040
Charles Chanb7f75ac2016-01-11 18:28:54 -080041/**
42 * Handler of ARP packets that responses or forwards ARP packets that
43 * are sent to the controller.
44 */
Pier Ventreb6b81d52016-12-02 08:16:05 -080045public class ArpHandler extends SegmentRoutingNeighbourHandler {
sangho80f11cb2015-04-01 13:05:26 -070046
47 private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
48
sangho80f11cb2015-04-01 13:05:26 -070049 /**
50 * Creates an ArpHandler object.
51 *
52 * @param srManager SegmentRoutingManager object
53 */
54 public ArpHandler(SegmentRoutingManager srManager) {
Pier Ventreb6b81d52016-12-02 08:16:05 -080055 super(srManager);
sangho80f11cb2015-04-01 13:05:26 -070056 }
57
58 /**
59 * Processes incoming ARP packets.
Charles Chanf4586112015-11-09 16:37:23 -080060 *
sangho80f11cb2015-04-01 13:05:26 -070061 * If it is an ARP request to router itself or known hosts,
62 * then it sends ARP response.
63 * If it is an ARP request to unknown hosts in its own subnet,
64 * then it flood the ARP request to the ports.
65 * If it is an ARP response, then set a flow rule for the host
66 * and forward any IP packets to the host in the packet buffer to the host.
Charles Chanf4586112015-11-09 16:37:23 -080067 * <p>
68 * Note: We handles all ARP packet in, even for those ARP packets between
69 * hosts in the same subnet.
70 * For an ARP packet with broadcast destination MAC,
71 * some switches pipelines will send it to the controller due to table miss,
Saurav Das7b1b4882016-02-05 13:15:20 -080072 * other switches will flood the packets directly in the data plane without
Charles Chanf4586112015-11-09 16:37:23 -080073 * packet in.
74 * We can deal with both cases.
sangho80f11cb2015-04-01 13:05:26 -070075 *
Pier Ventreb6a7f342016-11-26 21:05:22 -080076 * @param pkt incoming ARP packet and context information
77 * @param hostService the host service
sangho80f11cb2015-04-01 13:05:26 -070078 */
Pier Ventreb6a7f342016-11-26 21:05:22 -080079 public void processPacketIn(NeighbourMessageContext pkt, HostService hostService) {
Charles Chancbdc9be2016-10-17 18:03:37 -070080
Charles Chandebfea32016-10-24 14:52:01 -070081 SegmentRoutingAppConfig appConfig = srManager.cfgService
82 .getConfig(srManager.appId, SegmentRoutingAppConfig.class);
Pier Ventreb6a7f342016-11-26 21:05:22 -080083 if (appConfig != null && appConfig.suppressSubnet().contains(pkt.inPort())) {
Charles Chandebfea32016-10-24 14:52:01 -070084 // Ignore ARP packets come from suppressed ports
Pier Ventre1a655962016-11-28 16:48:06 -080085 pkt.drop();
Charles Chandebfea32016-10-24 14:52:01 -070086 return;
87 }
88
Pier Ventreb6a7f342016-11-26 21:05:22 -080089 if (!validateArpSpa(pkt)) {
Charles Chanee891c52016-11-08 16:32:13 -080090 log.debug("Ignore ARP packet discovered on {} with unexpected src protocol address {}.",
Pier Ventreb6a7f342016-11-26 21:05:22 -080091 pkt.inPort(), pkt.sender().getIp4Address());
Pier Ventre1a655962016-11-28 16:48:06 -080092 pkt.drop();
Charles Chancbdc9be2016-10-17 18:03:37 -070093 return;
94 }
95
Pier Ventreb6a7f342016-11-26 21:05:22 -080096 if (pkt.type() == REQUEST) {
97 handleArpRequest(pkt, hostService);
sangho80f11cb2015-04-01 13:05:26 -070098 } else {
Pier Ventreb6a7f342016-11-26 21:05:22 -080099 handleArpReply(pkt, hostService);
sangho80f11cb2015-04-01 13:05:26 -0700100 }
101 }
102
Pier Ventreb6a7f342016-11-26 21:05:22 -0800103 private void handleArpRequest(NeighbourMessageContext pkt, HostService hostService) {
Charles Chanf4586112015-11-09 16:37:23 -0800104 // ARP request for router. Send ARP reply.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800105 if (isArpForRouter(pkt)) {
106 MacAddress targetMac = config.getRouterMacForAGatewayIp(pkt.target().getIp4Address());
Pier Ventreb6b81d52016-12-02 08:16:05 -0800107 sendResponse(pkt, targetMac, hostService);
Charles Chanbbc8d902015-10-15 10:48:13 -0700108 } else {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800109 Set<Host> hosts = hostService.getHostsByIp(pkt.target());
110 if (hosts.size() > 1) {
111 log.warn("More than one host with the same ip {}", pkt.target());
112 }
113 Host targetHost = hosts.stream().findFirst().orElse(null);
Charles Chanf4586112015-11-09 16:37:23 -0800114 // ARP request for known hosts. Send proxy ARP reply on behalf of the target.
Charles Chanbbc8d902015-10-15 10:48:13 -0700115 if (targetHost != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800116 pkt.forward(targetHost.location());
Charles Chanf4586112015-11-09 16:37:23 -0800117 // ARP request for unknown host in the subnet. Flood in the subnet.
118 } else {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800119 flood(pkt);
Charles Chanf4586112015-11-09 16:37:23 -0800120 }
121 }
122 }
sangho80f11cb2015-04-01 13:05:26 -0700123
Pier Ventreb6a7f342016-11-26 21:05:22 -0800124 private void handleArpReply(NeighbourMessageContext pkt, HostService hostService) {
Charles Chanf4586112015-11-09 16:37:23 -0800125 // ARP reply for router. Process all pending IP packets.
Pier Ventreb6a7f342016-11-26 21:05:22 -0800126 if (isArpForRouter(pkt)) {
127 Ip4Address hostIpAddress = pkt.sender().getIp4Address();
128 srManager.ipHandler.forwardPackets(pkt.inPort().deviceId(), hostIpAddress);
Charles Chanf4586112015-11-09 16:37:23 -0800129 } else {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800130 HostId targetHostId = HostId.hostId(pkt.dstMac(), pkt.vlan());
131 Host targetHost = hostService.getHost(targetHostId);
Charles Chanf4586112015-11-09 16:37:23 -0800132 // ARP reply for known hosts. Forward to the host.
133 if (targetHost != null) {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800134 pkt.forward(targetHost.location());
Charles Chanf4586112015-11-09 16:37:23 -0800135 // ARP reply for unknown host, Flood in the subnet.
136 } else {
137 // Don't flood to non-edge ports
Pier Ventreb6a7f342016-11-26 21:05:22 -0800138 if (pkt.vlan().equals(
Saurav Das2d94d312015-11-24 23:21:05 -0800139 VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET))) {
Charles Chanf4586112015-11-09 16:37:23 -0800140 return;
141 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800142 flood(pkt);
Charles Chanbbc8d902015-10-15 10:48:13 -0700143 }
sangho80f11cb2015-04-01 13:05:26 -0700144 }
145 }
146
Charles Chancbdc9be2016-10-17 18:03:37 -0700147 /**
148 * Check if the source protocol address of an ARP packet belongs to the same
149 * subnet configured on the port it is seen.
150 *
Pier Ventreb6a7f342016-11-26 21:05:22 -0800151 * @param pkt ARP packet and context information
Charles Chancbdc9be2016-10-17 18:03:37 -0700152 * @return true if the source protocol address belongs to the configured subnet
153 */
Pier Ventreb6a7f342016-11-26 21:05:22 -0800154 private boolean validateArpSpa(NeighbourMessageContext pkt) {
155 Ip4Address spa = pkt.sender().getIp4Address();
156 Set<IpPrefix> subnet = config.getPortSubnets(pkt.inPort().deviceId(), pkt.inPort().port())
157 .stream()
158 .filter(ipPrefix -> ipPrefix.isIp4() && ipPrefix.contains(spa))
159 .collect(Collectors.toSet());
160 return !subnet.isEmpty();
Charles Chancbdc9be2016-10-17 18:03:37 -0700161 }
162
sangho80f11cb2015-04-01 13:05:26 -0700163
Pier Ventreb6a7f342016-11-26 21:05:22 -0800164 private boolean isArpForRouter(NeighbourMessageContext pkt) {
165 Ip4Address targetProtocolAddress = pkt.target().getIp4Address();
166 Set<IpAddress> gatewayIpAddresses = null;
Saurav Das2d94d312015-11-24 23:21:05 -0800167 try {
Pier Ventreb6a7f342016-11-26 21:05:22 -0800168 if (targetProtocolAddress.equals(config.getRouterIpv4(pkt.inPort().deviceId()))) {
sangho80f11cb2015-04-01 13:05:26 -0700169 return true;
170 }
Pier Ventreb6a7f342016-11-26 21:05:22 -0800171 gatewayIpAddresses = config.getPortIPs(pkt.inPort().deviceId());
Saurav Das2d94d312015-11-24 23:21:05 -0800172 } catch (DeviceConfigNotFoundException e) {
173 log.warn(e.getMessage() + " Aborting check for router IP in processing arp");
174 }
175 if (gatewayIpAddresses != null &&
176 gatewayIpAddresses.contains(targetProtocolAddress)) {
177 return true;
sangho80f11cb2015-04-01 13:05:26 -0700178 }
179 return false;
180 }
181
sangho80f11cb2015-04-01 13:05:26 -0700182 /**
183 * Sends an APR request for the target IP address to all ports except in-port.
184 *
185 * @param deviceId Switch device ID
186 * @param targetAddress target IP address for ARP
187 * @param inPort in-port
188 */
189 public void sendArpRequest(DeviceId deviceId, IpAddress targetAddress, ConnectPoint inPort) {
Pier Ventreb6b81d52016-12-02 08:16:05 -0800190 byte[] senderMacAddress = new byte[MacAddress.MAC_ADDRESS_LENGTH];
191 byte[] senderIpAddress = new byte[Ip4Address.BYTE_LENGTH];
192 /*
193 * Retrieves device info.
194 */
195 getSenderInfo(senderMacAddress, senderIpAddress, deviceId, targetAddress);
196 /*
197 * Creates the request.
198 */
199 Ethernet arpRequest = ARP.buildArpRequest(
200 senderMacAddress,
201 senderIpAddress,
202 targetAddress.toOctets(),
203 VlanId.NO_VID
Charles Chanf4586112015-11-09 16:37:23 -0800204 );
Pier Ventreb6b81d52016-12-02 08:16:05 -0800205 flood(arpRequest, inPort, targetAddress);
Pier Ventreb6a7f342016-11-26 21:05:22 -0800206 }
207
sangho80f11cb2015-04-01 13:05:26 -0700208}