blob: 4a19309003d95028874ca61ea4a507e4097ab7fa [file] [log] [blame]
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001/*
Jian Li8e7e6cd2018-03-30 13:33:08 +09002 * Copyright 2016-present Open Networking Foundation
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 */
Hyunsun Moon05400872017-02-07 17:11:25 +090016package org.onosproject.openstacknetworking.impl;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070017
Hyunsun Moonb974fca2016-06-30 21:20:39 -070018import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090019import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070020import org.onlab.packet.Ethernet;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
Daniel Park8a9220f2018-11-19 18:58:35 +090024import org.onlab.packet.VlanId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070025import org.onlab.util.Tools;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090027import org.onosproject.cfg.ConfigProperty;
Jian Lieae12362018-04-10 18:48:32 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Jian Lieae12362018-04-10 18:48:32 +090033import org.onosproject.mastership.MastershipService;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070037import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070039import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.packet.DefaultOutboundPacket;
41import org.onosproject.net.packet.PacketContext;
42import org.onosproject.net.packet.PacketProcessor;
43import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090045import org.onosproject.openstacknetworking.api.InstancePortEvent;
46import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090049import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
50import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
51import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090052import org.onosproject.openstacknode.api.OpenstackNode;
53import org.onosproject.openstacknode.api.OpenstackNodeEvent;
54import org.onosproject.openstacknode.api.OpenstackNodeListener;
55import org.onosproject.openstacknode.api.OpenstackNodeService;
56import org.openstack4j.model.network.Network;
57import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070059import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Modified;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090068
Hyunsun Moonb974fca2016-06-30 21:20:39 -070069import java.nio.ByteBuffer;
70import java.util.Dictionary;
Jian Lieae12362018-04-10 18:48:32 +090071import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070072import java.util.Set;
Jian Li32b03622018-11-06 17:54:24 +090073import java.util.concurrent.ExecutorService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070074
75import static com.google.common.base.Preconditions.checkNotNull;
Jian Li32b03622018-11-06 17:54:24 +090076import static java.util.concurrent.Executors.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
Jian Lieae12362018-04-10 18:48:32 +090078import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
79import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li5c09e212018-10-24 18:23:58 +090080import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090082import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li5c09e212018-10-24 18:23:58 +090083import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_FLOOD_RULE;
Jian Lieae12362018-04-10 18:48:32 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
85import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
86import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
Jian Lic2403592018-07-18 12:56:45 +090087import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Ray Milkey8e406512018-10-24 15:56:50 -070088import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
89import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
90import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
91import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +090092import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090093import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Lieae12362018-04-10 18:48:32 +090094import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
95import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070096
97/**
98 * Handles ARP packet from VMs.
99 */
Ray Milkey8e406512018-10-24 15:56:50 -0700100@Component(
101 immediate = true,
102 property = {
103 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900104 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700105 }
106)
Jian Li6a47fd02018-11-27 21:51:03 +0900107public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700108
109 private final Logger log = LoggerFactory.getLogger(getClass());
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900112 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900115 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900118 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900121 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900124 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900127 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900130 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900133 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900136 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900139 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900142 protected OpenstackNodeService osNodeService;
143
Ray Milkey8e406512018-10-24 15:56:50 -0700144 /** Fake MAC address for virtual network subnet gateway. */
145 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700146
Ray Milkey8e406512018-10-24 15:56:50 -0700147 /** ARP processing mode, broadcast | proxy (default). */
148 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900149
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700150 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151 private final InternalOpenstackNetworkListener osNetworkListener =
152 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900153 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
154 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
155
Jian Li32b03622018-11-06 17:54:24 +0900156 private final ExecutorService eventExecutor = newSingleThreadExecutor(
157 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
158
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159
160 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900161 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700162
163 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800164 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
166 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900167 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900168 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900169 osNodeService.addListener(osNodeListener);
170 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700171 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900172
173 instancePortService.addListener(instancePortListener);
174
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700176 }
177
178 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800179 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700180 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900182 osNodeService.removeListener(osNodeListener);
183 instancePortService.removeListener(instancePortListener);
184 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900186 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187
188 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700189 }
190
191 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800192 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900193 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900194
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700195 log.info("Modified");
196 }
197
Jian Li7f70bb72018-07-06 23:35:30 +0900198 private String getArpMode() {
199 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
200 return getPropertyValue(properties, ARP_MODE);
201 }
202
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700203 /**
204 * Processes ARP request packets.
205 * It checks if the target IP is owned by a known host first and then ask to
206 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
207 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700209 * @param ethPacket ethernet packet
210 */
211 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900212
213 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900214 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900215 return;
216 }
217
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700218 ARP arpPacket = (ARP) ethPacket.getPayload();
219 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
220 return;
221 }
222
Hyunsun Moon44aac662017-02-18 02:07:01 +0900223 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
224 if (srcInstPort == null) {
225 log.trace("Failed to find source instance port(MAC:{})",
226 ethPacket.getSourceMAC());
227 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700228 }
229
Hyunsun Moon44aac662017-02-18 02:07:01 +0900230 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900231
Jian Liac30e272018-10-18 23:08:03 +0900232 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700234 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900235 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700236 return;
237 }
238
239 Ethernet ethReply = ARP.buildArpReply(
240 targetIp.getIp4Address(),
241 replyMac,
242 ethPacket);
243
244 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
245 .setOutput(context.inPacket().receivedFrom().port())
246 .build();
247
248 packetService.emit(new DefaultOutboundPacket(
249 context.inPacket().receivedFrom().deviceId(),
250 treatment,
251 ByteBuffer.wrap(ethReply.serialize())));
252 }
253
Jian Liac30e272018-10-18 23:08:03 +0900254 /**
255 * Denotes whether the given target IP is gateway IP.
256 *
257 * @param targetIp target IP address
258 * @return true if the given targetIP is gateway IP, false otherwise.
259 */
260 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900261 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900262 .filter(Objects::nonNull)
263 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900264 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
265 }
266
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700267 /**
268 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700270 *
271 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900272 * @param osNetId openstack network id of the source instance port
273 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700274 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700276 checkNotNull(targetIp);
277
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
279 if (instPort != null) {
280 log.trace("Found MAC from host service for {}", targetIp);
281 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700282 } else {
283 return MacAddress.NONE;
284 }
285 }
286
Jian Lieae12362018-04-10 18:48:32 +0900287 /**
Daniel Park613ac372018-06-28 14:30:11 +0900288 * Installs flow rules which convert ARP request packet into ARP reply
289 * by adding a fake gateway MAC address as Source Hardware Address.
290 *
291 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900292 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900293 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900294 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900295 */
Jian Li5b155bf2018-11-21 18:16:26 +0900296 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
297 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900298
Jian Li7f70bb72018-07-06 23:35:30 +0900299 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900300
Daniel Park613ac372018-06-28 14:30:11 +0900301 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900302 if (gateway == null) {
303 return;
304 }
Daniel Park613ac372018-06-28 14:30:11 +0900305
Daniel Park8a9220f2018-11-19 18:58:35 +0900306 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
307 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900308
Jian Li5b155bf2018-11-21 18:16:26 +0900309 if (NetworkType.VLAN == network.getNetworkType()) {
310 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Daniel Park8a9220f2018-11-19 18:58:35 +0900311 tBuilder.popVlan();
Jian Li5b155bf2018-11-21 18:16:26 +0900312 } else if (NetworkType.VXLAN == network.getNetworkType()) {
313 // do not remove fake gateway ARP rules, if there is another gateway
314 // which has the same subnet that to be removed
315 // this only occurs if we have duplicated subnets associated with
316 // different networks
317 if (!install) {
318 long numOfDupGws = osNetworkService.subnets().stream()
319 .filter(s -> !s.getId().equals(osSubnet.getId()))
320 .filter(s -> s.getGateway() != null)
321 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
322 .count();
323 if (numOfDupGws > 0) {
324 return;
325 }
326 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900327 }
328
329 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
330 .matchArpOp(ARP.OP_REQUEST)
331 .matchArpTpa(Ip4Address.valueOf(gateway));
332
333 tBuilder.setArpOp(ARP.OP_REPLY)
Daniel Park613ac372018-06-28 14:30:11 +0900334 .setArpSha(MacAddress.valueOf(gatewayMac))
335 .setArpSpa(Ip4Address.valueOf(gateway))
Daniel Park8a9220f2018-11-19 18:58:35 +0900336 .setOutput(PortNumber.IN_PORT);
Daniel Park613ac372018-06-28 14:30:11 +0900337
338 if (osNode == null) {
339 osNodeService.completeNodes(COMPUTE).forEach(n ->
340 osFlowRuleService.setRule(
341 appId,
342 n.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900343 sBuilder.build(),
344 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900345 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900346 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900347 install
348 )
349 );
350 } else {
351 osFlowRuleService.setRule(
352 appId,
353 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900354 sBuilder.build(),
355 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900356 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900357 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900358 install
359 );
360 }
361
362 }
363 }
364
365 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900366 * Installs flow rules to match ARP request packets.
367 *
368 * @param port instance port
369 * @param install installation flag
370 */
371 private void setArpRequestRule(InstancePort port, boolean install) {
372 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
373
374 switch (type) {
375 case VXLAN:
376 setRemoteArpRequestRuleForVxlan(port, install);
377 break;
378 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900379 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900380 break;
381 default:
382 break;
383 }
384 }
385
386 /**
387 * Installs flow rules to match ARP reply packets.
388 *
389 * @param port instance port
390 * @param install installation flag
391 */
392 private void setArpReplyRule(InstancePort port, boolean install) {
393 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
394
395 switch (type) {
396 case VXLAN:
397 setArpReplyRuleForVxlan(port, install);
398 break;
399 case VLAN:
400 setArpReplyRuleForVlan(port, install);
401 break;
402 default:
403 break;
404 }
405 }
406
407 /**
408 * Installs flow rules to match ARP request packets only for VxLAN.
409 *
410 * @param port instance port
411 * @param install installation flag
412 */
413 private void setRemoteArpRequestRuleForVxlan(InstancePort port, boolean install) {
414
415 OpenstackNode localNode = osNodeService.node(port.deviceId());
416
Jian Li5c09e212018-10-24 18:23:58 +0900417 String segId = osNetworkService.segmentId(port.networkId());
418
Jian Li7f70bb72018-07-06 23:35:30 +0900419 TrafficSelector selector = DefaultTrafficSelector.builder()
420 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
421 .matchArpOp(ARP.OP_REQUEST)
422 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900423 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900424 .build();
425
426 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
427 }
428
429 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900430 * Installs flow rules to match ARP request packets for VLAN.
431 *
432 * @param port instance port
433 * @param install installation flag
434 */
435 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
436 TrafficSelector selector = getArpRequestSelectorForVlan(port);
437
438 setLocalArpRequestTreatmentForVlan(selector, port, install);
439 setRemoteArpRequestTreatmentForVlan(selector, port, install);
440 }
441
442 /**
443 * Obtains the ARP request selector for VLAN.
444 *
445 * @param port instance port
446 * @return traffic selector
447 */
448 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
449 String segId = osNetworkService.segmentId(port.networkId());
450
451 return DefaultTrafficSelector.builder()
452 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
453 .matchArpOp(ARP.OP_REQUEST)
454 .matchArpTpa(port.ipAddress().getIp4Address())
455 .matchVlanId(VlanId.vlanId(segId))
456 .build();
457 }
458
459 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900460 * Installs flow rules to match ARP reply packets only for VxLAN.
461 *
462 * @param port instance port
463 * @param install installation flag
464 */
465 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
466
467 OpenstackNode localNode = osNodeService.node(port.deviceId());
468
Jian Li5b155bf2018-11-21 18:16:26 +0900469 TrafficSelector selector = getArpReplySelectorForVxlan(port);
470
471 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900472 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
473 }
474
475 /**
476 * Installs flow rules to match ARP reply packets only for VLAN.
477 *
478 * @param port instance port
479 * @param install installation flag
480 */
481 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
482
Jian Li5b155bf2018-11-21 18:16:26 +0900483 TrafficSelector selector = getArpReplySelectorForVlan(port);
484
485 setLocalArpReplyTreatmentForVlan(selector, port, install);
486 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900487 }
488
489 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900490 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
491 return getArpReplySelectorForVnet(port, NetworkType.VXLAN);
492 }
493
494 // a helper method
495 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
496 return getArpReplySelectorForVnet(port, NetworkType.VLAN);
497 }
498
499 // a helper method
500 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
501 NetworkType type) {
502
503 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
504
505 if (type == NetworkType.VLAN) {
506 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
507 sBuilder.matchVlanId(VlanId.vlanId(segId));
508 }
509
510 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900511 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
512 .matchArpOp(ARP.OP_REPLY)
513 .matchArpTpa(port.ipAddress().getIp4Address())
514 .matchArpTha(port.macAddress())
515 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900516 }
Jian Li7f70bb72018-07-06 23:35:30 +0900517
Jian Li5b155bf2018-11-21 18:16:26 +0900518 // a helper method
519 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
520 InstancePort port,
521 boolean install) {
522 setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VXLAN, install);
523 }
524
525 // a helper method
526 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
527 InstancePort port,
528 boolean install) {
529 setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VLAN, install);
530 }
531
532 // a helper method
533 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
534 InstancePort port,
535 NetworkType type,
536 boolean install) {
537 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
538
539 if (type == NetworkType.VLAN) {
540 tBuilder.popVlan();
541 }
542
543 tBuilder.setOutput(port.portNumber());
544
545 osFlowRuleService.setRule(
546 appId,
547 port.deviceId(),
548 selector,
549 tBuilder.build(),
550 PRIORITY_ARP_REPLY_RULE,
551 ARP_TABLE,
552 install
553 );
554 }
555
556 // a helper method
557 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
558 InstancePort port,
559 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900560 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900561 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900562 .setOutput(port.portNumber())
563 .build();
564
565 osFlowRuleService.setRule(
566 appId,
567 port.deviceId(),
568 selector,
569 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900570 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900571 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900572 install
573 );
Jian Li7f70bb72018-07-06 23:35:30 +0900574 }
575
576 // a helper method
577 private void setRemoteArpTreatmentForVxlan(TrafficSelector selector,
578 InstancePort port,
579 OpenstackNode localNode,
580 boolean install) {
581 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
582 if (!remoteNode.intgBridge().equals(port.deviceId())) {
583 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
584 .extension(buildExtension(
585 deviceService,
586 remoteNode.intgBridge(),
587 localNode.dataIp().getIp4Address()),
588 remoteNode.intgBridge())
589 .setOutput(remoteNode.tunnelPortNum())
590 .build();
591
592 osFlowRuleService.setRule(
593 appId,
594 remoteNode.intgBridge(),
595 selector,
596 treatmentToRemote,
597 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900598 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900599 install
600 );
601 }
602 }
603 }
604
605 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900606 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
607 InstancePort port,
608 boolean install) {
609 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
610 }
611
612 // a helper method
613 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
614 InstancePort port,
615 boolean install) {
616 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
617 }
618
619 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900620 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
621 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900622 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900623 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900624
625 int priority;
626 if (arpOp == ARP.OP_REQUEST) {
627 priority = PRIORITY_ARP_REQUEST_RULE;
628 } else if (arpOp == ARP.OP_REPLY) {
629 priority = PRIORITY_ARP_REPLY_RULE;
630 } else {
631 // if ARP op does not match with any operation mode, we simply
632 // configure the ARP request rule priority
633 priority = PRIORITY_ARP_REQUEST_RULE;
634 }
635
Jian Li7f70bb72018-07-06 23:35:30 +0900636 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900637 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
638 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900639 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
640 .setOutput(remoteNode.vlanPortNum())
641 .build();
642
643 osFlowRuleService.setRule(
644 appId,
645 remoteNode.intgBridge(),
646 selector,
647 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900648 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900649 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900650 install);
651 }
652 }
653 }
654
655 /**
656 * Extracts properties from the component configuration context.
657 *
658 * @param context the component context
659 */
660 private void readComponentConfiguration(ComponentContext context) {
661 Dictionary<?, ?> properties = context.getProperties();
662
663 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700664 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900665 log.info("Configured. Gateway MAC is {}", gatewayMac);
666 }
667
668 /**
Jian Lieae12362018-04-10 18:48:32 +0900669 * An internal packet processor which processes ARP request, and results in
670 * packet-out ARP reply.
671 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700672 private class InternalPacketProcessor implements PacketProcessor {
673
674 @Override
675 public void process(PacketContext context) {
676 if (context.isHandled()) {
677 return;
678 }
679
680 Ethernet ethPacket = context.inPacket().parsed();
681 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
682 return;
683 }
Jian Li32b03622018-11-06 17:54:24 +0900684
685 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700686 }
687 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900688
Jian Lieae12362018-04-10 18:48:32 +0900689 /**
690 * An internal network listener which listens to openstack network event,
691 * manages the gateway collection and installs flow rule that handles
692 * ARP request in data plane.
693 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900694 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
695
696 @Override
697 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900698 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900699
Jian Lieae12362018-04-10 18:48:32 +0900700 if (network == null) {
701 log.warn("Network is not specified.");
702 return false;
703 } else {
Jian Li5b155bf2018-11-21 18:16:26 +0900704 return network.getNetworkType() != NetworkType.FLAT;
Jian Lieae12362018-04-10 18:48:32 +0900705 }
Jian Li5b155bf2018-11-21 18:16:26 +0900706 }
Jian Lieae12362018-04-10 18:48:32 +0900707
Jian Li5b155bf2018-11-21 18:16:26 +0900708 private boolean isRelevantHelper() {
709 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900710 }
711
712 @Override
713 public void event(OpenstackNetworkEvent event) {
714 switch (event.type()) {
715 case OPENSTACK_SUBNET_CREATED:
716 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900717 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900718 break;
719 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900720 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900721 break;
722 case OPENSTACK_NETWORK_CREATED:
723 case OPENSTACK_NETWORK_UPDATED:
724 case OPENSTACK_NETWORK_REMOVED:
725 case OPENSTACK_PORT_CREATED:
726 case OPENSTACK_PORT_UPDATED:
727 case OPENSTACK_PORT_REMOVED:
728 default:
729 // do nothing for the other events
730 break;
731 }
732 }
Jian Li6a47fd02018-11-27 21:51:03 +0900733
734 private void processSubnetCreation(OpenstackNetworkEvent event) {
735 if (!isRelevantHelper()) {
736 return;
737 }
738
739 setFakeGatewayArpRule(event.subnet(), event.subject(),
740 true, null);
741 }
742
743 private void processSubnetRemoval(OpenstackNetworkEvent event) {
744 if (!isRelevantHelper()) {
745 return;
746 }
747
748 setFakeGatewayArpRule(event.subnet(), event.subject(),
749 false, null);
750 }
Jian Lieae12362018-04-10 18:48:32 +0900751 }
752
753 /**
754 * An internal openstack node listener which is used for listening openstack
755 * node activity. As long as a node is in complete state, we will install
756 * default ARP rule to handle ARP request.
757 */
758 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900759 @Override
760 public boolean isRelevant(OpenstackNodeEvent event) {
761 return event.subject().type() == COMPUTE;
762 }
763
Jian Li34220ea2018-11-14 01:30:24 +0900764 private boolean isRelevantHelper() {
765 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900766 }
767
768 @Override
769 public void event(OpenstackNodeEvent event) {
770 OpenstackNode osNode = event.subject();
771 switch (event.type()) {
772 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900773 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900774 break;
775 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900776 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900777 break;
Jian Lieae12362018-04-10 18:48:32 +0900778 default:
779 break;
780 }
781 }
782
Jian Li6a47fd02018-11-27 21:51:03 +0900783 private void processNodeCompletion(OpenstackNode osNode) {
784 if (!isRelevantHelper()) {
785 return;
786 }
787
788 setDefaultArpRule(osNode, true);
789 setAllArpRules(osNode, true);
790 }
791
792 private void processNodeIncompletion(OpenstackNode osNode) {
793 if (!isRelevantHelper()) {
794 return;
795 }
796
797 setDefaultArpRule(osNode, false);
798 setAllArpRules(osNode, false);
799 }
800
Jian Lif96685c2018-05-21 14:14:16 +0900801 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900802
803 if (getArpMode() == null) {
804 return;
805 }
806
Jian Li7f70bb72018-07-06 23:35:30 +0900807 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900808 case ARP_PROXY_MODE:
809 setDefaultArpRuleForProxyMode(osNode, install);
810 break;
811 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900812 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900813 break;
814 default:
815 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900816 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900817 break;
Jian Lieae12362018-04-10 18:48:32 +0900818 }
819 }
Jian Lif96685c2018-05-21 14:14:16 +0900820
Jian Li6a47fd02018-11-27 21:51:03 +0900821 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
822 boolean install) {
823 setDefaultArpRuleForBroadcastMode(osNode, install);
824
825 // we do not add fake gateway ARP rules for FLAT network
826 // ARP packets generated by FLAT typed VM should not be
827 // delegated to switch to handle
828 osNetworkService.subnets().stream().filter(subnet ->
829 osNetworkService.network(subnet.getNetworkId()) != null &&
830 osNetworkService.network(subnet.getNetworkId())
831 .getNetworkType() != NetworkType.FLAT)
832 .forEach(subnet -> {
833 String netId = subnet.getNetworkId();
834 Network net = osNetworkService.network(netId);
835 setFakeGatewayArpRule(subnet, net, install, osNode);
836 });
837 }
838
Jian Lif96685c2018-05-21 14:14:16 +0900839 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
840 TrafficSelector selector = DefaultTrafficSelector.builder()
841 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
842 .build();
843
844 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
845 .punt()
846 .build();
847
848 osFlowRuleService.setRule(
849 appId,
850 osNode.intgBridge(),
851 selector,
852 treatment,
853 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900854 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900855 install
856 );
857 }
858
859 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
860 TrafficSelector selector = DefaultTrafficSelector.builder()
861 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
862 .matchArpOp(ARP.OP_REQUEST)
863 .build();
864
865 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
866 .setOutput(PortNumber.FLOOD)
867 .build();
868
869 osFlowRuleService.setRule(
870 appId,
871 osNode.intgBridge(),
872 selector,
873 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900874 PRIORITY_ARP_FLOOD_RULE,
875 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900876 install
877 );
878 }
Jian Li7f70bb72018-07-06 23:35:30 +0900879
Jian Li5b66ce02018-07-09 22:43:54 +0900880 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900881 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900882 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900883 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900884 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
885 .forEach(p -> {
886 setArpRequestRule(p, install);
887 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900888 });
889 }
890 }
Jian Lieae12362018-04-10 18:48:32 +0900891 }
892
893 /**
894 * An internal instance port listener which listens the port events generated
895 * from VM. When ARP a host which located in a remote compute node, we specify
896 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
897 * host IP address. When ARP a host which located in a local compute node,
898 * we specify only ARP OP mode as REQUEST.
899 */
900 private class InternalInstancePortListener implements InstancePortListener {
901
902 @Override
903 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900904 return ARP_BROADCAST_MODE.equals(getArpMode());
905 }
Jian Lieae12362018-04-10 18:48:32 +0900906
Jian Li34220ea2018-11-14 01:30:24 +0900907 private boolean isRelevantHelper(InstancePortEvent event) {
908 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +0900909 }
910
911 @Override
912 public void event(InstancePortEvent event) {
913 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +0900914 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900915 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +0900916 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +0900917 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +0900918 break;
919 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +0900920 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +0900921 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900922 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +0900923 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900924 break;
Jian Lieae12362018-04-10 18:48:32 +0900925 default:
926 break;
927 }
928 }
Jian Li6a47fd02018-11-27 21:51:03 +0900929
930 private void processInstanceMigrationStart(InstancePortEvent event) {
931 if (!isRelevantHelper(event)) {
932 return;
933 }
934
935 setArpRequestRule(event.subject(), true);
936 setArpReplyRule(event.subject(), true);
937 }
938
939 private void processInstanceMigrationEnd(InstancePortEvent event) {
940 if (!isRelevantHelper(event)) {
941 return;
942 }
943
944 InstancePort revisedInstPort = swapStaleLocation(event.subject());
945 setArpRequestRule(revisedInstPort, false);
946 }
947
948 private void processInstanceRemoval(InstancePortEvent event) {
949 if (!isRelevantHelper(event)) {
950 return;
951 }
952
953 setArpRequestRule(event.subject(), false);
954 setArpReplyRule(event.subject(), false);
955 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900956 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700957}