blob: 9e6e258e6d0be182207274c578a82956ebe08f6f [file] [log] [blame]
Hyunsun Moon022272f2016-01-11 15:30:42 -08001/*
Brian O'Connor80dff972017-08-03 22:46:30 -07002 * Copyright 2016-present Open Networking Foundation
Hyunsun Moon022272f2016-01-11 15:30:42 -08003 *
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 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Moon022272f2016-01-11 15:30:42 -080017
Hyunsun Moonbcf49252017-02-21 22:28:41 +090018import com.google.common.base.Strings;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080019import com.google.common.collect.Maps;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090023import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070025import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
Hyunsun Moon022272f2016-01-11 15:30:42 -080027import org.onlab.packet.ARP;
28import org.onlab.packet.EthType;
29import org.onlab.packet.Ethernet;
30import org.onlab.packet.Ip4Address;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.MacAddress;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090033import org.onlab.util.Tools;
34import org.onosproject.cfg.ComponentConfigService;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090035import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070037import org.onosproject.net.DeviceId;
Hyunsun Moon187bf532017-01-19 10:57:40 +090038import org.onosproject.net.Host;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090039import org.onosproject.net.HostId;
40import org.onosproject.net.Port;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070041import org.onosproject.net.PortNumber;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070042import org.onosproject.net.config.NetworkConfigEvent;
43import org.onosproject.net.config.NetworkConfigListener;
Hyunsun Moon187bf532017-01-19 10:57:40 +090044import org.onosproject.net.config.NetworkConfigService;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090045import org.onosproject.net.device.DeviceService;
Hyunsun Moon022272f2016-01-11 15:30:42 -080046import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090050import org.onosproject.net.host.HostService;
Hyunsun Moon022272f2016-01-11 15:30:42 -080051import org.onosproject.net.packet.DefaultOutboundPacket;
52import org.onosproject.net.packet.PacketContext;
53import org.onosproject.net.packet.PacketPriority;
Hyunsun Moon187bf532017-01-19 10:57:40 +090054import org.onosproject.net.packet.PacketProcessor;
Hyunsun Moon022272f2016-01-11 15:30:42 -080055import org.onosproject.net.packet.PacketService;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090056import org.opencord.cordvtn.api.Constants;
Hyunsun Moon187bf532017-01-19 10:57:40 +090057import org.opencord.cordvtn.api.CordVtnConfig;
58import org.opencord.cordvtn.api.core.Instance;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090059import org.opencord.cordvtn.api.core.ServiceNetworkEvent;
60import org.opencord.cordvtn.api.core.ServiceNetworkListener;
61import org.opencord.cordvtn.api.core.ServiceNetworkService;
Hyunsun Moon187bf532017-01-19 10:57:40 +090062import org.opencord.cordvtn.api.net.ServiceNetwork;
Hyunsun Moon0d00fb42017-08-09 18:21:03 +090063import org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090064import org.opencord.cordvtn.api.node.CordVtnNode;
65import org.opencord.cordvtn.api.node.CordVtnNodeService;
Hyunsun Moon0d00fb42017-08-09 18:21:03 +090066import org.opencord.cordvtn.api.node.CordVtnNodeState;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090067import org.osgi.service.component.ComponentContext;
Hyunsun Moon022272f2016-01-11 15:30:42 -080068import org.slf4j.Logger;
69
70import java.nio.ByteBuffer;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090071import java.util.Dictionary;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080072import java.util.Map;
Hyunsun Moon022272f2016-01-11 15:30:42 -080073import java.util.Optional;
74import java.util.Set;
75
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090076import static com.google.common.base.Preconditions.checkArgument;
Hyunsun Moon022272f2016-01-11 15:30:42 -080077import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090078import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090079import static org.opencord.cordvtn.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moon187bf532017-01-19 10:57:40 +090080import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.*;
Hyunsun Moon022272f2016-01-11 15:30:42 -080081import static org.slf4j.LoggerFactory.getLogger;
82
83/**
84 * Handles ARP requests for virtual network service IPs.
85 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070086@Component(immediate = true)
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090087public class CordVtnArpProxy {
Hyunsun Moon022272f2016-01-11 15:30:42 -080088 protected final Logger log = getLogger(getClass());
Hyunsun Moon022272f2016-01-11 15:30:42 -080089
Hyunsun Moonbcf49252017-02-21 22:28:41 +090090 private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
91
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected PacketService packetService;
Hyunsun Moon022272f2016-01-11 15:30:42 -080094
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070095 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090096 protected CoreService coreService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected HostService hostService;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700100
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900102 protected NetworkConfigService netConfigService;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected ComponentConfigService compConfigService;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700106
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900108 protected DeviceService deviceService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 protected CordVtnNodeService nodeService;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected ServiceNetworkService snetService;
115
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900116 @Property(name = PRIVATE_GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
117 label = "Fake MAC address for virtual network gateway")
118 private String privateGatewayMacStr = DEFAULT_GATEWAY_MAC_STR;
119 private MacAddress privateGatewayMac = MacAddress.valueOf(privateGatewayMacStr);
120
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700121 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900122 private final Map<IpAddress, MacAddress> gateways = Maps.newConcurrentMap();
Hyunsun Moon022272f2016-01-11 15:30:42 -0800123
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700124 private NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900125 private ServiceNetworkListener snetListener = new InternalServiceNetworkListener();
126 private ApplicationId appId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700127
128 @Activate
129 protected void activate() {
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900130 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900131 compConfigService.registerProperties(getClass());
132
133 netConfigService.addListener(configListener);
134 readPublicGateways();
135 snetService.addListener(snetListener);
136 readPrivateGateways();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700137
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700138 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
139 requestPacket();
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900140
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900141 log.info("Started");
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700142 }
143
144 @Deactivate
145 protected void deactivate() {
146 packetService.removeProcessor(packetProcessor);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900147 snetService.removeListener(snetListener);
148 netConfigService.removeListener(configListener);
149 compConfigService.unregisterProperties(getClass(), false);
150
151 log.info("Stopped");
152 }
153
154 @Modified
155 protected void modified(ComponentContext context) {
156 Dictionary<?, ?> properties = context.getProperties();
157 String updatedMac;
158
159 updatedMac = Tools.get(properties, PRIVATE_GATEWAY_MAC);
160 if (!Strings.isNullOrEmpty(updatedMac) &&
161 !updatedMac.equals(privateGatewayMacStr)) {
162 privateGatewayMacStr = updatedMac;
163 privateGatewayMac = MacAddress.valueOf(privateGatewayMacStr);
164 }
165
166 log.info("Modified");
Hyunsun Moon022272f2016-01-11 15:30:42 -0800167 }
168
169 /**
170 * Requests ARP packet.
171 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700172 private void requestPacket() {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800173 TrafficSelector selector = DefaultTrafficSelector.builder()
174 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
175 .build();
176
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900177 packetService.requestPackets(
178 selector,
179 PacketPriority.CONTROL,
180 appId,
181 Optional.empty());
Hyunsun Moon022272f2016-01-11 15:30:42 -0800182 }
183
184 /**
185 * Cancels ARP packet.
186 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700187 private void cancelPacket() {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800188 TrafficSelector selector = DefaultTrafficSelector.builder()
189 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
190 .build();
191
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900192 packetService.cancelPackets(
193 selector,
194 PacketPriority.CONTROL,
195 appId,
196 Optional.empty());
Hyunsun Moon022272f2016-01-11 15:30:42 -0800197 }
198
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900199 private void readPrivateGateways() {
200 snetService.serviceNetworks().stream()
201 .filter(net -> net.type() == PRIVATE || net.type() == VSG)
202 .filter(net -> net.serviceIp() != null)
203 .forEach(net -> addGateway(net.serviceIp(), privateGatewayMac));
204 }
205
Hyunsun Moon022272f2016-01-11 15:30:42 -0800206 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800207 * Adds a given gateway IP and MAC address to this ARP proxy.
Hyunsun Moon022272f2016-01-11 15:30:42 -0800208 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800209 * @param gatewayIp gateway ip address
210 * @param gatewayMac gateway mac address
Hyunsun Moon022272f2016-01-11 15:30:42 -0800211 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700212 private void addGateway(IpAddress gatewayIp, MacAddress gatewayMac) {
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900213 checkNotNull(gatewayIp, "Gateway IP address cannot be null");
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900214 checkArgument(gatewayMac != null && gatewayMac != MacAddress.NONE,
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900215 "Gateway MAC address cannot be null or NONE");
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900216
217 MacAddress existing = gateways.get(gatewayIp);
218 if (existing != null && !existing.equals(privateGatewayMac) &&
219 gatewayMac.equals(privateGatewayMac)) {
220 // this is public gateway IP and MAC configured via netcfg
221 // don't update with private gateway MAC
222 return;
223 }
224 gateways.put(gatewayIp, gatewayMac);
225 log.debug("Added ARP proxy entry IP:{} MAC:{}", gatewayIp, gatewayMac);
Hyunsun Moon022272f2016-01-11 15:30:42 -0800226 }
227
228 /**
229 * Removes a given service IP address from this ARP proxy.
230 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800231 * @param gatewayIp gateway ip address
Hyunsun Moon022272f2016-01-11 15:30:42 -0800232 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700233 private void removeGateway(IpAddress gatewayIp) {
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800234 checkNotNull(gatewayIp);
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900235 MacAddress existing = gateways.get(gatewayIp);
236 if (existing == null) {
237 return;
238 }
239 if (!existing.equals(privateGatewayMac)) {
240 // this is public gateway IP and MAC configured via netcfg
241 // do nothing
242 return;
243 }
244 gateways.remove(gatewayIp);
245 log.debug("Removed ARP proxy entry for IP:{} MAC: {}", gatewayIp, existing);
Hyunsun Moon022272f2016-01-11 15:30:42 -0800246 }
247
248 /**
249 * Emits ARP reply with fake MAC address for a given ARP request.
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700250 * It only handles requests for the registered gateway IPs and host IPs.
Hyunsun Moon022272f2016-01-11 15:30:42 -0800251 *
252 * @param context packet context
253 * @param ethPacket ethernet packet
254 */
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700255 private void processArpRequest(PacketContext context, Ethernet ethPacket) {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800256 ARP arpPacket = (ARP) ethPacket.getPayload();
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800257 Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800258
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800259 MacAddress gatewayMac = gateways.get(targetIp);
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700260 MacAddress replyMac = gatewayMac != null ? gatewayMac :
261 getMacFromHostService(targetIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800262
263 if (replyMac.equals(MacAddress.NONE)) {
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900264 forwardArpRequest(context, ethPacket);
Hyunsun Moon0d836e22016-02-01 23:30:58 -0800265 return;
266 }
267
Hyunsun Moon022272f2016-01-11 15:30:42 -0800268 Ethernet ethReply = ARP.buildArpReply(
269 targetIp,
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800270 replyMac,
Hyunsun Moon022272f2016-01-11 15:30:42 -0800271 ethPacket);
272
273 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
274 .setOutput(context.inPacket().receivedFrom().port())
275 .build();
276
277 packetService.emit(new DefaultOutboundPacket(
278 context.inPacket().receivedFrom().deviceId(),
279 treatment,
280 ByteBuffer.wrap(ethReply.serialize())));
281
282 context.block();
283 }
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800284
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700285 private void processArpReply(PacketContext context, Ethernet ethPacket) {
286 ARP arpPacket = (ARP) ethPacket.getPayload();
287 Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
288
289 DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
290 Host host = hostService.getHostsByIp(targetIp).stream()
291 .filter(h -> h.location().deviceId().equals(deviceId))
292 .findFirst()
293 .orElse(null);
294
295 if (host == null) {
296 // do nothing for the unknown ARP reply
297 log.trace("No host found for {} in {}", targetIp, deviceId);
298 context.block();
299 return;
300 }
301
302 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
303 .setOutput(host.location().port())
304 .build();
305
306 packetService.emit(new DefaultOutboundPacket(
307 deviceId,
308 treatment,
309 ByteBuffer.wrap(ethPacket.serialize())));
310
311 context.block();
312 }
313
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900314 private void forwardArpRequest(PacketContext context, Ethernet ethPacket) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700315 DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900316 PortNumber inputPort = context.inPacket().receivedFrom().port();
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700317
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900318 Host host = hostService.getHost(HostId.hostId(ethPacket.getSourceMAC()));
Jonathan Hartffc172c2018-01-25 13:42:46 -0800319 if (host == null) {
320 context.block();
321 return;
322 }
323
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900324 NetworkType networkType = Instance.of(host).netType();
Jonathan Hartffc172c2018-01-25 13:42:46 -0800325 if (networkType != MANAGEMENT_HOST && networkType != FLAT) {
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900326 context.block();
327 log.trace("Failed to handle ARP request");
328 return;
329 }
330
331 PortNumber outputPort = networkType == MANAGEMENT_HOST ?
332 hostMgmtPort(deviceId) : dataPort(deviceId);
333 if (inputPort.equals(outputPort)) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700334 context.block();
335 return;
336 }
337
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900338 if (outputPort != null) {
339 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
340 .setOutput(outputPort)
341 .build();
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700342
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900343 packetService.emit(new DefaultOutboundPacket(
344 context.inPacket().receivedFrom().deviceId(),
345 treatment,
346 ByteBuffer.wrap(ethPacket.serialize())));
347 } else {
348 log.trace("Failed to handle ARP request");
349 }
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700350
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700351 context.block();
352 }
353
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900354 private PortNumber hostMgmtPort(DeviceId deviceId) {
355 CordVtnNode node = nodeService.node(deviceId);
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900356 if (node == null || node.state() != CordVtnNodeState.COMPLETE ||
357 node.hostManagementInterface() == null) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900358 return null;
359 }
360 Optional<Port> port = deviceService.getPorts(deviceId).stream()
361 .filter(p -> p.annotations().value(PORT_NAME)
362 .equals(node.hostManagementInterface()) &&
363 p.isEnabled())
364 .findAny();
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900365 return port.map(Port::number).orElse(null);
366 }
367
368 private PortNumber dataPort(DeviceId deviceId) {
369 CordVtnNode node = nodeService.node(deviceId);
370 if (node == null || node.state() != CordVtnNodeState.COMPLETE ||
371 node.dataInterface() == null) {
372 return null;
373 }
374 Optional<Port> port = deviceService.getPorts(deviceId).stream()
375 .filter(p -> p.annotations().value(PORT_NAME)
376 .equals(node.dataInterface()) &&
377 p.isEnabled())
378 .findAny();
379 return port.map(Port::number).orElse(null);
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900380 }
381
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800382 /**
383 * Emits gratuitous ARP when a gateway mac address has been changed.
384 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800385 * @param gatewayIp gateway ip address to update MAC
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700386 * @param instances set of instances to send gratuitous ARP packet
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800387 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700388 private void sendGratuitousArp(IpAddress gatewayIp, Set<Instance> instances) {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900389 MacAddress gatewayMac = gateways.get(gatewayIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800390 if (gatewayMac == null) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700391 log.debug("Gateway {} is not registered to ARP proxy", gatewayIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800392 return;
393 }
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800394
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800395 Ethernet ethArp = buildGratuitousArp(gatewayIp.getIp4Address(), gatewayMac);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900396 instances.forEach(instance -> {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800397 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700398 .setOutput(instance.portNumber())
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800399 .build();
400
401 packetService.emit(new DefaultOutboundPacket(
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700402 instance.deviceId(),
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800403 treatment,
404 ByteBuffer.wrap(ethArp.serialize())));
405 });
406 }
407
408 /**
409 * Builds gratuitous ARP packet with a given IP and MAC address.
410 *
411 * @param ip ip address for TPA and SPA
412 * @param mac new mac address
413 * @return ethernet packet
414 */
415 private Ethernet buildGratuitousArp(IpAddress ip, MacAddress mac) {
416 Ethernet eth = new Ethernet();
417
418 eth.setEtherType(Ethernet.TYPE_ARP);
419 eth.setSourceMACAddress(mac);
420 eth.setDestinationMACAddress(MacAddress.BROADCAST);
421
422 ARP arp = new ARP();
423 arp.setOpCode(ARP.OP_REQUEST);
424 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
425 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
426 arp.setProtocolType(ARP.PROTO_TYPE_IP);
427 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
428
429 arp.setSenderHardwareAddress(mac.toBytes());
430 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
431 arp.setSenderProtocolAddress(ip.getIp4Address().toOctets());
432 arp.setTargetProtocolAddress(ip.getIp4Address().toOctets());
433
434 eth.setPayload(arp);
435 return eth;
436 }
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800437
438 /**
439 * Returns MAC address of a host with a given target IP address by asking to
440 * host service. It does not support overlapping IP.
441 *
442 * @param targetIp target ip
443 * @return mac address, or NONE mac address if it fails to find the mac
444 */
445 private MacAddress getMacFromHostService(IpAddress targetIp) {
446 checkNotNull(targetIp);
447
448 Host host = hostService.getHostsByIp(targetIp)
449 .stream()
450 .findFirst()
451 .orElse(null);
452
453 if (host != null) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700454 log.trace("Found MAC from host service for {}", targetIp);
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800455 return host.mac();
456 } else {
457 return MacAddress.NONE;
458 }
459 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700460
461 private class InternalPacketProcessor implements PacketProcessor {
462
463 @Override
464 public void process(PacketContext context) {
465 if (context.isHandled()) {
466 return;
467 }
468 Ethernet ethPacket = context.inPacket().parsed();
469 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
470 return;
471 }
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700472
473 ARP arpPacket = (ARP) ethPacket.getPayload();
474 switch (arpPacket.getOpCode()) {
475 case ARP.OP_REQUEST:
476 processArpRequest(context, ethPacket);
477 break;
478 case ARP.OP_REPLY:
479 processArpReply(context, ethPacket);
480 break;
481 default:
482 break;
483 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700484 }
485 }
486
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900487 private class InternalServiceNetworkListener implements ServiceNetworkListener {
488
489 @Override
490 public boolean isRelevant(ServiceNetworkEvent event) {
491 ServiceNetwork snet = event.subject();
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900492 return snet.serviceIp() != null;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700493 }
494
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900495 @Override
496 public void event(ServiceNetworkEvent event) {
497 ServiceNetwork snet = event.subject();
498 switch (event.type()) {
499 case SERVICE_NETWORK_CREATED:
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900500 if (snet.type() == PRIVATE || snet.type() == VSG) {
501 addGateway(snet.serviceIp(), privateGatewayMac);
502 }
503 break;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900504 case SERVICE_NETWORK_UPDATED:
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900505 if (snet.type() == PRIVATE || snet.type() == VSG) {
506 addGateway(snet.serviceIp(), privateGatewayMac);
507 } else {
508 // don't service ARP for the other network gateway
509 removeGateway(snet.serviceIp());
510 }
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900511 break;
512 case SERVICE_NETWORK_REMOVED:
513 removeGateway(snet.serviceIp());
514 break;
515 case SERVICE_PORT_CREATED:
516 case SERVICE_PORT_UPDATED:
517 case SERVICE_PORT_REMOVED:
518 default:
519 // do nothing for the other events
520 break;
521 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700522 }
523 }
524
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900525 private void readPublicGateways() {
526 CordVtnConfig config = netConfigService.getConfig(appId, CordVtnConfig.class);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700527 if (config == null) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900528 log.warn("No configuration found");
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700529 return;
530 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700531
Hyunsun Moon0d00fb42017-08-09 18:21:03 +0900532 config.publicGateways().forEach(this::addGateway);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700533 // TODO send gratuitous arp in case the MAC is changed
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700534 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700535
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700536 private class InternalConfigListener implements NetworkConfigListener {
537
538 @Override
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900539 public boolean isRelevant(NetworkConfigEvent event) {
540 return event.configClass().equals(CordVtnConfig.class);
541 }
542
543 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700544 public void event(NetworkConfigEvent event) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700545
546 switch (event.type()) {
547 case CONFIG_ADDED:
548 case CONFIG_UPDATED:
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900549 readPublicGateways();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700550 break;
551 default:
552 break;
553 }
554 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700555 }
Hyunsun Moon022272f2016-01-11 15:30:42 -0800556}