blob: 2021aa86c0ebc879e5d7703ed3db443e867711e3 [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;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090061import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090062import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090063import org.onosproject.openstacknode.api.OpenstackNodeEvent;
64import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090065import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li60312252018-05-10 18:40:32 +090066import org.openstack4j.model.network.ExternalGateway;
Jian Li4df657b2018-05-29 16:39:00 +090067import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090068import org.openstack4j.model.network.NetFloatingIP;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090069import org.openstack4j.model.network.Network;
Jian Li809b3ed2018-10-14 20:49:33 +090070import org.openstack4j.model.network.Port;
Jian Li60312252018-05-10 18:40:32 +090071import org.openstack4j.model.network.Router;
Jian Li28ec77f2018-10-31 07:07:25 +090072import org.openstack4j.model.network.RouterInterface;
Jian Li60312252018-05-10 18:40:32 +090073import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074import org.osgi.service.component.annotations.Activate;
75import org.osgi.service.component.annotations.Component;
76import org.osgi.service.component.annotations.Deactivate;
77import org.osgi.service.component.annotations.Modified;
78import org.osgi.service.component.annotations.Reference;
79import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090080import org.slf4j.Logger;
81
82import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090084import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090086import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090087
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070088import static java.util.concurrent.Executors.newSingleThreadExecutor;
89import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090090import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
91import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li60312252018-05-10 18:40:32 +090092import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
93import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090094import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090095import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li581f21a2018-10-12 09:33:56 +090096import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Ray Milkey8e406512018-10-24 15:56:50 -070097import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
98import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
99import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li24ec59f2018-05-23 19:01:25 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900109import static org.slf4j.LoggerFactory.getLogger;
110
111/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900113 */
Ray Milkey8e406512018-10-24 15:56:50 -0700114@Component(
115 immediate = true,
116 property = {
117 ARP_MODE + "=" + ARP_MODE_DEFAULT
118 }
119)
Daniel Park81a61a12016-02-26 08:24:44 +0900120public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700122 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900123
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
125 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900126 private static final String ARP_MODE = "arpMode";
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900129 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700132 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900135 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900138 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parke49eb382017-04-05 16:48:28 +0900141 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900144 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900147 protected ClusterService clusterService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900150 protected LeadershipService leadershipService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900153 protected OpenstackFlowRuleService osFlowRuleService;
154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li1064e4f2018-05-29 16:16:53 +0900156 protected OpenstackNetworkService osNetworkService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900159 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900160
Ray Milkey0b18b722018-10-16 13:19:15 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900162 protected PreCommitPortService preCommitPortService;
163
Ray Milkey8e406512018-10-24 15:56:50 -0700164 /** ARP processing mode, broadcast | proxy (default). **/
165 protected String arpMode = ARP_MODE_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900166
Ray Milkey8e406512018-10-24 15:56:50 -0700167 protected String gatewayMac = GATEWAY_MAC_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900168
169 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900170 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900171 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900172 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900173
174 private ApplicationId appId;
175 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900176
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 private final ExecutorService eventExecutor = newSingleThreadExecutor(
178 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700179
Hyunsun Moon0d457362017-06-27 17:19:41 +0900180 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700181
182 @Activate
183 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900184 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
185 configService.registerProperties(getClass());
186 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900187 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900188 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900189 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900190 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900191 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700192 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
193 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900194 }
195
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700196 @Deactivate
197 protected void deactivate() {
198 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900199 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900200 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900201 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900202 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900203 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900204 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900205 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900206 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700207 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900208 }
209
Jian Li60312252018-05-10 18:40:32 +0900210 @Modified
211 void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900212 log.info("Modified");
213 }
214
Jian Li7f70bb72018-07-06 23:35:30 +0900215 private String getArpMode() {
216 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
217 return getPropertyValue(properties, ARP_MODE);
218 }
219
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700220 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900221 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900222
Jian Li7f70bb72018-07-06 23:35:30 +0900223 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900224 if (log.isTraceEnabled()) {
225 log.trace("ARP request received from {} for {}",
226 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
227 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
228 }
229
230 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900231
232 MacAddress targetMac = null;
233
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900234 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900235 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
236 .findAny().orElse(null);
237
daniel park576969a2018-03-09 07:07:41 +0900238 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900239 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900240 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
241 if (instPort == null) {
242 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
243 return;
244 } else {
245 targetMac = instPort.macAddress();
246 }
247
248 OpenstackNode gw = getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
249
250 if (gw == null) {
251 return;
252 }
253
254 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
255 if (!Objects.equals(gw.intgBridge(), context.inPacket().receivedFrom().deviceId())) {
256 return;
257 }
daniel parkeeb8e042018-02-21 14:06:58 +0900258 }
259
Daniel Park96f1e032018-08-09 13:30:57 +0900260 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900261 targetMac = Constants.DEFAULT_GATEWAY_MAC;
262 }
263
264 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900265 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
266 return;
267 }
268
daniel parkb5817102018-02-15 00:18:51 +0900269 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
270 targetMac, ethernet);
271
272 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900273 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900274
275 packetService.emit(new DefaultOutboundPacket(
276 context.inPacket().receivedFrom().deviceId(),
277 treatment,
278 ByteBuffer.wrap(ethReply.serialize())));
279
280 context.block();
Jian Li60312252018-05-10 18:40:32 +0900281 }
282
283 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900284 ConnectPoint cp = context.inPacket().receivedFrom();
285 PortNumber receivedPortNum = cp.port();
286 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
287 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
288
289 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
290
daniel parkb5817102018-02-15 00:18:51 +0900291 try {
Jian Li14a79f22018-06-05 03:44:22 +0900292
Jian Lid4066ea2018-06-07 01:44:45 +0900293 Set<String> extRouterIps = osNetworkService.externalPeerRouters().
Jian Li5e2ad4a2018-07-16 13:40:53 +0900294 stream().map(r -> r.ipAddress().toString()).collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900295
Jian Lid4066ea2018-06-07 01:44:45 +0900296 // if SPA is NOT contained in existing external router IP set, we ignore it
297 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900298 return;
299 }
300
301 OpenstackNode node = osNodeService.node(cp.deviceId());
302
303 if (node == null) {
304 return;
305 }
306
307 // we only handles the ARP-Reply message received by gateway node
308 if (node.type() != GATEWAY) {
309 return;
310 }
311
312 if (receivedPortNum.equals(node.uplinkPortNum())) {
313 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900314 }
315 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900316 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900317 }
Daniel Park81a61a12016-02-26 08:24:44 +0900318 }
Daniel Park81a61a12016-02-26 08:24:44 +0900319 }
320
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700321 private class InternalPacketProcessor implements PacketProcessor {
322
323 @Override
324 public void process(PacketContext context) {
325 if (context.isHandled()) {
326 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900327 }
328
329 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
330 .stream().map(OpenstackNode::intgBridge)
331 .collect(Collectors.toSet());
332
333 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700334 // return if the packet is not from gateway nodes
335 return;
336 }
337
338 InboundPacket pkt = context.inPacket();
339 Ethernet ethernet = pkt.parsed();
340 if (ethernet != null &&
341 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900342 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700343 }
344 }
345 }
346
daniel parkeeb8e042018-02-21 14:06:58 +0900347 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900348 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900350 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900351 .flatMap(osPort -> osPort.getFixedIps().stream())
352 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900353 }
Jian Li60312252018-05-10 18:40:32 +0900354
Jian Li60312252018-05-10 18:40:32 +0900355 /**
356 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900357 *
358 * @param gateway gateway node
359 * @param install flow rule installation flag
360 */
361 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900362 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900363
364 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
365 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
366 finalGws.addAll(ImmutableSet.copyOf(completedGws));
367
368 if (install) {
369 if (completedGws.contains(gateway)) {
370 if (completedGws.size() > 1) {
371 finalGws.remove(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900372 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900373 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900374 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900375 finalGws.add(gateway);
376 }
377 });
378 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900379 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900380 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900381 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900382 }
383 });
384 } else {
385 log.warn("Detected node should be included in completed gateway set");
386 }
387 } else {
388 if (!completedGws.contains(gateway)) {
389 finalGws.add(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900390 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900391 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900392 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900393 }
394 });
395 finalGws.remove(gateway);
396 if (completedGws.size() >= 1) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900397 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900398 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900399 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900400 }
401 });
402 }
403 } else {
404 log.warn("Detected node should NOT be included in completed gateway set");
405 }
406 }
407 }
408 }
409
410 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900411 * Installs/uninstalls ARP flow rules to the corresponding gateway by
412 * looking for compute node's device ID.
413 *
414 * @param fip floating IP
415 * @param port instance port
416 * @param gateways a collection of gateways
417 * @param install install flag
418 */
419 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
420 InstancePort port,
421 Set<OpenstackNode> gateways,
422 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900423 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900424
425 OpenstackNode gw = getGwByInstancePort(gateways, port);
426
427 if (gw == null) {
428 return;
429 }
430
431 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
432
433 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
434 }
435 }
436
437 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900438 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900439 * Note that, those rules will be only matched ARP_REQUEST packets,
440 * used for telling gateway node the mapped MAC address of requested IP,
441 * without the helps from controller.
442 *
443 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900444 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900445 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900446 * @param install flow rule installation flag
447 */
Jian Li8f64feb2018-07-24 13:20:16 +0900448 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900449 Set<OpenstackNode> gateways,
450 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900451 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900452
453 if (fip == null) {
454 log.warn("Failed to set ARP broadcast rule for floating IP");
455 return;
456 }
457
Jian Li581f21a2018-10-12 09:33:56 +0900458 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900459 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900460 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900461 return;
462 }
463
Jian Li8f64feb2018-07-24 13:20:16 +0900464 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900465 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900466
Jian Lia171a432018-06-11 11:52:11 +0900467 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900468
469 if (gw == null) {
470 return;
471 }
472
Jian Li581f21a2018-10-12 09:33:56 +0900473 if (install) {
474 preCommitPortService.subscribePreCommit(instPort.portId(),
475 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
476 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
477 } else {
478 preCommitPortService.unsubscribePreCommit(instPort.portId(),
479 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
480 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
481 }
482
Jian Li24ec59f2018-05-23 19:01:25 +0900483 setArpRule(fip, targetMac, gw, install);
484 }
485 }
Jian Li60312252018-05-10 18:40:32 +0900486
Jian Li24ec59f2018-05-23 19:01:25 +0900487 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
488 OpenstackNode gateway, boolean install) {
489 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900490 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900491 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
492 .matchArpOp(ARP.OP_REQUEST)
493 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
494 .build();
Jian Li60312252018-05-10 18:40:32 +0900495
Jian Li24ec59f2018-05-23 19:01:25 +0900496 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
497 .setArpOp(ARP.OP_REPLY)
498 .setArpSha(targetMac)
499 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
500 .setOutput(PortNumber.IN_PORT)
501 .build();
Jian Li60312252018-05-10 18:40:32 +0900502
Jian Li24ec59f2018-05-23 19:01:25 +0900503 osFlowRuleService.setRule(
504 appId,
505 gateway.intgBridge(),
506 selector,
507 treatment,
508 PRIORITY_ARP_GATEWAY_RULE,
509 GW_COMMON_TABLE,
510 install
511 );
512
513 if (install) {
514 log.info("Install ARP Rule for Floating IP {}",
515 fip.getFloatingIpAddress());
516 } else {
517 log.info("Uninstall ARP Rule for Floating IP {}",
518 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900519 }
520 }
521
Jian Li809b3ed2018-10-14 20:49:33 +0900522 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Jian Li28ec77f2018-10-31 07:07:25 +0900523 setFakeGatewayArpRuleByGateway(router.getId(), router.getExternalGatewayInfo(), install);
Daniel Park96f1e032018-08-09 13:30:57 +0900524 }
525
Jian Li28ec77f2018-10-31 07:07:25 +0900526 private Set<IP> getExternalGatewaySnatIps(String routerId, ExternalGateway extGw) {
527 if (routerId == null) {
528 return ImmutableSet.of();
529 }
530
531 Set<String> portIds = osRouterAdminService.routerInterfaces(routerId).stream()
532 .map(RouterInterface::getPortId)
533 .collect(Collectors.toSet());
534
535 return portIds.stream()
536 .map(pid -> osNetworkAdminService.port(pid))
537 .filter(p -> Objects.equals(p.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
538 .flatMap(p -> p.getFixedIps().stream())
Daniel Park96f1e032018-08-09 13:30:57 +0900539 .collect(Collectors.toSet());
540 }
541
Jian Li28ec77f2018-10-31 07:07:25 +0900542 private void setFakeGatewayArpRuleByGateway(String routerId, ExternalGateway extGw, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900543 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
544
545 if (extGw == null) {
546 return;
547 }
548
Jian Li28ec77f2018-10-31 07:07:25 +0900549 setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(routerId, extGw), install);
Jian Li809b3ed2018-10-14 20:49:33 +0900550 }
551 }
Daniel Park96f1e032018-08-09 13:30:57 +0900552
Jian Li809b3ed2018-10-14 20:49:33 +0900553 private void setFakeGatewayArpRuleByIps(Set<IP> ips, boolean install) {
554 ips.forEach(ip -> {
555 TrafficSelector selector = DefaultTrafficSelector.builder()
556 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
557 .matchArpOp(ARP.OP_REQUEST)
558 .matchArpTpa(Ip4Address.valueOf(ip.getIpAddress()))
559 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900560
Jian Li809b3ed2018-10-14 20:49:33 +0900561 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
562 .setArpOp(ARP.OP_REPLY)
563 .setArpSha(MacAddress.valueOf(gatewayMac))
564 .setArpSpa(Ip4Address.valueOf(ip.getIpAddress()))
565 .setOutput(PortNumber.IN_PORT)
566 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900567
Jian Li809b3ed2018-10-14 20:49:33 +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 );
Daniel Park96f1e032018-08-09 13:30:57 +0900579
Jian Li809b3ed2018-10-14 20:49:33 +0900580 if (install) {
581 log.info("Install ARP Rule for Gateway Snat {}", ip.getIpAddress());
582 } else {
583 log.info("Uninstall ARP Rule for Gateway Snat {}", ip.getIpAddress());
584 }
585 });
586 }
587
588 /**
589 * An internal network event listener, intended to uninstall ARP rules for
590 * routing the packets destined to external gateway.
591 */
592 private class InternalNetworkEventListener implements OpenstackNetworkListener {
593
594 @Override
595 public boolean isRelevant(OpenstackNetworkEvent event) {
596 Port osPort = event.port();
597 if (osPort == null || osPort.getFixedIps() == null) {
598 return false;
599 }
600
601 // do not allow to proceed without leadership
602 NodeId leader = leadershipService.getLeader(appId.name());
603 return Objects.equals(localNodeId, leader) &&
Jian Li2360acb2018-10-17 00:46:31 +0900604 DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
605 ARP_BROADCAST_MODE.equals(getArpMode());
Jian Li809b3ed2018-10-14 20:49:33 +0900606 }
607
608 @Override
609 public void event(OpenstackNetworkEvent event) {
610 switch (event.type()) {
611 case OPENSTACK_PORT_CREATED:
612 case OPENSTACK_PORT_UPDATED:
613 eventExecutor.execute(() ->
614 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), true)
615 );
616 break;
617 case OPENSTACK_PORT_REMOVED:
618 eventExecutor.execute(() ->
619 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), false)
620 );
621 break;
622 default:
623 // do nothing
624 break;
625 }
Daniel Park96f1e032018-08-09 13:30:57 +0900626 }
627 }
628
Jian Li60312252018-05-10 18:40:32 +0900629 /**
630 * An internal router event listener, intended to install/uninstall
631 * ARP rules for forwarding packets created from floating IPs.
632 */
633 private class InternalRouterEventListener implements OpenstackRouterListener {
634
635 @Override
636 public boolean isRelevant(OpenstackRouterEvent event) {
637 // do not allow to proceed without leadership
638 NodeId leader = leadershipService.getLeader(appId.name());
639 return Objects.equals(localNodeId, leader);
640 }
641
642 @Override
643 public void event(OpenstackRouterEvent event) {
Jian Li1064e4f2018-05-29 16:16:53 +0900644
645 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
646
Jian Li60312252018-05-10 18:40:32 +0900647 switch (event.type()) {
648 case OPENSTACK_ROUTER_CREATED:
649 eventExecutor.execute(() ->
650 // add a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900651 setFakeGatewayArpRuleByRouter(event.subject(), true)
Jian Li60312252018-05-10 18:40:32 +0900652 );
653 break;
654 case OPENSTACK_ROUTER_REMOVED:
655 eventExecutor.execute(() ->
656 // remove a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900657 setFakeGatewayArpRuleByRouter(event.subject(), false)
Jian Li60312252018-05-10 18:40:32 +0900658 );
659 break;
660 case OPENSTACK_ROUTER_GATEWAY_ADDED:
661 eventExecutor.execute(() ->
662 // add a gateway manually after adding a router
Jian Li28ec77f2018-10-31 07:07:25 +0900663 setFakeGatewayArpRuleByGateway(event.subject().getId(),
664 event.externalGateway(), true)
Jian Li60312252018-05-10 18:40:32 +0900665 );
666 break;
667 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
668 eventExecutor.execute(() ->
669 // remove a gateway from an existing router
Jian Li28ec77f2018-10-31 07:07:25 +0900670 setFakeGatewayArpRuleByGateway(event.subject().getId(),
671 event.externalGateway(), false)
Jian Li60312252018-05-10 18:40:32 +0900672 );
673 break;
674 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900675 if (getValidPortId(event) != null) {
676 eventExecutor.execute(() -> {
677 // associate a floating IP with an existing VM
678 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
679 completedGws, true);
680 });
681 }
Jian Li60312252018-05-10 18:40:32 +0900682 break;
683 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900684 if (getValidPortId(event) != null) {
685 eventExecutor.execute(() -> {
686 // disassociate a floating IP with an existing VM
687 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
688 completedGws, false);
689 });
690 }
Jian Li60312252018-05-10 18:40:32 +0900691 break;
692 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900693 // during floating IP creation, if the floating IP is
694 // associated with any port of VM, then we will set
695 // floating IP related ARP rules to gateway node
696 if (getValidPortId(event) != null) {
697 eventExecutor.execute(() -> {
698 // associate a floating IP with an existing VM
699 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
700 completedGws, true);
701 });
702 }
Jian Li60312252018-05-10 18:40:32 +0900703 break;
704 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900705 // during floating IP deletion, if the floating IP is
706 // still associated with any port of VM, then we will
707 // remove floating IP related ARP rules from gateway node
708 if (getValidPortId(event) != null) {
709 eventExecutor.execute(() -> {
710 // associate a floating IP with an existing VM
711 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
712 completedGws, false);
713 });
714 }
Jian Li60312252018-05-10 18:40:32 +0900715 break;
716 default:
717 // do nothing for the other events
718 break;
719 }
720 }
721
Jian Lida03ce92018-07-24 21:41:53 +0900722 private String getValidPortId(OpenstackRouterEvent event) {
723 NetFloatingIP osFip = event.floatingIp();
724 String portId = osFip.getPortId();
725
726 if (Strings.isNullOrEmpty(portId)) {
727 portId = event.portId();
728 }
729
730 if (portId != null && instancePortService.instancePort(portId) != null) {
731 return portId;
732 }
733
734 return null;
735 }
Jian Li60312252018-05-10 18:40:32 +0900736 }
737
Jian Lie1a39032018-06-19 21:49:36 +0900738 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900739
740 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900741 public boolean isRelevant(InstancePortEvent event) {
742 // do not allow to proceed without leadership
743 NodeId leader = leadershipService.getLeader(appId.name());
744 return Objects.equals(localNodeId, leader);
Jian Li60312252018-05-10 18:40:32 +0900745 }
746
747 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900748 public void event(InstancePortEvent event) {
749 InstancePort instPort = event.subject();
750
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900751 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
Jian Lie1a39032018-06-19 21:49:36 +0900752 NetFloatingIP fip = associatedFloatingIp(instPort, ips);
753 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
754
Jian Li60312252018-05-10 18:40:32 +0900755 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900756 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Lie1a39032018-06-19 21:49:36 +0900757
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900758 osRouterAdminService.floatingIps().stream()
Jian Li46b74002018-07-15 18:39:08 +0900759 .filter(f -> f.getPortId() != null)
760 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li8f64feb2018-07-24 13:20:16 +0900761 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
Jian Lie1a39032018-06-19 21:49:36 +0900762
Jian Li60312252018-05-10 18:40:32 +0900763 break;
Jian Lie1a39032018-06-19 21:49:36 +0900764 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
765
766 if (gateways.size() == 1) {
767 return;
768 }
769
770 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900771 eventExecutor.execute(() ->
Jian Lie1a39032018-06-19 21:49:36 +0900772 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
Jian Liec5c32b2018-07-13 14:28:58 +0900773 gateways, true)
774 );
Jian Lie1a39032018-06-19 21:49:36 +0900775 }
776
777 break;
778 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
779
Jian Liec5c32b2018-07-13 14:28:58 +0900780 InstancePort revisedInstPort = swapStaleLocation(event.subject());
781
Jian Lie1a39032018-06-19 21:49:36 +0900782 if (gateways.size() == 1) {
783 return;
784 }
785
786 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900787 DeviceId newDeviceId = event.subject().deviceId();
788 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Lie1a39032018-06-19 21:49:36 +0900789
790 OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
791 OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
792
793 if (oldGw != null && oldGw.equals(newGw)) {
794 return;
795 }
796
797 eventExecutor.execute(() ->
Jian Liec5c32b2018-07-13 14:28:58 +0900798 setFloatingIpArpRuleWithPortEvent(fip,
799 revisedInstPort, gateways, false));
Jian Lie1a39032018-06-19 21:49:36 +0900800 }
801 break;
802 default:
803 break;
804 }
Jian Li60312252018-05-10 18:40:32 +0900805 }
806 }
Jian Lif96685c2018-05-21 14:14:16 +0900807
808 private class InternalNodeEventListener implements OpenstackNodeListener {
809
810 @Override
811 public boolean isRelevant(OpenstackNodeEvent event) {
812 // do not allow to proceed without leadership
813 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900814 return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
Jian Lif96685c2018-05-21 14:14:16 +0900815 }
816
817 @Override
818 public void event(OpenstackNodeEvent event) {
819 OpenstackNode osNode = event.subject();
820 switch (event.type()) {
821 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900822 setDefaultArpRule(osNode, true);
823 setFloatingIpArpRuleForGateway(osNode, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900824 sendGratuitousArpToSwitch(event.subject(), true);
Jian Lif96685c2018-05-21 14:14:16 +0900825 break;
826 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900827 setDefaultArpRule(osNode, false);
828 setFloatingIpArpRuleForGateway(osNode, false);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900829 sendGratuitousArpToSwitch(event.subject(), false);
Jian Lif96685c2018-05-21 14:14:16 +0900830 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900831 case OPENSTACK_NODE_REMOVED:
832 sendGratuitousArpToSwitch(event.subject(), false);
833 break;
834
Jian Lif96685c2018-05-21 14:14:16 +0900835 default:
836 break;
837 }
838 }
839
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900840 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
841 Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
842
843 if (isCompleteCase) {
844 osNodeService.completeNodes(COMPUTE)
845 .stream()
846 .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
847 .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
848
849 } else {
850 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
851 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
852 oldCompleteGws.add(gatewayNode);
853
854 osNodeService.completeNodes(COMPUTE)
855 .stream()
856 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
857 .forEach(node -> {
858 OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
859 processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
860 });
861 }
862 }
863
864 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
865 OpenstackNode computeNode,
866 OpenstackNode gwNode) {
867 return OpenstackNetworkingUtil
868 .getGwByComputeDevId(gws, computeNode.intgBridge())
869 .intgBridge().equals(gwNode.intgBridge());
870 }
871
872 private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
873 instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
874 NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
875 osRouterAdminService);
876 Network network = osNetworkService.network(instancePort.networkId());
877 ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
878 osNetworkService, osRouterAdminService);
879 if (floatingIP != null && externalPeerRouter != null) {
880 processGratuitousArpPacketForFloatingIp(
881 floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
882 }
883 });
884 }
885
Jian Lif96685c2018-05-21 14:14:16 +0900886 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900887
888 if (getArpMode() == null) {
889 return;
890 }
891
Jian Li7f70bb72018-07-06 23:35:30 +0900892 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900893 case ARP_PROXY_MODE:
894 setDefaultArpRuleForProxyMode(osNode, install);
895 break;
896 case ARP_BROADCAST_MODE:
897 setDefaultArpRuleForBroadcastMode(osNode, install);
898 break;
899 default:
900 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900901 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900902 break;
903 }
904 }
905
906 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
907 TrafficSelector selector = DefaultTrafficSelector.builder()
908 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
909 .build();
910
911 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
912 .punt()
913 .build();
914
915 osFlowRuleService.setRule(
916 appId,
917 osNode.intgBridge(),
918 selector,
919 treatment,
920 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900921 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900922 install
923 );
924 }
925
926 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
927 // we only match ARP_REPLY in gateway node, because controller
928 // somehow need to process ARP_REPLY which is issued from
929 // external router...
930 TrafficSelector selector = DefaultTrafficSelector.builder()
931 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
932 .matchArpOp(ARP.OP_REPLY)
933 .build();
934
935 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
936 .punt()
937 .build();
938
939 osFlowRuleService.setRule(
940 appId,
941 osNode.intgBridge(),
942 selector,
943 treatment,
944 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900945 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900946 install
947 );
Daniel Park96f1e032018-08-09 13:30:57 +0900948
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900949 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +0900950 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +0900951 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +0900952 }
953 }
Daniel Park81a61a12016-02-26 08:24:44 +0900954}