blob: a373ab347bff4f2be2400c01bba4815af2d8f163 [file] [log] [blame]
Daniel Park81a61a12016-02-26 08:24:44 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Daniel Park81a61a12016-02-26 08:24:44 +09003 *
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;
Daniel Park81a61a12016-02-26 08:24:44 +090017
Jian Lida03ce92018-07-24 21:41:53 +090018import com.google.common.base.Strings;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li1064e4f2018-05-29 16:16:53 +090020import com.google.common.collect.Sets;
Daniel Park81a61a12016-02-26 08:24:44 +090021import org.onlab.packet.ARP;
Jian Li60312252018-05-10 18:40:32 +090022import org.onlab.packet.EthType;
Daniel Park81a61a12016-02-26 08:24:44 +090023import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090024import org.onlab.packet.Ip4Address;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
Jian Li60312252018-05-10 18:40:32 +090027import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090028import org.onosproject.cfg.ConfigProperty;
Jian Li60312252018-05-10 18:40:32 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Jian Li14a79f22018-06-05 03:44:22 +090034import org.onosproject.net.ConnectPoint;
Hyunsun Moon0d457362017-06-27 17:19:41 +090035import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090036import org.onosproject.net.PortNumber;
Jian Li60312252018-05-10 18:40:32 +090037import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090038import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090039import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090040import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070042import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090043import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070044import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090045import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090046import org.onosproject.openstacknetworking.api.Constants;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090047import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Li60312252018-05-10 18:40:32 +090048import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li581f21a2018-10-12 09:33:56 +090049import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090050import org.onosproject.openstacknetworking.api.InstancePortEvent;
51import org.onosproject.openstacknetworking.api.InstancePortListener;
Jian Li60312252018-05-10 18:40:32 +090052import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090053import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Li809b3ed2018-10-14 20:49:33 +090054import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
55import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090056import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090057import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Li60312252018-05-10 18:40:32 +090058import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
59import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li581f21a2018-10-12 09:33:56 +090060import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090061import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090062import org.onosproject.openstacknode.api.OpenstackNodeEvent;
63import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090064import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li34220ea2018-11-14 01:30:24 +090065import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090066import org.openstack4j.model.network.NetFloatingIP;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090067import org.openstack4j.model.network.Network;
Jian Li809b3ed2018-10-14 20:49:33 +090068import org.openstack4j.model.network.Port;
Jian Li60312252018-05-10 18:40:32 +090069import org.openstack4j.model.network.Router;
Jian Li60312252018-05-10 18:40:32 +090070import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071import org.osgi.service.component.annotations.Activate;
72import org.osgi.service.component.annotations.Component;
73import org.osgi.service.component.annotations.Deactivate;
74import org.osgi.service.component.annotations.Modified;
75import org.osgi.service.component.annotations.Reference;
76import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090077import org.slf4j.Logger;
78
79import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070082import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090083import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090084
Jian Li4d138702018-11-27 17:25:28 +090085import static java.util.Objects.requireNonNull;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070086import static java.util.concurrent.Executors.newSingleThreadExecutor;
87import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090088import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
89import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li60312252018-05-10 18:40:32 +090090import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
91import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090092import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090093import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li581f21a2018-10-12 09:33:56 +090094import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Ray Milkey8e406512018-10-24 15:56:50 -070095import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
96import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
97import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li24ec59f2018-05-23 19:01:25 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li32b03622018-11-06 17:54:24 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.floatingIpByInstancePort;
Jian Liebde74d2018-11-14 00:18:57 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Li24ec59f2018-05-23 19:01:25 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900107import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900109import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900110import static org.slf4j.LoggerFactory.getLogger;
111
112/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900114 */
Ray Milkey8e406512018-10-24 15:56:50 -0700115@Component(
116 immediate = true,
117 property = {
118 ARP_MODE + "=" + ARP_MODE_DEFAULT
119 }
120)
Daniel Park81a61a12016-02-26 08:24:44 +0900121public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700123 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900124
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
126 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900127 private static final String ARP_MODE = "arpMode";
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900130 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700133 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900136 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900139 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parke49eb382017-04-05 16:48:28 +0900142 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900145 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900148 protected ClusterService clusterService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900151 protected LeadershipService leadershipService;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900154 protected OpenstackFlowRuleService osFlowRuleService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li1064e4f2018-05-29 16:16:53 +0900157 protected OpenstackNetworkService osNetworkService;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900160 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900161
Ray Milkey0b18b722018-10-16 13:19:15 -0700162 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900163 protected PreCommitPortService preCommitPortService;
164
Ray Milkey8e406512018-10-24 15:56:50 -0700165 /** ARP processing mode, broadcast | proxy (default). **/
166 protected String arpMode = ARP_MODE_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900167
Ray Milkey8e406512018-10-24 15:56:50 -0700168 protected String gatewayMac = GATEWAY_MAC_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900169
170 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900171 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900172 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900173 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900174
175 private ApplicationId appId;
176 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900177
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178 private final ExecutorService eventExecutor = newSingleThreadExecutor(
179 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700180
Hyunsun Moon0d457362017-06-27 17:19:41 +0900181 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700182
183 @Activate
184 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900185 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
186 configService.registerProperties(getClass());
187 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900188 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900189 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900190 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900191 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900192 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700193 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
194 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900195 }
196
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700197 @Deactivate
198 protected void deactivate() {
199 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900200 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900201 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900202 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900203 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900204 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900205 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900206 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900207 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700208 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900209 }
210
Jian Li60312252018-05-10 18:40:32 +0900211 @Modified
Jian Li4d138702018-11-27 17:25:28 +0900212 protected void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900213 log.info("Modified");
214 }
215
Jian Li7f70bb72018-07-06 23:35:30 +0900216 private String getArpMode() {
217 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
218 return getPropertyValue(properties, ARP_MODE);
219 }
220
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700221 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900222 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900223
Jian Li7f70bb72018-07-06 23:35:30 +0900224 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900225 if (log.isTraceEnabled()) {
226 log.trace("ARP request received from {} for {}",
227 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
228 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
229 }
230
231 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900232
233 MacAddress targetMac = null;
234
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900235 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900236 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
237 .findAny().orElse(null);
238
daniel park576969a2018-03-09 07:07:41 +0900239 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900240 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900241 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
242 if (instPort == null) {
243 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
244 return;
245 } else {
246 targetMac = instPort.macAddress();
247 }
248
Jian Li32b03622018-11-06 17:54:24 +0900249 OpenstackNode gw =
250 getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
Daniel Park96f1e032018-08-09 13:30:57 +0900251
252 if (gw == null) {
253 return;
254 }
255
256 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
Jian Li32b03622018-11-06 17:54:24 +0900257 if (!Objects.equals(gw.intgBridge(),
258 context.inPacket().receivedFrom().deviceId())) {
Daniel Park96f1e032018-08-09 13:30:57 +0900259 return;
260 }
daniel parkeeb8e042018-02-21 14:06:58 +0900261 }
262
Daniel Park96f1e032018-08-09 13:30:57 +0900263 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900264 targetMac = Constants.DEFAULT_GATEWAY_MAC;
265 }
266
267 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900268 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
269 return;
270 }
271
daniel parkb5817102018-02-15 00:18:51 +0900272 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
273 targetMac, ethernet);
274
275 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900276 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900277
278 packetService.emit(new DefaultOutboundPacket(
279 context.inPacket().receivedFrom().deviceId(),
280 treatment,
281 ByteBuffer.wrap(ethReply.serialize())));
282
283 context.block();
Jian Li60312252018-05-10 18:40:32 +0900284 }
285
286 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900287 ConnectPoint cp = context.inPacket().receivedFrom();
288 PortNumber receivedPortNum = cp.port();
289 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
290 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
291
292 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
293
daniel parkb5817102018-02-15 00:18:51 +0900294 try {
Jian Li14a79f22018-06-05 03:44:22 +0900295
Jian Li32b03622018-11-06 17:54:24 +0900296 Set<String> extRouterIps = osNetworkService.externalPeerRouters()
297 .stream()
298 .map(r -> r.ipAddress().toString())
299 .collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900300
Jian Lid4066ea2018-06-07 01:44:45 +0900301 // if SPA is NOT contained in existing external router IP set, we ignore it
302 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900303 return;
304 }
305
306 OpenstackNode node = osNodeService.node(cp.deviceId());
307
308 if (node == null) {
309 return;
310 }
311
312 // we only handles the ARP-Reply message received by gateway node
313 if (node.type() != GATEWAY) {
314 return;
315 }
316
317 if (receivedPortNum.equals(node.uplinkPortNum())) {
318 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900319 }
320 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900321 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900322 }
Daniel Park81a61a12016-02-26 08:24:44 +0900323 }
Daniel Park81a61a12016-02-26 08:24:44 +0900324 }
325
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700326 private class InternalPacketProcessor implements PacketProcessor {
327
328 @Override
329 public void process(PacketContext context) {
330 if (context.isHandled()) {
331 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900332 }
333
Jian Li34220ea2018-11-14 01:30:24 +0900334 InboundPacket pkt = context.inPacket();
335 Ethernet ethernet = pkt.parsed();
336 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
337 eventExecutor.execute(() -> {
338
339 if (!isRelevantHelper(context)) {
340 return;
341 }
342
343 processArpPacket(context, ethernet);
344 });
345 }
346 }
347
348 private boolean isRelevantHelper(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900349 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
350 .stream().map(OpenstackNode::intgBridge)
351 .collect(Collectors.toSet());
352
Jian Li34220ea2018-11-14 01:30:24 +0900353 return gateways.contains(context.inPacket().receivedFrom().deviceId());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700354 }
355 }
356
daniel parkeeb8e042018-02-21 14:06:58 +0900357 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900358 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900359 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900360 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900361 .flatMap(osPort -> osPort.getFixedIps().stream())
362 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900363 }
Jian Li60312252018-05-10 18:40:32 +0900364
Jian Li60312252018-05-10 18:40:32 +0900365 /**
366 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900367 *
368 * @param gateway gateway node
369 * @param install flow rule installation flag
370 */
Jian Li32b03622018-11-06 17:54:24 +0900371 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway,
372 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900373 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900374
375 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
376 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
377 finalGws.addAll(ImmutableSet.copyOf(completedGws));
378
379 if (install) {
380 if (completedGws.contains(gateway)) {
381 if (completedGws.size() > 1) {
382 finalGws.remove(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900383 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900384 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900385 setFloatingIpArpRule(fip, fip.getPortId(),
386 finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900387 finalGws.add(gateway);
388 }
389 });
390 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900391 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900392 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900393 setFloatingIpArpRule(fip, fip.getPortId(),
394 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900395 }
396 });
397 } else {
398 log.warn("Detected node should be included in completed gateway set");
399 }
400 } else {
401 if (!completedGws.contains(gateway)) {
402 finalGws.add(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900403 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900404 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900405 setFloatingIpArpRule(fip, fip.getPortId(),
406 finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900407 }
408 });
409 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900410 if (!completedGws.isEmpty()) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900411 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900412 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900413 setFloatingIpArpRule(fip, fip.getPortId(),
414 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900415 }
416 });
417 }
418 } else {
419 log.warn("Detected node should NOT be included in completed gateway set");
420 }
421 }
422 }
423 }
424
425 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900426 * Installs/uninstalls ARP flow rules to the corresponding gateway by
427 * looking for compute node's device ID.
428 *
429 * @param fip floating IP
430 * @param port instance port
431 * @param gateways a collection of gateways
432 * @param install install flag
433 */
434 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
435 InstancePort port,
436 Set<OpenstackNode> gateways,
437 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900438 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900439
440 OpenstackNode gw = getGwByInstancePort(gateways, port);
441
442 if (gw == null) {
443 return;
444 }
445
446 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
447
448 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
449 }
450 }
451
452 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900453 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900454 * Note that, those rules will be only matched ARP_REQUEST packets,
455 * used for telling gateway node the mapped MAC address of requested IP,
456 * without the helps from controller.
457 *
458 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900459 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900460 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900461 * @param install flow rule installation flag
462 */
Jian Li8f64feb2018-07-24 13:20:16 +0900463 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900464 Set<OpenstackNode> gateways,
465 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900466 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900467
468 if (fip == null) {
469 log.warn("Failed to set ARP broadcast rule for floating IP");
470 return;
471 }
472
Jian Li581f21a2018-10-12 09:33:56 +0900473 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900474 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900475 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900476 return;
477 }
478
Jian Li8f64feb2018-07-24 13:20:16 +0900479 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900480 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900481
Jian Lia171a432018-06-11 11:52:11 +0900482 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900483
484 if (gw == null) {
485 return;
486 }
487
Jian Li581f21a2018-10-12 09:33:56 +0900488 if (install) {
489 preCommitPortService.subscribePreCommit(instPort.portId(),
490 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li4d138702018-11-27 17:25:28 +0900491 log.info("Subscribed the port {} on listening pre-remove event",
492 instPort.portId());
Jian Li581f21a2018-10-12 09:33:56 +0900493 } else {
494 preCommitPortService.unsubscribePreCommit(instPort.portId(),
Jian Li4d138702018-11-27 17:25:28 +0900495 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
496 this.getClass().getName());
497 log.info("Unsubscribed the port {} on listening pre-remove event",
498 instPort.portId());
Jian Li581f21a2018-10-12 09:33:56 +0900499 }
500
Jian Li24ec59f2018-05-23 19:01:25 +0900501 setArpRule(fip, targetMac, gw, install);
502 }
503 }
Jian Li60312252018-05-10 18:40:32 +0900504
Jian Li24ec59f2018-05-23 19:01:25 +0900505 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
506 OpenstackNode gateway, boolean install) {
507 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900508 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900509 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
510 .matchArpOp(ARP.OP_REQUEST)
511 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
512 .build();
Jian Li60312252018-05-10 18:40:32 +0900513
Jian Li24ec59f2018-05-23 19:01:25 +0900514 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
515 .setArpOp(ARP.OP_REPLY)
516 .setArpSha(targetMac)
517 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
518 .setOutput(PortNumber.IN_PORT)
519 .build();
Jian Li60312252018-05-10 18:40:32 +0900520
Jian Li24ec59f2018-05-23 19:01:25 +0900521 osFlowRuleService.setRule(
522 appId,
523 gateway.intgBridge(),
524 selector,
525 treatment,
526 PRIORITY_ARP_GATEWAY_RULE,
527 GW_COMMON_TABLE,
528 install
529 );
530
531 if (install) {
532 log.info("Install ARP Rule for Floating IP {}",
533 fip.getFloatingIpAddress());
534 } else {
535 log.info("Uninstall ARP Rule for Floating IP {}",
536 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900537 }
538 }
539
Jian Li809b3ed2018-10-14 20:49:33 +0900540 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900541 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li34220ea2018-11-14 01:30:24 +0900542 IpAddress externalIp = getExternalIp(router, osNetworkService);
543
544 if (externalIp == null) {
545 log.debug("External IP is not found");
546 return;
547 }
548
549 setFakeGatewayArpRuleByExternalIp(externalIp, install);
Jian Li809b3ed2018-10-14 20:49:33 +0900550 }
551 }
Daniel Park96f1e032018-08-09 13:30:57 +0900552
Jian Liebde74d2018-11-14 00:18:57 +0900553 private void setFakeGatewayArpRuleByExternalIp(IpAddress ipAddress, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900554
Jian Liebde74d2018-11-14 00:18:57 +0900555 TrafficSelector selector = DefaultTrafficSelector.builder()
556 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
557 .matchArpOp(ARP.OP_REQUEST)
558 .matchArpTpa(ipAddress.getIp4Address())
559 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900560
Jian Liebde74d2018-11-14 00:18:57 +0900561 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
562 .setArpOp(ARP.OP_REPLY)
563 .setArpSha(MacAddress.valueOf(gatewayMac))
564 .setArpSpa(ipAddress.getIp4Address())
565 .setOutput(PortNumber.IN_PORT)
566 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900567
Jian Liebde74d2018-11-14 00:18:57 +0900568 osNodeService.completeNodes(GATEWAY).forEach(n ->
569 osFlowRuleService.setRule(
570 appId,
571 n.intgBridge(),
572 selector,
573 treatment,
574 PRIORITY_ARP_GATEWAY_RULE,
575 GW_COMMON_TABLE,
576 install
577 )
578 );
579
580 if (install) {
581 log.info("Install ARP Rule for Gateway Snat {}", ipAddress);
582 } else {
583 log.info("Uninstall ARP Rule for Gateway Snat {}", ipAddress);
584 }
Jian Li809b3ed2018-10-14 20:49:33 +0900585 }
586
587 /**
588 * An internal network event listener, intended to uninstall ARP rules for
589 * routing the packets destined to external gateway.
590 */
591 private class InternalNetworkEventListener implements OpenstackNetworkListener {
592
593 @Override
594 public boolean isRelevant(OpenstackNetworkEvent event) {
595 Port osPort = event.port();
596 if (osPort == null || osPort.getFixedIps() == null) {
597 return false;
598 }
599
Jian Li34220ea2018-11-14 01:30:24 +0900600 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
601 ARP_BROADCAST_MODE.equals(getArpMode());
602 }
603
604 private boolean isRelevantHelper() {
605 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li809b3ed2018-10-14 20:49:33 +0900606 }
607
608 @Override
609 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900610 IpAddress ipAddress = externalIp(event.port());
Jian Li809b3ed2018-10-14 20:49:33 +0900611 switch (event.type()) {
612 case OPENSTACK_PORT_CREATED:
613 case OPENSTACK_PORT_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900614 eventExecutor.execute(() -> processPortCreation(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900615 break;
616 case OPENSTACK_PORT_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900617 eventExecutor.execute(() -> processPortRemoval(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900618 break;
619 default:
620 // do nothing
621 break;
622 }
Daniel Park96f1e032018-08-09 13:30:57 +0900623 }
Jian Li34220ea2018-11-14 01:30:24 +0900624
Jian Li4d138702018-11-27 17:25:28 +0900625 private void processPortCreation(IpAddress ipAddress) {
626 if (!isRelevantHelper() || ipAddress == null) {
627 return;
628 }
629
630 setFakeGatewayArpRuleByExternalIp(ipAddress, true);
631 }
632
633 private void processPortRemoval(IpAddress ipAddress) {
634 if (!isRelevantHelper() || ipAddress == null) {
635 return;
636 }
637
638 setFakeGatewayArpRuleByExternalIp(ipAddress, false);
639 }
640
Jian Li34220ea2018-11-14 01:30:24 +0900641 private IpAddress externalIp(Port port) {
642 IP ip = port.getFixedIps().stream().findAny().orElse(null);
643
644 if (ip != null && ip.getIpAddress() != null) {
645 return IpAddress.valueOf(ip.getIpAddress());
646 }
647
648 return null;
649 }
Daniel Park96f1e032018-08-09 13:30:57 +0900650 }
651
Jian Li60312252018-05-10 18:40:32 +0900652 /**
653 * An internal router event listener, intended to install/uninstall
654 * ARP rules for forwarding packets created from floating IPs.
655 */
656 private class InternalRouterEventListener implements OpenstackRouterListener {
657
Jian Li34220ea2018-11-14 01:30:24 +0900658 private boolean isRelevantHelper() {
659 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900660 }
661
662 @Override
663 public void event(OpenstackRouterEvent event) {
664 switch (event.type()) {
665 case OPENSTACK_ROUTER_CREATED:
Jian Liebde74d2018-11-14 00:18:57 +0900666 // add a router with external gateway
667 case OPENSTACK_ROUTER_GATEWAY_ADDED:
668 // add a gateway manually after adding a router
Jian Li4d138702018-11-27 17:25:28 +0900669 eventExecutor.execute(() -> processRouterGwCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900670 break;
671 case OPENSTACK_ROUTER_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900672 // remove a router with external gateway
Jian Li60312252018-05-10 18:40:32 +0900673 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900674 // remove a gateway from an existing router
Jian Li4d138702018-11-27 17:25:28 +0900675 eventExecutor.execute(() -> processRouterGwRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900676 break;
677 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900678 // during floating IP creation, if the floating IP is
679 // associated with any port of VM, then we will set
680 // floating IP related ARP rules to gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900681 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900682 eventExecutor.execute(() -> processFloatingIpCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900683 break;
684 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900685 // during floating IP deletion, if the floating IP is
686 // still associated with any port of VM, then we will
687 // remove floating IP related ARP rules from gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900688 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900689 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900690 break;
691 default:
692 // do nothing for the other events
693 break;
694 }
695 }
696
Jian Li4d138702018-11-27 17:25:28 +0900697 private void processRouterGwCreation(OpenstackRouterEvent event) {
698 if (!isRelevantHelper()) {
699 return;
700 }
701
702 // add a router with external gateway
703 setFakeGatewayArpRuleByRouter(event.subject(), true);
704 }
705
706 private void processRouterGwRemoval(OpenstackRouterEvent event) {
707 if (!isRelevantHelper()) {
708 return;
709 }
710
711 setFakeGatewayArpRuleByRouter(event.subject(), false);
712 }
713
714 private void processFloatingIpCreation(OpenstackRouterEvent event) {
715 if (!isRelevantHelper()) {
716 return;
717 }
718
719 if (getValidPortId(event) == null) {
720 return;
721 }
722
723 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
724
725 // associate a floating IP with an existing VM
726 setFloatingIpArpRule(event.floatingIp(),
727 getValidPortId(event), completedGws, true);
728 }
729
730 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
731 if (!isRelevantHelper()) {
732 return;
733 }
734
735 if (getValidPortId(event) == null) {
736 return;
737 }
738
739 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
740
741 // disassociate a floating IP with an existing VM
742 setFloatingIpArpRule(event.floatingIp(),
743 getValidPortId(event), completedGws, false);
744 }
745
Jian Lida03ce92018-07-24 21:41:53 +0900746 private String getValidPortId(OpenstackRouterEvent event) {
747 NetFloatingIP osFip = event.floatingIp();
748 String portId = osFip.getPortId();
749
750 if (Strings.isNullOrEmpty(portId)) {
751 portId = event.portId();
752 }
753
754 if (portId != null && instancePortService.instancePort(portId) != null) {
755 return portId;
756 }
757
758 return null;
759 }
Jian Li60312252018-05-10 18:40:32 +0900760 }
761
Jian Lie1a39032018-06-19 21:49:36 +0900762 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900763
Jian Li34220ea2018-11-14 01:30:24 +0900764 private boolean isRelevantHelper() {
765 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900766 }
767
768 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900769 public void event(InstancePortEvent event) {
770 InstancePort instPort = event.subject();
Jian Li60312252018-05-10 18:40:32 +0900771 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900772 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900773 eventExecutor.execute(() ->
774 processInstanceDetection(event, instPort));
Jian Li34220ea2018-11-14 01:30:24 +0900775
Jian Li60312252018-05-10 18:40:32 +0900776 break;
Jian Lie1a39032018-06-19 21:49:36 +0900777 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900778 eventExecutor.execute(() ->
779 processInstanceMigrationStart(event, instPort));
Jian Li32b03622018-11-06 17:54:24 +0900780
781 break;
782 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900783 eventExecutor.execute(() ->
784 processInstanceMigrationEnd(event, instPort));
Jian Lie1a39032018-06-19 21:49:36 +0900785 break;
786 default:
787 break;
788 }
Jian Li60312252018-05-10 18:40:32 +0900789 }
Jian Li4d138702018-11-27 17:25:28 +0900790
791 private void processInstanceDetection(InstancePortEvent event,
792 InstancePort instPort) {
793 if (!isRelevantHelper()) {
794 return;
795 }
796
797 osRouterAdminService.floatingIps().stream()
798 .filter(f -> f.getPortId() != null)
799 .filter(f -> f.getPortId().equals(instPort.portId()))
800 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(),
801 osNodeService.completeNodes(GATEWAY), true));
802 }
803
804 private void processInstanceMigrationStart(InstancePortEvent event,
805 InstancePort instPort) {
806 if (!isRelevantHelper()) {
807 return;
808 }
809
810 NetFloatingIP fip = associatedFloatingIp(instPort,
811 osRouterAdminService.floatingIps());
812
813 if (osNodeService.completeNodes(GATEWAY).size() == 1) {
814 return;
815 }
816
817 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
818 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
819 osNodeService.completeNodes(GATEWAY), true);
820 }
821 }
822
823 private void processInstanceMigrationEnd(InstancePortEvent event,
824 InstancePort instPort) {
825 if (!isRelevantHelper()) {
826 return;
827 }
828
829 NetFloatingIP fip = associatedFloatingIp(instPort,
830 osRouterAdminService.floatingIps());
831 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
832
833 InstancePort revisedInstPort = swapStaleLocation(event.subject());
834
835 if (gateways.size() == 1) {
836 return;
837 }
838
839 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
840 DeviceId newDeviceId = event.subject().deviceId();
841 DeviceId oldDeviceId = revisedInstPort.deviceId();
842
843 OpenstackNode oldGw =
844 getGwByComputeDevId(gateways, oldDeviceId);
845 OpenstackNode newGw =
846 getGwByComputeDevId(gateways, newDeviceId);
847
848 if (oldGw != null && oldGw.equals(newGw)) {
849 return;
850 }
851
852 setFloatingIpArpRuleWithPortEvent(fip,
853 revisedInstPort, gateways, false);
854 }
855 }
Jian Li60312252018-05-10 18:40:32 +0900856 }
Jian Lif96685c2018-05-21 14:14:16 +0900857
858 private class InternalNodeEventListener implements OpenstackNodeListener {
859
860 @Override
861 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900862 return event.subject().type() == GATEWAY;
863 }
864
865 private boolean isRelevantHelper() {
866 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lif96685c2018-05-21 14:14:16 +0900867 }
868
869 @Override
870 public void event(OpenstackNodeEvent event) {
871 OpenstackNode osNode = event.subject();
872 switch (event.type()) {
873 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900874 eventExecutor.execute(() -> processNodeCompletion(event, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900875 break;
876 case OPENSTACK_NODE_INCOMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900877 eventExecutor.execute(() -> processNodeIncompletion(event, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900878 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900879 case OPENSTACK_NODE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900880 eventExecutor.execute(() -> processNodeRemoval(event));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900881 break;
Jian Lif96685c2018-05-21 14:14:16 +0900882 default:
883 break;
884 }
885 }
886
Jian Li4d138702018-11-27 17:25:28 +0900887 private void processNodeCompletion(OpenstackNodeEvent event, OpenstackNode node) {
888 if (!isRelevantHelper()) {
889 return;
890 }
891 setDefaultArpRule(node, true);
892 setFloatingIpArpRuleForGateway(node, true);
893 sendGratuitousArpToSwitch(event.subject(), true);
894 }
895
896 private void processNodeIncompletion(OpenstackNodeEvent event, OpenstackNode node) {
897 if (!isRelevantHelper()) {
898 return;
899 }
900 setDefaultArpRule(node, false);
901 setFloatingIpArpRuleForGateway(node, false);
902 sendGratuitousArpToSwitch(event.subject(), false);
903 }
904
905 private void processNodeRemoval(OpenstackNodeEvent event) {
906 if (!isRelevantHelper()) {
907 return;
908 }
909 sendGratuitousArpToSwitch(event.subject(), false);
910 }
911
Jian Li32b03622018-11-06 17:54:24 +0900912 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
913 boolean isCompleteCase) {
914 Set<OpenstackNode> completeGws =
915 ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900916
917 if (isCompleteCase) {
Jian Li32b03622018-11-06 17:54:24 +0900918 osNodeService.completeNodes(COMPUTE).stream()
919 .filter(node -> isGwSelectedByComputeNode(completeGws,
920 node, gatewayNode))
921 .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900922
923 } else {
924 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
925 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
926 oldCompleteGws.add(gatewayNode);
927
Jian Li32b03622018-11-06 17:54:24 +0900928 osNodeService.completeNodes(COMPUTE).stream()
929 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
930 node, gatewayNode))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900931 .forEach(node -> {
Jian Li32b03622018-11-06 17:54:24 +0900932 OpenstackNode newSelectedGatewayNode =
933 getGwByComputeDevId(completeGws, node.intgBridge());
934 processGarpPacketForComputeNode(node, newSelectedGatewayNode);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900935 });
936 }
937 }
938
939 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
940 OpenstackNode computeNode,
941 OpenstackNode gwNode) {
Jian Li4d138702018-11-27 17:25:28 +0900942 return requireNonNull(getGwByComputeDevId(gws, computeNode.intgBridge()))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900943 .intgBridge().equals(gwNode.intgBridge());
944 }
945
Jian Li32b03622018-11-06 17:54:24 +0900946 private void processGarpPacketForComputeNode(OpenstackNode computeNode,
947 OpenstackNode gatewayNode) {
948 instancePortService.instancePort(computeNode.intgBridge())
949 .forEach(instancePort -> {
950 NetFloatingIP floatingIP =
951 floatingIpByInstancePort(instancePort, osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900952 Network network = osNetworkService.network(instancePort.networkId());
Jian Li32b03622018-11-06 17:54:24 +0900953 ExternalPeerRouter externalPeerRouter =
954 externalPeerRouterForNetwork(network, osNetworkService,
955 osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900956 if (floatingIP != null && externalPeerRouter != null) {
Jian Li32b03622018-11-06 17:54:24 +0900957 processGarpPacketForFloatingIp(
958 floatingIP, instancePort, externalPeerRouter.vlanId(),
959 gatewayNode, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900960 }
961 });
962 }
963
Jian Lif96685c2018-05-21 14:14:16 +0900964 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900965
966 if (getArpMode() == null) {
967 return;
968 }
Jian Liebde74d2018-11-14 00:18:57 +0900969 log.info("ARP mode is {}", getArpMode());
Jian Lib6969502018-10-30 20:38:07 +0900970
Jian Li7f70bb72018-07-06 23:35:30 +0900971 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900972 case ARP_PROXY_MODE:
973 setDefaultArpRuleForProxyMode(osNode, install);
974 break;
975 case ARP_BROADCAST_MODE:
976 setDefaultArpRuleForBroadcastMode(osNode, install);
977 break;
978 default:
979 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900980 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900981 break;
982 }
983 }
984
Jian Li32b03622018-11-06 17:54:24 +0900985 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
986 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900987 TrafficSelector selector = DefaultTrafficSelector.builder()
988 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
989 .build();
990
991 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
992 .punt()
993 .build();
994
995 osFlowRuleService.setRule(
996 appId,
997 osNode.intgBridge(),
998 selector,
999 treatment,
1000 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001001 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001002 install
1003 );
1004 }
1005
Jian Li32b03622018-11-06 17:54:24 +09001006 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
1007 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +09001008 // we only match ARP_REPLY in gateway node, because controller
1009 // somehow need to process ARP_REPLY which is issued from
1010 // external router...
1011 TrafficSelector selector = DefaultTrafficSelector.builder()
1012 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1013 .matchArpOp(ARP.OP_REPLY)
1014 .build();
1015
1016 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1017 .punt()
1018 .build();
1019
1020 osFlowRuleService.setRule(
1021 appId,
1022 osNode.intgBridge(),
1023 selector,
1024 treatment,
1025 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001026 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001027 install
1028 );
Daniel Park96f1e032018-08-09 13:30:57 +09001029
Jian Liebde74d2018-11-14 00:18:57 +09001030 log.info("calling setFakeGatewayArpRuleByRouter.. ");
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001031 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +09001032 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +09001033 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +09001034 }
1035 }
Daniel Park81a61a12016-02-26 08:24:44 +09001036}