blob: 192a16e6a7c323ebea2e15f37217f302a613bbf9 [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 Moon2c3f0ee2017-04-06 16:47:21 +090063import org.opencord.cordvtn.api.node.CordVtnNode;
64import org.opencord.cordvtn.api.node.CordVtnNodeService;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090065import org.osgi.service.component.ComponentContext;
Hyunsun Moon022272f2016-01-11 15:30:42 -080066import org.slf4j.Logger;
67
68import java.nio.ByteBuffer;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090069import java.util.Dictionary;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080070import java.util.Map;
Hyunsun Moon022272f2016-01-11 15:30:42 -080071import java.util.Optional;
72import java.util.Set;
73
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090074import static com.google.common.base.Preconditions.checkArgument;
Hyunsun Moon022272f2016-01-11 15:30:42 -080075import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +090076import static org.onosproject.net.AnnotationKeys.PORT_NAME;
Hyunsun Moonbcf49252017-02-21 22:28:41 +090077import static org.opencord.cordvtn.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moon187bf532017-01-19 10:57:40 +090078import static org.opencord.cordvtn.api.net.ServiceNetwork.NetworkType.*;
Hyunsun Moon022272f2016-01-11 15:30:42 -080079import static org.slf4j.LoggerFactory.getLogger;
80
81/**
82 * Handles ARP requests for virtual network service IPs.
83 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070084@Component(immediate = true)
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090085public class CordVtnArpProxy {
Hyunsun Moon022272f2016-01-11 15:30:42 -080086 protected final Logger log = getLogger(getClass());
Hyunsun Moon022272f2016-01-11 15:30:42 -080087
Hyunsun Moonbcf49252017-02-21 22:28:41 +090088 private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
89
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected PacketService packetService;
Hyunsun Moon022272f2016-01-11 15:30:42 -080092
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon4302c2b2017-01-19 14:20:34 +090094 protected CoreService coreService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 protected HostService hostService;
Hyunsun Moonc031d9b2016-08-04 13:57:22 -070098
Hyunsun Mooneaf75e62016-09-27 16:40:23 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900100 protected NetworkConfigService netConfigService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 protected ComponentConfigService compConfigService;
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700104
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900106 protected DeviceService deviceService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 protected CordVtnNodeService nodeService;
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected ServiceNetworkService snetService;
113
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900114 @Property(name = PRIVATE_GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
115 label = "Fake MAC address for virtual network gateway")
116 private String privateGatewayMacStr = DEFAULT_GATEWAY_MAC_STR;
117 private MacAddress privateGatewayMac = MacAddress.valueOf(privateGatewayMacStr);
118
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700119 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900120 private final Map<IpAddress, MacAddress> gateways = Maps.newConcurrentMap();
Hyunsun Moon022272f2016-01-11 15:30:42 -0800121
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700122 private NetworkConfigListener configListener = new InternalConfigListener();
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900123 private ServiceNetworkListener snetListener = new InternalServiceNetworkListener();
124 private ApplicationId appId;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700125
126 @Activate
127 protected void activate() {
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900128 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900129 compConfigService.registerProperties(getClass());
130
131 netConfigService.addListener(configListener);
132 readPublicGateways();
133 snetService.addListener(snetListener);
134 readPrivateGateways();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700135
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700136 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
137 requestPacket();
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900138
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900139 log.info("Started");
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700140 }
141
142 @Deactivate
143 protected void deactivate() {
144 packetService.removeProcessor(packetProcessor);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900145 snetService.removeListener(snetListener);
146 netConfigService.removeListener(configListener);
147 compConfigService.unregisterProperties(getClass(), false);
148
149 log.info("Stopped");
150 }
151
152 @Modified
153 protected void modified(ComponentContext context) {
154 Dictionary<?, ?> properties = context.getProperties();
155 String updatedMac;
156
157 updatedMac = Tools.get(properties, PRIVATE_GATEWAY_MAC);
158 if (!Strings.isNullOrEmpty(updatedMac) &&
159 !updatedMac.equals(privateGatewayMacStr)) {
160 privateGatewayMacStr = updatedMac;
161 privateGatewayMac = MacAddress.valueOf(privateGatewayMacStr);
162 }
163
164 log.info("Modified");
Hyunsun Moon022272f2016-01-11 15:30:42 -0800165 }
166
167 /**
168 * Requests ARP packet.
169 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700170 private void requestPacket() {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800171 TrafficSelector selector = DefaultTrafficSelector.builder()
172 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
173 .build();
174
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900175 packetService.requestPackets(
176 selector,
177 PacketPriority.CONTROL,
178 appId,
179 Optional.empty());
Hyunsun Moon022272f2016-01-11 15:30:42 -0800180 }
181
182 /**
183 * Cancels ARP packet.
184 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700185 private void cancelPacket() {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800186 TrafficSelector selector = DefaultTrafficSelector.builder()
187 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
188 .build();
189
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900190 packetService.cancelPackets(
191 selector,
192 PacketPriority.CONTROL,
193 appId,
194 Optional.empty());
Hyunsun Moon022272f2016-01-11 15:30:42 -0800195 }
196
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900197 private void readPrivateGateways() {
198 snetService.serviceNetworks().stream()
199 .filter(net -> net.type() == PRIVATE || net.type() == VSG)
200 .filter(net -> net.serviceIp() != null)
201 .forEach(net -> addGateway(net.serviceIp(), privateGatewayMac));
202 }
203
Hyunsun Moon022272f2016-01-11 15:30:42 -0800204 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800205 * Adds a given gateway IP and MAC address to this ARP proxy.
Hyunsun Moon022272f2016-01-11 15:30:42 -0800206 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800207 * @param gatewayIp gateway ip address
208 * @param gatewayMac gateway mac address
Hyunsun Moon022272f2016-01-11 15:30:42 -0800209 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700210 private void addGateway(IpAddress gatewayIp, MacAddress gatewayMac) {
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900211 checkNotNull(gatewayIp, "Gateway IP address cannot be null");
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900212 checkArgument(gatewayMac != null && gatewayMac != MacAddress.NONE,
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900213 "Gateway MAC address cannot be null or NONE");
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900214
215 MacAddress existing = gateways.get(gatewayIp);
216 if (existing != null && !existing.equals(privateGatewayMac) &&
217 gatewayMac.equals(privateGatewayMac)) {
218 // this is public gateway IP and MAC configured via netcfg
219 // don't update with private gateway MAC
220 return;
221 }
222 gateways.put(gatewayIp, gatewayMac);
223 log.debug("Added ARP proxy entry IP:{} MAC:{}", gatewayIp, gatewayMac);
Hyunsun Moon022272f2016-01-11 15:30:42 -0800224 }
225
226 /**
227 * Removes a given service IP address from this ARP proxy.
228 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800229 * @param gatewayIp gateway ip address
Hyunsun Moon022272f2016-01-11 15:30:42 -0800230 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700231 private void removeGateway(IpAddress gatewayIp) {
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800232 checkNotNull(gatewayIp);
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900233 MacAddress existing = gateways.get(gatewayIp);
234 if (existing == null) {
235 return;
236 }
237 if (!existing.equals(privateGatewayMac)) {
238 // this is public gateway IP and MAC configured via netcfg
239 // do nothing
240 return;
241 }
242 gateways.remove(gatewayIp);
243 log.debug("Removed ARP proxy entry for IP:{} MAC: {}", gatewayIp, existing);
Hyunsun Moon022272f2016-01-11 15:30:42 -0800244 }
245
246 /**
247 * Emits ARP reply with fake MAC address for a given ARP request.
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700248 * It only handles requests for the registered gateway IPs and host IPs.
Hyunsun Moon022272f2016-01-11 15:30:42 -0800249 *
250 * @param context packet context
251 * @param ethPacket ethernet packet
252 */
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700253 private void processArpRequest(PacketContext context, Ethernet ethPacket) {
Hyunsun Moon022272f2016-01-11 15:30:42 -0800254 ARP arpPacket = (ARP) ethPacket.getPayload();
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800255 Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800256
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800257 MacAddress gatewayMac = gateways.get(targetIp);
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700258 MacAddress replyMac = gatewayMac != null ? gatewayMac :
259 getMacFromHostService(targetIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800260
261 if (replyMac.equals(MacAddress.NONE)) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700262 log.trace("Failed to find MAC for {}", targetIp);
263 forwardManagementArpRequest(context, ethPacket);
Hyunsun Moon0d836e22016-02-01 23:30:58 -0800264 return;
265 }
266
Hyunsun Moon022272f2016-01-11 15:30:42 -0800267 Ethernet ethReply = ARP.buildArpReply(
268 targetIp,
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800269 replyMac,
Hyunsun Moon022272f2016-01-11 15:30:42 -0800270 ethPacket);
271
272 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
273 .setOutput(context.inPacket().receivedFrom().port())
274 .build();
275
276 packetService.emit(new DefaultOutboundPacket(
277 context.inPacket().receivedFrom().deviceId(),
278 treatment,
279 ByteBuffer.wrap(ethReply.serialize())));
280
281 context.block();
282 }
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800283
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700284 private void processArpReply(PacketContext context, Ethernet ethPacket) {
285 ARP arpPacket = (ARP) ethPacket.getPayload();
286 Ip4Address targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
287
288 DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
289 Host host = hostService.getHostsByIp(targetIp).stream()
290 .filter(h -> h.location().deviceId().equals(deviceId))
291 .findFirst()
292 .orElse(null);
293
294 if (host == null) {
295 // do nothing for the unknown ARP reply
296 log.trace("No host found for {} in {}", targetIp, deviceId);
297 context.block();
298 return;
299 }
300
301 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
302 .setOutput(host.location().port())
303 .build();
304
305 packetService.emit(new DefaultOutboundPacket(
306 deviceId,
307 treatment,
308 ByteBuffer.wrap(ethPacket.serialize())));
309
310 context.block();
311 }
312
313 private void forwardManagementArpRequest(PacketContext context, Ethernet ethPacket) {
314 DeviceId deviceId = context.inPacket().receivedFrom().deviceId();
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900315 PortNumber hostMgmtPort = hostMgmtPort(deviceId);
316 Host host = hostService.getHost(HostId.hostId(ethPacket.getSourceMAC()));
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700317
318 if (host == null ||
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900319 Instance.of(host).netType() != MANAGEMENT_HOST ||
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700320 hostMgmtPort == null) {
321 context.block();
322 return;
323 }
324
325 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
326 .setOutput(hostMgmtPort)
327 .build();
328
329 packetService.emit(new DefaultOutboundPacket(
330 context.inPacket().receivedFrom().deviceId(),
331 treatment,
332 ByteBuffer.wrap(ethPacket.serialize())));
333
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700334 context.block();
335 }
336
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900337 private PortNumber hostMgmtPort(DeviceId deviceId) {
338 CordVtnNode node = nodeService.node(deviceId);
339 if (node == null || node.hostManagementInterface() == null) {
340 return null;
341 }
342 Optional<Port> port = deviceService.getPorts(deviceId).stream()
343 .filter(p -> p.annotations().value(PORT_NAME)
344 .equals(node.hostManagementInterface()) &&
345 p.isEnabled())
346 .findAny();
347 return port.isPresent() ? port.get().number() : null;
348 }
349
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800350 /**
351 * Emits gratuitous ARP when a gateway mac address has been changed.
352 *
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800353 * @param gatewayIp gateway ip address to update MAC
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700354 * @param instances set of instances to send gratuitous ARP packet
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800355 */
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700356 private void sendGratuitousArp(IpAddress gatewayIp, Set<Instance> instances) {
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900357 MacAddress gatewayMac = gateways.get(gatewayIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800358 if (gatewayMac == null) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700359 log.debug("Gateway {} is not registered to ARP proxy", gatewayIp);
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800360 return;
361 }
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800362
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800363 Ethernet ethArp = buildGratuitousArp(gatewayIp.getIp4Address(), gatewayMac);
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900364 instances.forEach(instance -> {
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800365 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700366 .setOutput(instance.portNumber())
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800367 .build();
368
369 packetService.emit(new DefaultOutboundPacket(
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700370 instance.deviceId(),
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800371 treatment,
372 ByteBuffer.wrap(ethArp.serialize())));
373 });
374 }
375
376 /**
377 * Builds gratuitous ARP packet with a given IP and MAC address.
378 *
379 * @param ip ip address for TPA and SPA
380 * @param mac new mac address
381 * @return ethernet packet
382 */
383 private Ethernet buildGratuitousArp(IpAddress ip, MacAddress mac) {
384 Ethernet eth = new Ethernet();
385
386 eth.setEtherType(Ethernet.TYPE_ARP);
387 eth.setSourceMACAddress(mac);
388 eth.setDestinationMACAddress(MacAddress.BROADCAST);
389
390 ARP arp = new ARP();
391 arp.setOpCode(ARP.OP_REQUEST);
392 arp.setHardwareType(ARP.HW_TYPE_ETHERNET);
393 arp.setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH);
394 arp.setProtocolType(ARP.PROTO_TYPE_IP);
395 arp.setProtocolAddressLength((byte) Ip4Address.BYTE_LENGTH);
396
397 arp.setSenderHardwareAddress(mac.toBytes());
398 arp.setTargetHardwareAddress(MacAddress.BROADCAST.toBytes());
399 arp.setSenderProtocolAddress(ip.getIp4Address().toOctets());
400 arp.setTargetProtocolAddress(ip.getIp4Address().toOctets());
401
402 eth.setPayload(arp);
403 return eth;
404 }
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800405
406 /**
407 * Returns MAC address of a host with a given target IP address by asking to
408 * host service. It does not support overlapping IP.
409 *
410 * @param targetIp target ip
411 * @return mac address, or NONE mac address if it fails to find the mac
412 */
413 private MacAddress getMacFromHostService(IpAddress targetIp) {
414 checkNotNull(targetIp);
415
416 Host host = hostService.getHostsByIp(targetIp)
417 .stream()
418 .findFirst()
419 .orElse(null);
420
421 if (host != null) {
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700422 log.trace("Found MAC from host service for {}", targetIp);
Hyunsun Moonb6febbe2016-02-12 15:59:53 -0800423 return host.mac();
424 } else {
425 return MacAddress.NONE;
426 }
427 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700428
429 private class InternalPacketProcessor implements PacketProcessor {
430
431 @Override
432 public void process(PacketContext context) {
433 if (context.isHandled()) {
434 return;
435 }
436 Ethernet ethPacket = context.inPacket().parsed();
437 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
438 return;
439 }
Hyunsun Moonc031d9b2016-08-04 13:57:22 -0700440
441 ARP arpPacket = (ARP) ethPacket.getPayload();
442 switch (arpPacket.getOpCode()) {
443 case ARP.OP_REQUEST:
444 processArpRequest(context, ethPacket);
445 break;
446 case ARP.OP_REPLY:
447 processArpReply(context, ethPacket);
448 break;
449 default:
450 break;
451 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700452 }
453 }
454
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900455 private class InternalServiceNetworkListener implements ServiceNetworkListener {
456
457 @Override
458 public boolean isRelevant(ServiceNetworkEvent event) {
459 ServiceNetwork snet = event.subject();
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900460 return snet.serviceIp() != null;
Hyunsun Moon1e88fef2016-08-04 14:00:35 -0700461 }
462
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900463 @Override
464 public void event(ServiceNetworkEvent event) {
465 ServiceNetwork snet = event.subject();
466 switch (event.type()) {
467 case SERVICE_NETWORK_CREATED:
468 case SERVICE_NETWORK_UPDATED:
Hyunsun Moon8e9bc932017-01-31 21:32:20 +0900469 addGateway(snet.serviceIp(), privateGatewayMac);
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900470 break;
471 case SERVICE_NETWORK_REMOVED:
472 removeGateway(snet.serviceIp());
473 break;
474 case SERVICE_PORT_CREATED:
475 case SERVICE_PORT_UPDATED:
476 case SERVICE_PORT_REMOVED:
477 default:
478 // do nothing for the other events
479 break;
480 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700481 }
482 }
483
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900484 private void readPublicGateways() {
485 CordVtnConfig config = netConfigService.getConfig(appId, CordVtnConfig.class);
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700486 if (config == null) {
Hyunsun Moon2c3f0ee2017-04-06 16:47:21 +0900487 log.warn("No configuration found");
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700488 return;
489 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700490
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900491 config.publicGateways().entrySet().forEach(entry -> {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700492 addGateway(entry.getKey(), entry.getValue());
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700493 });
494 // TODO send gratuitous arp in case the MAC is changed
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700495 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700496
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700497 private class InternalConfigListener implements NetworkConfigListener {
498
499 @Override
Hyunsun Moon4302c2b2017-01-19 14:20:34 +0900500 public boolean isRelevant(NetworkConfigEvent event) {
501 return event.configClass().equals(CordVtnConfig.class);
502 }
503
504 @Override
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700505 public void event(NetworkConfigEvent event) {
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700506
507 switch (event.type()) {
508 case CONFIG_ADDED:
509 case CONFIG_UPDATED:
Hyunsun Moonbcf49252017-02-21 22:28:41 +0900510 readPublicGateways();
Hyunsun Mooneaf75e62016-09-27 16:40:23 -0700511 break;
512 default:
513 break;
514 }
515 }
Hyunsun Moon5401aaa2016-06-12 17:40:34 -0700516 }
Hyunsun Moon022272f2016-01-11 15:30:42 -0800517}