blob: 3c92404587347b85bfd4e410b8ab8ea83f7d3180 [file] [log] [blame]
Hyunsun Moon022272f2016-01-11 15:30:42 -08001/*
2 * Copyright 2014-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 */
16package org.onosproject.cordvtn;
17
18import com.google.common.collect.Sets;
19import org.onlab.packet.ARP;
20import org.onlab.packet.EthType;
21import org.onlab.packet.Ethernet;
22import org.onlab.packet.Ip4Address;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.MacAddress;
25import org.onosproject.core.ApplicationId;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080026import org.onosproject.net.Host;
Hyunsun Moon022272f2016-01-11 15:30:42 -080027import org.onosproject.net.flow.DefaultTrafficSelector;
28import org.onosproject.net.flow.DefaultTrafficTreatment;
29import org.onosproject.net.flow.TrafficSelector;
30import org.onosproject.net.flow.TrafficTreatment;
31import org.onosproject.net.packet.DefaultOutboundPacket;
32import org.onosproject.net.packet.PacketContext;
33import org.onosproject.net.packet.PacketPriority;
34import org.onosproject.net.packet.PacketService;
35import org.slf4j.Logger;
36
37import java.nio.ByteBuffer;
38import java.util.Optional;
39import java.util.Set;
40
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080041import static com.google.common.base.Preconditions.checkArgument;
Hyunsun Moon022272f2016-01-11 15:30:42 -080042import static com.google.common.base.Preconditions.checkNotNull;
43import static org.slf4j.LoggerFactory.getLogger;
44
45/**
46 * Handles ARP requests for virtual network service IPs.
47 */
48public class CordVtnArpProxy {
49 protected final Logger log = getLogger(getClass());
Hyunsun Moon022272f2016-01-11 15:30:42 -080050
51 private final ApplicationId appId;
52 private final PacketService packetService;
53
54 private Set<Ip4Address> serviceIPs = Sets.newHashSet();
55
56 /**
57 * Default constructor.
58 *
59 * @param appId application id
60 * @param packetService packet service
61 */
62 public CordVtnArpProxy(ApplicationId appId, PacketService packetService) {
63 this.appId = appId;
64 this.packetService = packetService;
65 }
66
67 /**
68 * Requests ARP packet.
69 */
70 public void requestPacket() {
71 TrafficSelector selector = DefaultTrafficSelector.builder()
72 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
73 .build();
74
75 packetService.requestPackets(selector,
76 PacketPriority.CONTROL,
77 appId,
78 Optional.empty());
79 }
80
81 /**
82 * Cancels ARP packet.
83 */
84 public void cancelPacket() {
85 TrafficSelector selector = DefaultTrafficSelector.builder()
86 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
87 .build();
88
89 packetService.cancelPackets(selector,
90 PacketPriority.CONTROL,
91 appId,
92 Optional.empty());
93 }
94
95 /**
96 * Adds a given service IP address to be served.
97 *
98 * @param serviceIp service ip
99 */
100 public void addServiceIp(IpAddress serviceIp) {
101 checkNotNull(serviceIp);
102 serviceIPs.add(serviceIp.getIp4Address());
103 }
104
105 /**
106 * Removes a given service IP address from this ARP proxy.
107 *
108 * @param serviceIp service ip
109 */
110 public void removeServiceIp(IpAddress serviceIp) {
111 checkNotNull(serviceIp);
112 serviceIPs.remove(serviceIp.getIp4Address());
113 }
114
115 /**
116 * Emits ARP reply with fake MAC address for a given ARP request.
117 * It only handles requests for the registered service IPs, and the other
118 * requests can be handled by other ARP handlers like openstackSwitching or
119 * proxyArp, for example.
120 *
121 * @param context packet context
122 * @param ethPacket ethernet packet
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800123 * @param gatewayMac gateway mac address
Hyunsun Moon022272f2016-01-11 15:30:42 -0800124 */
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800125 public void processArpPacket(PacketContext context, Ethernet ethPacket, MacAddress gatewayMac) {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800126 ARP arpPacket = (ARP) ethPacket.getPayload();
127 Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
128
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800129 if (arpPacket.getOpCode() != ARP.OP_REQUEST || !serviceIPs.contains(targetIp)) {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800130 return;
131 }
132
Hyunsun Moon0d836e22016-02-01 23:30:58 -0800133 if (gatewayMac.equals(MacAddress.NONE)) {
134 log.debug("Gateway mac address is not set, ignoring ARP request");
135 context.block();
136 return;
137 }
138
Hyunsun Moon022272f2016-01-11 15:30:42 -0800139 Ethernet ethReply = ARP.buildArpReply(
140 targetIp,
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800141 gatewayMac,
Hyunsun Moon022272f2016-01-11 15:30:42 -0800142 ethPacket);
143
144 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
145 .setOutput(context.inPacket().receivedFrom().port())
146 .build();
147
148 packetService.emit(new DefaultOutboundPacket(
149 context.inPacket().receivedFrom().deviceId(),
150 treatment,
151 ByteBuffer.wrap(ethReply.serialize())));
152
153 context.block();
154 }
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800155
156 /**
157 * Emits gratuitous ARP when a gateway mac address has been changed.
158 *
159 * @param ip ip address to update MAC
160 * @param mac new mac address
161 * @param hosts set of hosts to send gratuitous ARP packet
162 */
163 public void sendGratuitousArp(IpAddress ip, MacAddress mac, Set<Host> hosts) {
164 checkArgument(!mac.equals(MacAddress.NONE));
165
166 Ethernet ethArp = buildGratuitousArp(ip.getIp4Address(), mac);
167 hosts.stream().forEach(host -> {
168 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
169 .setOutput(host.location().port())
170 .build();
171
172 packetService.emit(new DefaultOutboundPacket(
173 host.location().deviceId(),
174 treatment,
175 ByteBuffer.wrap(ethArp.serialize())));
176 });
177 }
178
179 /**
180 * Builds gratuitous ARP packet with a given IP and MAC address.
181 *
182 * @param ip ip address for TPA and SPA
183 * @param mac new mac address
184 * @return ethernet packet
185 */
186 private Ethernet buildGratuitousArp(IpAddress ip, MacAddress mac) {
187 Ethernet eth = new Ethernet();
188
189 eth.setEtherType(Ethernet.TYPE_ARP);
190 eth.setSourceMACAddress(mac);
191 eth.setDestinationMACAddress(MacAddress.BROADCAST);
192
193 ARP arp = new ARP();
194 arp.setOpCode(ARP.OP_REQUEST);
195 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
196 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
197 arp.setProtocolType(ARP.PROTO_TYPE_IP);
198 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
199
200 arp.setSenderHardwareAddress(mac.toBytes());
201 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
202 arp.setSenderProtocolAddress(ip.getIp4Address().toOctets());
203 arp.setTargetProtocolAddress(ip.getIp4Address().toOctets());
204
205 eth.setPayload(arp);
206 return eth;
207 }
Hyunsun Moon022272f2016-01-11 15:30:42 -0800208}