blob: 3670390c799c7227c39fc36e2441c96f5fa3e875 [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 Li2d68c192018-12-13 15:52:59 +090094import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +090095import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
96import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070097
98/**
99 * Handles ARP packet from VMs.
100 */
Ray Milkey8e406512018-10-24 15:56:50 -0700101@Component(
102 immediate = true,
103 property = {
104 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900105 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700106 }
107)
Jian Li6a47fd02018-11-27 21:51:03 +0900108public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700109
110 private final Logger log = LoggerFactory.getLogger(getClass());
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900113 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900116 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900119 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900122 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900125 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900128 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900131 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900134 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900137 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900140 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900143 protected OpenstackNodeService osNodeService;
144
Ray Milkey8e406512018-10-24 15:56:50 -0700145 /** Fake MAC address for virtual network subnet gateway. */
146 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700147
Ray Milkey8e406512018-10-24 15:56:50 -0700148 /** ARP processing mode, broadcast | proxy (default). */
149 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900150
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700151 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900152 private final InternalOpenstackNetworkListener osNetworkListener =
153 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900154 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
155 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
156
Jian Li32b03622018-11-06 17:54:24 +0900157 private final ExecutorService eventExecutor = newSingleThreadExecutor(
158 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
159
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160
161 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900162 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700163
164 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800165 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900166 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
167 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900168 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900170 osNodeService.addListener(osNodeListener);
171 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700172 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900173
174 instancePortService.addListener(instancePortListener);
175
Hyunsun Moon44aac662017-02-18 02:07:01 +0900176 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700177 }
178
179 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800180 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700181 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900183 osNodeService.removeListener(osNodeListener);
184 instancePortService.removeListener(instancePortListener);
185 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900187 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188
189 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700190 }
191
192 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800193 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900194 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900195
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700196 log.info("Modified");
197 }
198
Jian Li7f70bb72018-07-06 23:35:30 +0900199 private String getArpMode() {
200 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
201 return getPropertyValue(properties, ARP_MODE);
202 }
203
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700204 /**
205 * Processes ARP request packets.
206 * It checks if the target IP is owned by a known host first and then ask to
207 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
208 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900209 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700210 * @param ethPacket ethernet packet
211 */
212 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900213
214 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900215 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900216 return;
217 }
218
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700219 ARP arpPacket = (ARP) ethPacket.getPayload();
220 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
221 return;
222 }
223
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
225 if (srcInstPort == null) {
226 log.trace("Failed to find source instance port(MAC:{})",
227 ethPacket.getSourceMAC());
228 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700229 }
230
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900232
Jian Liac30e272018-10-18 23:08:03 +0900233 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900234 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700235 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700237 return;
238 }
239
240 Ethernet ethReply = ARP.buildArpReply(
241 targetIp.getIp4Address(),
242 replyMac,
243 ethPacket);
244
245 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
246 .setOutput(context.inPacket().receivedFrom().port())
247 .build();
248
249 packetService.emit(new DefaultOutboundPacket(
250 context.inPacket().receivedFrom().deviceId(),
251 treatment,
252 ByteBuffer.wrap(ethReply.serialize())));
253 }
254
Jian Liac30e272018-10-18 23:08:03 +0900255 /**
256 * Denotes whether the given target IP is gateway IP.
257 *
258 * @param targetIp target IP address
259 * @return true if the given targetIP is gateway IP, false otherwise.
260 */
261 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900262 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900263 .filter(Objects::nonNull)
264 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900265 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
266 }
267
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700268 /**
269 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700271 *
272 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900273 * @param osNetId openstack network id of the source instance port
274 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700275 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700277 checkNotNull(targetIp);
278
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
280 if (instPort != null) {
281 log.trace("Found MAC from host service for {}", targetIp);
282 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700283 } else {
284 return MacAddress.NONE;
285 }
286 }
287
Jian Lieae12362018-04-10 18:48:32 +0900288 /**
Daniel Park613ac372018-06-28 14:30:11 +0900289 * Installs flow rules which convert ARP request packet into ARP reply
290 * by adding a fake gateway MAC address as Source Hardware Address.
291 *
292 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900293 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900294 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900295 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900296 */
Jian Li5b155bf2018-11-21 18:16:26 +0900297 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
298 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900299
Jian Li7f70bb72018-07-06 23:35:30 +0900300 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900301
Daniel Park613ac372018-06-28 14:30:11 +0900302 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900303 if (gateway == null) {
304 return;
305 }
Daniel Park613ac372018-06-28 14:30:11 +0900306
Daniel Park8a9220f2018-11-19 18:58:35 +0900307 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
308 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900309
Jian Li5b155bf2018-11-21 18:16:26 +0900310 if (NetworkType.VLAN == network.getNetworkType()) {
311 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Daniel Park8a9220f2018-11-19 18:58:35 +0900312 tBuilder.popVlan();
Jian Li2d68c192018-12-13 15:52:59 +0900313 } else if (NetworkType.VXLAN == network.getNetworkType() ||
314 NetworkType.GRE == network.getNetworkType()) {
Jian Li5b155bf2018-11-21 18:16:26 +0900315 // do not remove fake gateway ARP rules, if there is another gateway
316 // which has the same subnet that to be removed
317 // this only occurs if we have duplicated subnets associated with
318 // different networks
319 if (!install) {
320 long numOfDupGws = osNetworkService.subnets().stream()
321 .filter(s -> !s.getId().equals(osSubnet.getId()))
322 .filter(s -> s.getGateway() != null)
323 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
324 .count();
325 if (numOfDupGws > 0) {
326 return;
327 }
328 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900329 }
330
331 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
332 .matchArpOp(ARP.OP_REQUEST)
333 .matchArpTpa(Ip4Address.valueOf(gateway));
334
335 tBuilder.setArpOp(ARP.OP_REPLY)
Daniel Park613ac372018-06-28 14:30:11 +0900336 .setArpSha(MacAddress.valueOf(gatewayMac))
337 .setArpSpa(Ip4Address.valueOf(gateway))
Daniel Park8a9220f2018-11-19 18:58:35 +0900338 .setOutput(PortNumber.IN_PORT);
Daniel Park613ac372018-06-28 14:30:11 +0900339
340 if (osNode == null) {
341 osNodeService.completeNodes(COMPUTE).forEach(n ->
342 osFlowRuleService.setRule(
343 appId,
344 n.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900345 sBuilder.build(),
346 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900347 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900348 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900349 install
350 )
351 );
352 } else {
353 osFlowRuleService.setRule(
354 appId,
355 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900356 sBuilder.build(),
357 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900358 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900359 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900360 install
361 );
362 }
363
364 }
365 }
366
367 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900368 * Installs flow rules to match ARP request packets.
369 *
370 * @param port instance port
371 * @param install installation flag
372 */
373 private void setArpRequestRule(InstancePort port, boolean install) {
374 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
375
376 switch (type) {
377 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900378 case GRE:
379 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900380 break;
381 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900382 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900383 break;
384 default:
385 break;
386 }
387 }
388
389 /**
390 * Installs flow rules to match ARP reply packets.
391 *
392 * @param port instance port
393 * @param install installation flag
394 */
395 private void setArpReplyRule(InstancePort port, boolean install) {
396 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
397
398 switch (type) {
399 case VXLAN:
400 setArpReplyRuleForVxlan(port, install);
401 break;
Jian Li2d68c192018-12-13 15:52:59 +0900402 case GRE:
403 setArpReplyRuleForGre(port, install);
404 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900405 case VLAN:
406 setArpReplyRuleForVlan(port, install);
407 break;
408 default:
409 break;
410 }
411 }
412
413 /**
414 * Installs flow rules to match ARP request packets only for VxLAN.
415 *
416 * @param port instance port
417 * @param install installation flag
418 */
Jian Li2d68c192018-12-13 15:52:59 +0900419 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900420
421 OpenstackNode localNode = osNodeService.node(port.deviceId());
422
Jian Li5c09e212018-10-24 18:23:58 +0900423 String segId = osNetworkService.segmentId(port.networkId());
424
Jian Li7f70bb72018-07-06 23:35:30 +0900425 TrafficSelector selector = DefaultTrafficSelector.builder()
426 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
427 .matchArpOp(ARP.OP_REQUEST)
428 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900429 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900430 .build();
431
Jian Li2d68c192018-12-13 15:52:59 +0900432 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900433 }
434
435 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900436 * Installs flow rules to match ARP request packets for VLAN.
437 *
438 * @param port instance port
439 * @param install installation flag
440 */
441 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
442 TrafficSelector selector = getArpRequestSelectorForVlan(port);
443
444 setLocalArpRequestTreatmentForVlan(selector, port, install);
445 setRemoteArpRequestTreatmentForVlan(selector, port, install);
446 }
447
448 /**
449 * Obtains the ARP request selector for VLAN.
450 *
451 * @param port instance port
452 * @return traffic selector
453 */
454 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
455 String segId = osNetworkService.segmentId(port.networkId());
456
457 return DefaultTrafficSelector.builder()
458 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
459 .matchArpOp(ARP.OP_REQUEST)
460 .matchArpTpa(port.ipAddress().getIp4Address())
461 .matchVlanId(VlanId.vlanId(segId))
462 .build();
463 }
464
465 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900466 * Installs flow rules to match ARP reply packets only for VxLAN.
467 *
468 * @param port instance port
469 * @param install installation flag
470 */
471 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
472
473 OpenstackNode localNode = osNodeService.node(port.deviceId());
474
Jian Li5b155bf2018-11-21 18:16:26 +0900475 TrafficSelector selector = getArpReplySelectorForVxlan(port);
476
477 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900478 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
479 }
480
481 /**
482 * Installs flow rules to match ARP reply packets only for GRE.
483 *
484 * @param port instance port
485 * @param install installation flag
486 */
487 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
488
489 OpenstackNode localNode = osNodeService.node(port.deviceId());
490
491 TrafficSelector selector = getArpReplySelectorForGre(port);
492
493 setLocalArpReplyTreatmentForGre(selector, port, install);
494 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900495 }
496
497 /**
498 * Installs flow rules to match ARP reply packets only for VLAN.
499 *
500 * @param port instance port
501 * @param install installation flag
502 */
503 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
504
Jian Li5b155bf2018-11-21 18:16:26 +0900505 TrafficSelector selector = getArpReplySelectorForVlan(port);
506
507 setLocalArpReplyTreatmentForVlan(selector, port, install);
508 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900509 }
510
511 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900512 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
513 return getArpReplySelectorForVnet(port, NetworkType.VXLAN);
514 }
515
516 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900517 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
518 return getArpReplySelectorForVnet(port, NetworkType.GRE);
519 }
520
521 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900522 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
523 return getArpReplySelectorForVnet(port, NetworkType.VLAN);
524 }
525
526 // a helper method
527 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
528 NetworkType type) {
529
530 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
531
532 if (type == NetworkType.VLAN) {
533 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
534 sBuilder.matchVlanId(VlanId.vlanId(segId));
535 }
536
537 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900538 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
539 .matchArpOp(ARP.OP_REPLY)
540 .matchArpTpa(port.ipAddress().getIp4Address())
541 .matchArpTha(port.macAddress())
542 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900543 }
Jian Li7f70bb72018-07-06 23:35:30 +0900544
Jian Li5b155bf2018-11-21 18:16:26 +0900545 // a helper method
546 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
547 InstancePort port,
548 boolean install) {
549 setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VXLAN, install);
550 }
551
552 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900553 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
554 InstancePort port,
555 boolean install) {
556 setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.GRE, install);
557 }
558
559 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900560 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
561 InstancePort port,
562 boolean install) {
563 setLocalArpReplyTreatmentForVnet(selector, port, NetworkType.VLAN, install);
564 }
565
566 // a helper method
567 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
568 InstancePort port,
569 NetworkType type,
570 boolean install) {
571 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
572
573 if (type == NetworkType.VLAN) {
574 tBuilder.popVlan();
575 }
576
577 tBuilder.setOutput(port.portNumber());
578
579 osFlowRuleService.setRule(
580 appId,
581 port.deviceId(),
582 selector,
583 tBuilder.build(),
584 PRIORITY_ARP_REPLY_RULE,
585 ARP_TABLE,
586 install
587 );
588 }
589
590 // a helper method
591 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
592 InstancePort port,
593 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900594 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900595 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900596 .setOutput(port.portNumber())
597 .build();
598
599 osFlowRuleService.setRule(
600 appId,
601 port.deviceId(),
602 selector,
603 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900604 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900605 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900606 install
607 );
Jian Li7f70bb72018-07-06 23:35:30 +0900608 }
609
610 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900611 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
612 InstancePort port,
613 OpenstackNode localNode,
614 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900615 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
616 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900617
618 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
619 osNetworkService, remoteNode);
620
Jian Li7f70bb72018-07-06 23:35:30 +0900621 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900622 .extension(buildExtension(
623 deviceService,
624 remoteNode.intgBridge(),
625 localNode.dataIp().getIp4Address()),
626 remoteNode.intgBridge())
627 .setOutput(portNum)
628 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900629
630 osFlowRuleService.setRule(
631 appId,
632 remoteNode.intgBridge(),
633 selector,
634 treatmentToRemote,
635 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900636 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900637 install
638 );
639 }
640 }
641 }
642
643 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900644 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
645 InstancePort port,
646 boolean install) {
647 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
648 }
649
650 // a helper method
651 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
652 InstancePort port,
653 boolean install) {
654 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
655 }
656
657 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900658 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
659 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900660 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900661 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900662
663 int priority;
664 if (arpOp == ARP.OP_REQUEST) {
665 priority = PRIORITY_ARP_REQUEST_RULE;
666 } else if (arpOp == ARP.OP_REPLY) {
667 priority = PRIORITY_ARP_REPLY_RULE;
668 } else {
669 // if ARP op does not match with any operation mode, we simply
670 // configure the ARP request rule priority
671 priority = PRIORITY_ARP_REQUEST_RULE;
672 }
673
Jian Li7f70bb72018-07-06 23:35:30 +0900674 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900675 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
676 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900677 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
678 .setOutput(remoteNode.vlanPortNum())
679 .build();
680
681 osFlowRuleService.setRule(
682 appId,
683 remoteNode.intgBridge(),
684 selector,
685 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900686 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900687 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900688 install);
689 }
690 }
691 }
692
693 /**
694 * Extracts properties from the component configuration context.
695 *
696 * @param context the component context
697 */
698 private void readComponentConfiguration(ComponentContext context) {
699 Dictionary<?, ?> properties = context.getProperties();
700
701 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700702 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900703 log.info("Configured. Gateway MAC is {}", gatewayMac);
704 }
705
706 /**
Jian Lieae12362018-04-10 18:48:32 +0900707 * An internal packet processor which processes ARP request, and results in
708 * packet-out ARP reply.
709 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700710 private class InternalPacketProcessor implements PacketProcessor {
711
712 @Override
713 public void process(PacketContext context) {
714 if (context.isHandled()) {
715 return;
716 }
717
718 Ethernet ethPacket = context.inPacket().parsed();
719 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
720 return;
721 }
Jian Li32b03622018-11-06 17:54:24 +0900722
723 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700724 }
725 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900726
Jian Lieae12362018-04-10 18:48:32 +0900727 /**
728 * An internal network listener which listens to openstack network event,
729 * manages the gateway collection and installs flow rule that handles
730 * ARP request in data plane.
731 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900732 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
733
734 @Override
735 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900736 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900737
Jian Lieae12362018-04-10 18:48:32 +0900738 if (network == null) {
739 log.warn("Network is not specified.");
740 return false;
741 } else {
Jian Li5b155bf2018-11-21 18:16:26 +0900742 return network.getNetworkType() != NetworkType.FLAT;
Jian Lieae12362018-04-10 18:48:32 +0900743 }
Jian Li5b155bf2018-11-21 18:16:26 +0900744 }
Jian Lieae12362018-04-10 18:48:32 +0900745
Jian Li5b155bf2018-11-21 18:16:26 +0900746 private boolean isRelevantHelper() {
747 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900748 }
749
750 @Override
751 public void event(OpenstackNetworkEvent event) {
752 switch (event.type()) {
753 case OPENSTACK_SUBNET_CREATED:
754 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900755 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900756 break;
757 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900758 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900759 break;
760 case OPENSTACK_NETWORK_CREATED:
761 case OPENSTACK_NETWORK_UPDATED:
762 case OPENSTACK_NETWORK_REMOVED:
763 case OPENSTACK_PORT_CREATED:
764 case OPENSTACK_PORT_UPDATED:
765 case OPENSTACK_PORT_REMOVED:
766 default:
767 // do nothing for the other events
768 break;
769 }
770 }
Jian Li6a47fd02018-11-27 21:51:03 +0900771
772 private void processSubnetCreation(OpenstackNetworkEvent event) {
773 if (!isRelevantHelper()) {
774 return;
775 }
776
777 setFakeGatewayArpRule(event.subnet(), event.subject(),
778 true, null);
779 }
780
781 private void processSubnetRemoval(OpenstackNetworkEvent event) {
782 if (!isRelevantHelper()) {
783 return;
784 }
785
786 setFakeGatewayArpRule(event.subnet(), event.subject(),
787 false, null);
788 }
Jian Lieae12362018-04-10 18:48:32 +0900789 }
790
791 /**
792 * An internal openstack node listener which is used for listening openstack
793 * node activity. As long as a node is in complete state, we will install
794 * default ARP rule to handle ARP request.
795 */
796 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900797 @Override
798 public boolean isRelevant(OpenstackNodeEvent event) {
799 return event.subject().type() == COMPUTE;
800 }
801
Jian Li34220ea2018-11-14 01:30:24 +0900802 private boolean isRelevantHelper() {
803 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900804 }
805
806 @Override
807 public void event(OpenstackNodeEvent event) {
808 OpenstackNode osNode = event.subject();
809 switch (event.type()) {
810 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900811 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900812 break;
813 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900814 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900815 break;
Jian Lieae12362018-04-10 18:48:32 +0900816 default:
817 break;
818 }
819 }
820
Jian Li6a47fd02018-11-27 21:51:03 +0900821 private void processNodeCompletion(OpenstackNode osNode) {
822 if (!isRelevantHelper()) {
823 return;
824 }
825
826 setDefaultArpRule(osNode, true);
827 setAllArpRules(osNode, true);
828 }
829
830 private void processNodeIncompletion(OpenstackNode osNode) {
831 if (!isRelevantHelper()) {
832 return;
833 }
834
835 setDefaultArpRule(osNode, false);
836 setAllArpRules(osNode, false);
837 }
838
Jian Lif96685c2018-05-21 14:14:16 +0900839 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900840
841 if (getArpMode() == null) {
842 return;
843 }
844
Jian Li7f70bb72018-07-06 23:35:30 +0900845 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900846 case ARP_PROXY_MODE:
847 setDefaultArpRuleForProxyMode(osNode, install);
848 break;
849 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900850 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900851 break;
852 default:
853 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900854 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900855 break;
Jian Lieae12362018-04-10 18:48:32 +0900856 }
857 }
Jian Lif96685c2018-05-21 14:14:16 +0900858
Jian Li6a47fd02018-11-27 21:51:03 +0900859 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
860 boolean install) {
861 setDefaultArpRuleForBroadcastMode(osNode, install);
862
863 // we do not add fake gateway ARP rules for FLAT network
864 // ARP packets generated by FLAT typed VM should not be
865 // delegated to switch to handle
866 osNetworkService.subnets().stream().filter(subnet ->
867 osNetworkService.network(subnet.getNetworkId()) != null &&
868 osNetworkService.network(subnet.getNetworkId())
869 .getNetworkType() != NetworkType.FLAT)
870 .forEach(subnet -> {
871 String netId = subnet.getNetworkId();
872 Network net = osNetworkService.network(netId);
873 setFakeGatewayArpRule(subnet, net, install, osNode);
874 });
875 }
876
Jian Lif96685c2018-05-21 14:14:16 +0900877 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
878 TrafficSelector selector = DefaultTrafficSelector.builder()
879 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
880 .build();
881
882 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
883 .punt()
884 .build();
885
886 osFlowRuleService.setRule(
887 appId,
888 osNode.intgBridge(),
889 selector,
890 treatment,
891 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900892 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900893 install
894 );
895 }
896
897 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
898 TrafficSelector selector = DefaultTrafficSelector.builder()
899 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
900 .matchArpOp(ARP.OP_REQUEST)
901 .build();
902
903 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
904 .setOutput(PortNumber.FLOOD)
905 .build();
906
907 osFlowRuleService.setRule(
908 appId,
909 osNode.intgBridge(),
910 selector,
911 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900912 PRIORITY_ARP_FLOOD_RULE,
913 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900914 install
915 );
916 }
Jian Li7f70bb72018-07-06 23:35:30 +0900917
Jian Li5b66ce02018-07-09 22:43:54 +0900918 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900919 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900920 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900921 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900922 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
923 .forEach(p -> {
924 setArpRequestRule(p, install);
925 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900926 });
927 }
928 }
Jian Lieae12362018-04-10 18:48:32 +0900929 }
930
931 /**
932 * An internal instance port listener which listens the port events generated
933 * from VM. When ARP a host which located in a remote compute node, we specify
934 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
935 * host IP address. When ARP a host which located in a local compute node,
936 * we specify only ARP OP mode as REQUEST.
937 */
938 private class InternalInstancePortListener implements InstancePortListener {
939
940 @Override
941 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900942 return ARP_BROADCAST_MODE.equals(getArpMode());
943 }
Jian Lieae12362018-04-10 18:48:32 +0900944
Jian Li34220ea2018-11-14 01:30:24 +0900945 private boolean isRelevantHelper(InstancePortEvent event) {
946 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +0900947 }
948
949 @Override
950 public void event(InstancePortEvent event) {
951 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +0900952 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900953 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +0900954 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +0900955 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +0900956 break;
957 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +0900958 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +0900959 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900960 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +0900961 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900962 break;
Jian Lieae12362018-04-10 18:48:32 +0900963 default:
964 break;
965 }
966 }
Jian Li6a47fd02018-11-27 21:51:03 +0900967
968 private void processInstanceMigrationStart(InstancePortEvent event) {
969 if (!isRelevantHelper(event)) {
970 return;
971 }
972
973 setArpRequestRule(event.subject(), true);
974 setArpReplyRule(event.subject(), true);
975 }
976
977 private void processInstanceMigrationEnd(InstancePortEvent event) {
978 if (!isRelevantHelper(event)) {
979 return;
980 }
981
982 InstancePort revisedInstPort = swapStaleLocation(event.subject());
983 setArpRequestRule(revisedInstPort, false);
984 }
985
986 private void processInstanceRemoval(InstancePortEvent event) {
987 if (!isRelevantHelper(event)) {
988 return;
989 }
990
991 setArpRequestRule(event.subject(), false);
992 setArpReplyRule(event.subject(), false);
993 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900994 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700995}