blob: 4f2c344a4e7e1d4371381b6805a7743afacc9382 [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;
Jian Li528f96e2020-04-29 23:36:15 +090035import org.onosproject.net.Device;
Hyunsun Moon0d457362017-06-27 17:19:41 +090036import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090037import org.onosproject.net.PortNumber;
Jian Li528f96e2020-04-29 23:36:15 +090038import org.onosproject.net.device.DeviceService;
Jian Li60312252018-05-10 18:40:32 +090039import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090040import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090041import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090042import org.onosproject.net.flow.TrafficTreatment;
43import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070044import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090045import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070046import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090047import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090048import org.onosproject.openstacknetworking.api.Constants;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090049import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Li60312252018-05-10 18:40:32 +090050import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li581f21a2018-10-12 09:33:56 +090051import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090052import org.onosproject.openstacknetworking.api.InstancePortEvent;
53import org.onosproject.openstacknetworking.api.InstancePortListener;
Jian Li60312252018-05-10 18:40:32 +090054import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090055import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Li809b3ed2018-10-14 20:49:33 +090056import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
57import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090058import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090059import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Li60312252018-05-10 18:40:32 +090060import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
61import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li581f21a2018-10-12 09:33:56 +090062import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090063import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090064import org.onosproject.openstacknode.api.OpenstackNodeEvent;
65import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090066import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li34220ea2018-11-14 01:30:24 +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 Li60312252018-05-10 18:40:32 +090072import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070073import org.osgi.service.component.annotations.Activate;
74import org.osgi.service.component.annotations.Component;
75import org.osgi.service.component.annotations.Deactivate;
76import org.osgi.service.component.annotations.Modified;
77import org.osgi.service.component.annotations.Reference;
78import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090079import org.slf4j.Logger;
80
81import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090083import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070084import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090085import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090086
Jian Li4d138702018-11-27 17:25:28 +090087import static java.util.Objects.requireNonNull;
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;
Jian Lia5c7edf2020-02-24 16:42:24 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalGatewayIp;
Jian Li32b03622018-11-06 17:54:24 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.floatingIpByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900107import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +0900108import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900109import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li528f96e2020-04-29 23:36:15 +0900110import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
111import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
112import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900113import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900114import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900115import static org.slf4j.LoggerFactory.getLogger;
116
117/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900119 */
Ray Milkey8e406512018-10-24 15:56:50 -0700120@Component(
121 immediate = true,
122 property = {
123 ARP_MODE + "=" + ARP_MODE_DEFAULT
124 }
125)
Daniel Park81a61a12016-02-26 08:24:44 +0900126public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700128 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900129
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
131 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900132 private static final String ARP_MODE = "arpMode";
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900135 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700138 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900141 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900144 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parke49eb382017-04-05 16:48:28 +0900147 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900150 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li528f96e2020-04-29 23:36:15 +0900153 protected DeviceService deviceService;
154
155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900156 protected ClusterService clusterService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900159 protected LeadershipService leadershipService;
160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900162 protected OpenstackFlowRuleService osFlowRuleService;
163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li1064e4f2018-05-29 16:16:53 +0900165 protected OpenstackNetworkService osNetworkService;
166
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700167 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900168 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900169
Ray Milkey0b18b722018-10-16 13:19:15 -0700170 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900171 protected PreCommitPortService preCommitPortService;
172
Ray Milkey8e406512018-10-24 15:56:50 -0700173 /** ARP processing mode, broadcast | proxy (default). **/
174 protected String arpMode = ARP_MODE_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900175
Ray Milkey8e406512018-10-24 15:56:50 -0700176 protected String gatewayMac = GATEWAY_MAC_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900177
178 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900179 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900180 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900181 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900182
183 private ApplicationId appId;
184 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900185
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 private final ExecutorService eventExecutor = newSingleThreadExecutor(
187 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700188
Hyunsun Moon0d457362017-06-27 17:19:41 +0900189 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700190
191 @Activate
192 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900193 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
194 configService.registerProperties(getClass());
195 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900196 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900197 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900198 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900199 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900200 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700201 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
202 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900203 }
204
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700205 @Deactivate
206 protected void deactivate() {
207 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900208 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900209 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900210 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900211 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900212 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900213 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900215 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700216 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900217 }
218
Jian Li60312252018-05-10 18:40:32 +0900219 @Modified
Jian Li4d138702018-11-27 17:25:28 +0900220 protected void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900221 log.info("Modified");
222 }
223
Jian Li7f70bb72018-07-06 23:35:30 +0900224 private String getArpMode() {
225 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
226 return getPropertyValue(properties, ARP_MODE);
227 }
228
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700229 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900230 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900231
Jian Li7f70bb72018-07-06 23:35:30 +0900232 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900233 if (log.isTraceEnabled()) {
234 log.trace("ARP request received from {} for {}",
235 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
236 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
237 }
238
239 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900240
241 MacAddress targetMac = null;
242
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900243 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900244 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
245 .findAny().orElse(null);
246
daniel park576969a2018-03-09 07:07:41 +0900247 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900248 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900249 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
250 if (instPort == null) {
251 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
252 return;
253 } else {
254 targetMac = instPort.macAddress();
255 }
256
Jian Li32b03622018-11-06 17:54:24 +0900257 OpenstackNode gw =
258 getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
Daniel Park96f1e032018-08-09 13:30:57 +0900259
260 if (gw == null) {
261 return;
262 }
263
264 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
Jian Li32b03622018-11-06 17:54:24 +0900265 if (!Objects.equals(gw.intgBridge(),
266 context.inPacket().receivedFrom().deviceId())) {
Daniel Park96f1e032018-08-09 13:30:57 +0900267 return;
268 }
daniel parkeeb8e042018-02-21 14:06:58 +0900269 }
270
Daniel Park96f1e032018-08-09 13:30:57 +0900271 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900272 targetMac = Constants.DEFAULT_GATEWAY_MAC;
273 }
274
275 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900276 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
277 return;
278 }
279
daniel parkb5817102018-02-15 00:18:51 +0900280 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
281 targetMac, ethernet);
282
283 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900284 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900285
286 packetService.emit(new DefaultOutboundPacket(
287 context.inPacket().receivedFrom().deviceId(),
288 treatment,
289 ByteBuffer.wrap(ethReply.serialize())));
290
291 context.block();
Jian Li60312252018-05-10 18:40:32 +0900292 }
293
294 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900295 ConnectPoint cp = context.inPacket().receivedFrom();
296 PortNumber receivedPortNum = cp.port();
297 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
298 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
299
300 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
301
daniel parkb5817102018-02-15 00:18:51 +0900302 try {
Jian Li14a79f22018-06-05 03:44:22 +0900303
Jian Li32b03622018-11-06 17:54:24 +0900304 Set<String> extRouterIps = osNetworkService.externalPeerRouters()
305 .stream()
306 .map(r -> r.ipAddress().toString())
307 .collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900308
Jian Lid4066ea2018-06-07 01:44:45 +0900309 // if SPA is NOT contained in existing external router IP set, we ignore it
310 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900311 return;
312 }
313
314 OpenstackNode node = osNodeService.node(cp.deviceId());
315
316 if (node == null) {
317 return;
318 }
319
320 // we only handles the ARP-Reply message received by gateway node
321 if (node.type() != GATEWAY) {
322 return;
323 }
324
325 if (receivedPortNum.equals(node.uplinkPortNum())) {
326 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900327 }
328 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900329 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900330 }
Daniel Park81a61a12016-02-26 08:24:44 +0900331 }
Daniel Park81a61a12016-02-26 08:24:44 +0900332 }
333
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700334 private class InternalPacketProcessor implements PacketProcessor {
335
336 @Override
337 public void process(PacketContext context) {
338 if (context.isHandled()) {
339 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900340 }
341
Jian Li34220ea2018-11-14 01:30:24 +0900342 InboundPacket pkt = context.inPacket();
343 Ethernet ethernet = pkt.parsed();
344 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
345 eventExecutor.execute(() -> {
346
347 if (!isRelevantHelper(context)) {
348 return;
349 }
350
351 processArpPacket(context, ethernet);
352 });
353 }
354 }
355
356 private boolean isRelevantHelper(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900357 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
358 .stream().map(OpenstackNode::intgBridge)
359 .collect(Collectors.toSet());
360
Jian Li34220ea2018-11-14 01:30:24 +0900361 return gateways.contains(context.inPacket().receivedFrom().deviceId());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700362 }
363 }
364
daniel parkeeb8e042018-02-21 14:06:58 +0900365 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900366 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900367 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900368 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900369 .flatMap(osPort -> osPort.getFixedIps().stream())
370 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900371 }
Jian Li60312252018-05-10 18:40:32 +0900372
Jian Li60312252018-05-10 18:40:32 +0900373 /**
374 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900375 *
376 * @param gateway gateway node
377 * @param install flow rule installation flag
378 */
Jian Li32b03622018-11-06 17:54:24 +0900379 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway,
380 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900381 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900382
383 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
384 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
385 finalGws.addAll(ImmutableSet.copyOf(completedGws));
386
387 if (install) {
388 if (completedGws.contains(gateway)) {
389 if (completedGws.size() > 1) {
390 finalGws.remove(gateway);
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, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900395 finalGws.add(gateway);
396 }
397 });
398 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900399 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900400 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900401 setFloatingIpArpRule(fip, fip.getPortId(),
402 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900403 }
404 });
405 } else {
406 log.warn("Detected node should be included in completed gateway set");
407 }
408 } else {
409 if (!completedGws.contains(gateway)) {
410 finalGws.add(gateway);
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, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900415 }
416 });
417 finalGws.remove(gateway);
Jian Li4d138702018-11-27 17:25:28 +0900418 if (!completedGws.isEmpty()) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900419 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900420 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900421 setFloatingIpArpRule(fip, fip.getPortId(),
422 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900423 }
424 });
425 }
426 } else {
427 log.warn("Detected node should NOT be included in completed gateway set");
428 }
429 }
430 }
431 }
432
433 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900434 * Installs/uninstalls ARP flow rules to the corresponding gateway by
435 * looking for compute node's device ID.
436 *
437 * @param fip floating IP
438 * @param port instance port
439 * @param gateways a collection of gateways
440 * @param install install flag
441 */
442 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
443 InstancePort port,
444 Set<OpenstackNode> gateways,
445 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900446 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900447
448 OpenstackNode gw = getGwByInstancePort(gateways, port);
449
450 if (gw == null) {
451 return;
452 }
453
454 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
455
456 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
457 }
458 }
459
460 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900461 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900462 * Note that, those rules will be only matched ARP_REQUEST packets,
463 * used for telling gateway node the mapped MAC address of requested IP,
464 * without the helps from controller.
465 *
466 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900467 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900468 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900469 * @param install flow rule installation flag
470 */
Jian Li8f64feb2018-07-24 13:20:16 +0900471 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900472 Set<OpenstackNode> gateways,
473 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900474 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900475
476 if (fip == null) {
477 log.warn("Failed to set ARP broadcast rule for floating IP");
478 return;
479 }
480
Jian Li581f21a2018-10-12 09:33:56 +0900481 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900482 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900483 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900484 return;
485 }
486
Jian Li8f64feb2018-07-24 13:20:16 +0900487 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900488 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900489
Jian Lia171a432018-06-11 11:52:11 +0900490 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900491
492 if (gw == null) {
493 return;
494 }
495
Jian Li581f21a2018-10-12 09:33:56 +0900496 if (install) {
497 preCommitPortService.subscribePreCommit(instPort.portId(),
498 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
Jian Li4d138702018-11-27 17:25:28 +0900499 log.info("Subscribed the port {} on listening pre-remove event",
500 instPort.portId());
Jian Li581f21a2018-10-12 09:33:56 +0900501 } else {
502 preCommitPortService.unsubscribePreCommit(instPort.portId(),
Jian Li4d138702018-11-27 17:25:28 +0900503 OPENSTACK_PORT_PRE_REMOVE, instancePortService,
504 this.getClass().getName());
505 log.info("Unsubscribed the port {} on listening pre-remove event",
506 instPort.portId());
Jian Li581f21a2018-10-12 09:33:56 +0900507 }
508
Jian Li24ec59f2018-05-23 19:01:25 +0900509 setArpRule(fip, targetMac, gw, install);
510 }
511 }
Jian Li60312252018-05-10 18:40:32 +0900512
Jian Li24ec59f2018-05-23 19:01:25 +0900513 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
514 OpenstackNode gateway, boolean install) {
515 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900516 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900517 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
518 .matchArpOp(ARP.OP_REQUEST)
519 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
520 .build();
Jian Li60312252018-05-10 18:40:32 +0900521
Jian Li528f96e2020-04-29 23:36:15 +0900522 Device device = deviceService.getDevice(gateway.intgBridge());
523
Jian Li24ec59f2018-05-23 19:01:25 +0900524 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li528f96e2020-04-29 23:36:15 +0900525 .extension(buildMoveEthSrcToDstExtension(device), device.id())
526 .extension(buildMoveArpShaToThaExtension(device), device.id())
527 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
Jian Li24ec59f2018-05-23 19:01:25 +0900528 .setArpOp(ARP.OP_REPLY)
Jian Li528f96e2020-04-29 23:36:15 +0900529 .setEthSrc(targetMac)
Jian Li24ec59f2018-05-23 19:01:25 +0900530 .setArpSha(targetMac)
531 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
532 .setOutput(PortNumber.IN_PORT)
533 .build();
Jian Li60312252018-05-10 18:40:32 +0900534
Jian Li24ec59f2018-05-23 19:01:25 +0900535 osFlowRuleService.setRule(
536 appId,
537 gateway.intgBridge(),
538 selector,
539 treatment,
540 PRIORITY_ARP_GATEWAY_RULE,
541 GW_COMMON_TABLE,
542 install
543 );
544
545 if (install) {
546 log.info("Install ARP Rule for Floating IP {}",
547 fip.getFloatingIpAddress());
548 } else {
549 log.info("Uninstall ARP Rule for Floating IP {}",
550 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900551 }
552 }
553
Jian Li809b3ed2018-10-14 20:49:33 +0900554 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900555 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900556 IpAddress externalIp = externalGatewayIp(router, osNetworkService);
Jian Li34220ea2018-11-14 01:30:24 +0900557
558 if (externalIp == null) {
559 log.debug("External IP is not found");
560 return;
561 }
562
563 setFakeGatewayArpRuleByExternalIp(externalIp, install);
Jian Li809b3ed2018-10-14 20:49:33 +0900564 }
565 }
Daniel Park96f1e032018-08-09 13:30:57 +0900566
Jian Liebde74d2018-11-14 00:18:57 +0900567 private void setFakeGatewayArpRuleByExternalIp(IpAddress ipAddress, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900568
Jian Liebde74d2018-11-14 00:18:57 +0900569 TrafficSelector selector = DefaultTrafficSelector.builder()
570 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
571 .matchArpOp(ARP.OP_REQUEST)
572 .matchArpTpa(ipAddress.getIp4Address())
573 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900574
Jian Liaec1b132020-04-30 12:00:13 +0900575 osNodeService.completeNodes(GATEWAY).forEach(n -> {
576 Device device = deviceService.getDevice(n.intgBridge());
Daniel Park96f1e032018-08-09 13:30:57 +0900577
Jian Liaec1b132020-04-30 12:00:13 +0900578 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
579 .extension(buildMoveEthSrcToDstExtension(device), device.id())
580 .extension(buildMoveArpShaToThaExtension(device), device.id())
581 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
582 .setArpOp(ARP.OP_REPLY)
583 .setEthSrc(MacAddress.valueOf(gatewayMac))
584 .setArpSha(MacAddress.valueOf(gatewayMac))
585 .setArpSpa(ipAddress.getIp4Address())
586 .setOutput(PortNumber.IN_PORT)
587 .build();
588
Jian Liebde74d2018-11-14 00:18:57 +0900589 osFlowRuleService.setRule(
590 appId,
591 n.intgBridge(),
592 selector,
593 treatment,
594 PRIORITY_ARP_GATEWAY_RULE,
595 GW_COMMON_TABLE,
596 install
Jian Liaec1b132020-04-30 12:00:13 +0900597 );
598 }
Jian Liebde74d2018-11-14 00:18:57 +0900599 );
600
601 if (install) {
602 log.info("Install ARP Rule for Gateway Snat {}", ipAddress);
603 } else {
604 log.info("Uninstall ARP Rule for Gateway Snat {}", ipAddress);
605 }
Jian Li809b3ed2018-10-14 20:49:33 +0900606 }
607
608 /**
609 * An internal network event listener, intended to uninstall ARP rules for
610 * routing the packets destined to external gateway.
611 */
612 private class InternalNetworkEventListener implements OpenstackNetworkListener {
613
614 @Override
615 public boolean isRelevant(OpenstackNetworkEvent event) {
616 Port osPort = event.port();
617 if (osPort == null || osPort.getFixedIps() == null) {
618 return false;
619 }
620
Jian Li34220ea2018-11-14 01:30:24 +0900621 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
622 ARP_BROADCAST_MODE.equals(getArpMode());
623 }
624
625 private boolean isRelevantHelper() {
626 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li809b3ed2018-10-14 20:49:33 +0900627 }
628
629 @Override
630 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900631 IpAddress ipAddress = externalIp(event.port());
Jian Li809b3ed2018-10-14 20:49:33 +0900632 switch (event.type()) {
633 case OPENSTACK_PORT_CREATED:
634 case OPENSTACK_PORT_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900635 eventExecutor.execute(() -> processPortCreation(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900636 break;
637 case OPENSTACK_PORT_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900638 eventExecutor.execute(() -> processPortRemoval(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900639 break;
640 default:
641 // do nothing
642 break;
643 }
Daniel Park96f1e032018-08-09 13:30:57 +0900644 }
Jian Li34220ea2018-11-14 01:30:24 +0900645
Jian Li4d138702018-11-27 17:25:28 +0900646 private void processPortCreation(IpAddress ipAddress) {
647 if (!isRelevantHelper() || ipAddress == null) {
648 return;
649 }
650
651 setFakeGatewayArpRuleByExternalIp(ipAddress, true);
652 }
653
654 private void processPortRemoval(IpAddress ipAddress) {
655 if (!isRelevantHelper() || ipAddress == null) {
656 return;
657 }
658
659 setFakeGatewayArpRuleByExternalIp(ipAddress, false);
660 }
661
Jian Li34220ea2018-11-14 01:30:24 +0900662 private IpAddress externalIp(Port port) {
663 IP ip = port.getFixedIps().stream().findAny().orElse(null);
664
665 if (ip != null && ip.getIpAddress() != null) {
666 return IpAddress.valueOf(ip.getIpAddress());
667 }
668
669 return null;
670 }
Daniel Park96f1e032018-08-09 13:30:57 +0900671 }
672
Jian Li60312252018-05-10 18:40:32 +0900673 /**
674 * An internal router event listener, intended to install/uninstall
675 * ARP rules for forwarding packets created from floating IPs.
676 */
677 private class InternalRouterEventListener implements OpenstackRouterListener {
678
Jian Li34220ea2018-11-14 01:30:24 +0900679 private boolean isRelevantHelper() {
680 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900681 }
682
683 @Override
684 public void event(OpenstackRouterEvent event) {
685 switch (event.type()) {
686 case OPENSTACK_ROUTER_CREATED:
Jian Liebde74d2018-11-14 00:18:57 +0900687 // add a router with external gateway
688 case OPENSTACK_ROUTER_GATEWAY_ADDED:
689 // add a gateway manually after adding a router
Jian Li4d138702018-11-27 17:25:28 +0900690 eventExecutor.execute(() -> processRouterGwCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900691 break;
692 case OPENSTACK_ROUTER_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900693 // remove a router with external gateway
Jian Li60312252018-05-10 18:40:32 +0900694 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900695 // remove a gateway from an existing router
Jian Li4d138702018-11-27 17:25:28 +0900696 eventExecutor.execute(() -> processRouterGwRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900697 break;
698 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900699 // during floating IP creation, if the floating IP is
700 // associated with any port of VM, then we will set
701 // floating IP related ARP rules to gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900702 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900703 eventExecutor.execute(() -> processFloatingIpCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900704 break;
705 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900706 // during floating IP deletion, if the floating IP is
707 // still associated with any port of VM, then we will
708 // remove floating IP related ARP rules from gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900709 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900710 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900711 break;
712 default:
713 // do nothing for the other events
714 break;
715 }
716 }
717
Jian Li4d138702018-11-27 17:25:28 +0900718 private void processRouterGwCreation(OpenstackRouterEvent event) {
719 if (!isRelevantHelper()) {
720 return;
721 }
722
723 // add a router with external gateway
724 setFakeGatewayArpRuleByRouter(event.subject(), true);
725 }
726
727 private void processRouterGwRemoval(OpenstackRouterEvent event) {
728 if (!isRelevantHelper()) {
729 return;
730 }
731
732 setFakeGatewayArpRuleByRouter(event.subject(), false);
733 }
734
735 private void processFloatingIpCreation(OpenstackRouterEvent event) {
736 if (!isRelevantHelper()) {
737 return;
738 }
739
740 if (getValidPortId(event) == null) {
741 return;
742 }
743
744 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
745
746 // associate a floating IP with an existing VM
747 setFloatingIpArpRule(event.floatingIp(),
748 getValidPortId(event), completedGws, true);
749 }
750
751 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
752 if (!isRelevantHelper()) {
753 return;
754 }
755
756 if (getValidPortId(event) == null) {
757 return;
758 }
759
760 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
761
762 // disassociate a floating IP with an existing VM
763 setFloatingIpArpRule(event.floatingIp(),
764 getValidPortId(event), completedGws, false);
765 }
766
Jian Lida03ce92018-07-24 21:41:53 +0900767 private String getValidPortId(OpenstackRouterEvent event) {
768 NetFloatingIP osFip = event.floatingIp();
769 String portId = osFip.getPortId();
770
771 if (Strings.isNullOrEmpty(portId)) {
772 portId = event.portId();
773 }
774
775 if (portId != null && instancePortService.instancePort(portId) != null) {
776 return portId;
777 }
778
779 return null;
780 }
Jian Li60312252018-05-10 18:40:32 +0900781 }
782
Jian Lie1a39032018-06-19 21:49:36 +0900783 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900784
Jian Li34220ea2018-11-14 01:30:24 +0900785 private boolean isRelevantHelper() {
786 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900787 }
788
789 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900790 public void event(InstancePortEvent event) {
791 InstancePort instPort = event.subject();
Jian Li60312252018-05-10 18:40:32 +0900792 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900793 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900794 eventExecutor.execute(() ->
795 processInstanceDetection(event, instPort));
Jian Li34220ea2018-11-14 01:30:24 +0900796
Jian Li60312252018-05-10 18:40:32 +0900797 break;
Jian Lie1a39032018-06-19 21:49:36 +0900798 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900799 eventExecutor.execute(() ->
800 processInstanceMigrationStart(event, instPort));
Jian Li32b03622018-11-06 17:54:24 +0900801
802 break;
803 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900804 eventExecutor.execute(() ->
805 processInstanceMigrationEnd(event, instPort));
Jian Lie1a39032018-06-19 21:49:36 +0900806 break;
807 default:
808 break;
809 }
Jian Li60312252018-05-10 18:40:32 +0900810 }
Jian Li4d138702018-11-27 17:25:28 +0900811
812 private void processInstanceDetection(InstancePortEvent event,
813 InstancePort instPort) {
814 if (!isRelevantHelper()) {
815 return;
816 }
817
818 osRouterAdminService.floatingIps().stream()
819 .filter(f -> f.getPortId() != null)
820 .filter(f -> f.getPortId().equals(instPort.portId()))
821 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(),
822 osNodeService.completeNodes(GATEWAY), true));
823 }
824
825 private void processInstanceMigrationStart(InstancePortEvent event,
826 InstancePort instPort) {
827 if (!isRelevantHelper()) {
828 return;
829 }
830
831 NetFloatingIP fip = associatedFloatingIp(instPort,
832 osRouterAdminService.floatingIps());
833
834 if (osNodeService.completeNodes(GATEWAY).size() == 1) {
835 return;
836 }
837
838 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
839 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
840 osNodeService.completeNodes(GATEWAY), true);
841 }
842 }
843
844 private void processInstanceMigrationEnd(InstancePortEvent event,
845 InstancePort instPort) {
846 if (!isRelevantHelper()) {
847 return;
848 }
849
850 NetFloatingIP fip = associatedFloatingIp(instPort,
851 osRouterAdminService.floatingIps());
852 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
853
854 InstancePort revisedInstPort = swapStaleLocation(event.subject());
855
856 if (gateways.size() == 1) {
857 return;
858 }
859
860 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
861 DeviceId newDeviceId = event.subject().deviceId();
862 DeviceId oldDeviceId = revisedInstPort.deviceId();
863
864 OpenstackNode oldGw =
865 getGwByComputeDevId(gateways, oldDeviceId);
866 OpenstackNode newGw =
867 getGwByComputeDevId(gateways, newDeviceId);
868
869 if (oldGw != null && oldGw.equals(newGw)) {
870 return;
871 }
872
873 setFloatingIpArpRuleWithPortEvent(fip,
874 revisedInstPort, gateways, false);
875 }
876 }
Jian Li60312252018-05-10 18:40:32 +0900877 }
Jian Lif96685c2018-05-21 14:14:16 +0900878
879 private class InternalNodeEventListener implements OpenstackNodeListener {
880
881 @Override
882 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900883 return event.subject().type() == GATEWAY;
884 }
885
886 private boolean isRelevantHelper() {
887 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lif96685c2018-05-21 14:14:16 +0900888 }
889
890 @Override
891 public void event(OpenstackNodeEvent event) {
892 OpenstackNode osNode = event.subject();
893 switch (event.type()) {
894 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900895 eventExecutor.execute(() -> processNodeCompletion(event, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900896 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900897 case OPENSTACK_NODE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900898 eventExecutor.execute(() -> processNodeRemoval(event));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900899 break;
Jian Li238552d2019-09-24 22:32:02 +0900900 case OPENSTACK_NODE_INCOMPLETE:
Jian Lif96685c2018-05-21 14:14:16 +0900901 default:
902 break;
903 }
904 }
905
Jian Li4d138702018-11-27 17:25:28 +0900906 private void processNodeCompletion(OpenstackNodeEvent event, OpenstackNode node) {
907 if (!isRelevantHelper()) {
908 return;
909 }
910 setDefaultArpRule(node, true);
911 setFloatingIpArpRuleForGateway(node, true);
912 sendGratuitousArpToSwitch(event.subject(), true);
913 }
914
915 private void processNodeIncompletion(OpenstackNodeEvent event, OpenstackNode node) {
916 if (!isRelevantHelper()) {
917 return;
918 }
919 setDefaultArpRule(node, false);
920 setFloatingIpArpRuleForGateway(node, false);
921 sendGratuitousArpToSwitch(event.subject(), false);
922 }
923
924 private void processNodeRemoval(OpenstackNodeEvent event) {
925 if (!isRelevantHelper()) {
926 return;
927 }
928 sendGratuitousArpToSwitch(event.subject(), false);
929 }
930
Jian Li32b03622018-11-06 17:54:24 +0900931 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
932 boolean isCompleteCase) {
933 Set<OpenstackNode> completeGws =
934 ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900935
936 if (isCompleteCase) {
Jian Li32b03622018-11-06 17:54:24 +0900937 osNodeService.completeNodes(COMPUTE).stream()
938 .filter(node -> isGwSelectedByComputeNode(completeGws,
939 node, gatewayNode))
940 .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900941
942 } else {
943 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
944 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
945 oldCompleteGws.add(gatewayNode);
946
Jian Li32b03622018-11-06 17:54:24 +0900947 osNodeService.completeNodes(COMPUTE).stream()
948 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
949 node, gatewayNode))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900950 .forEach(node -> {
Jian Li32b03622018-11-06 17:54:24 +0900951 OpenstackNode newSelectedGatewayNode =
952 getGwByComputeDevId(completeGws, node.intgBridge());
953 processGarpPacketForComputeNode(node, newSelectedGatewayNode);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900954 });
955 }
956 }
957
958 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
959 OpenstackNode computeNode,
960 OpenstackNode gwNode) {
Jian Li4d138702018-11-27 17:25:28 +0900961 return requireNonNull(getGwByComputeDevId(gws, computeNode.intgBridge()))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900962 .intgBridge().equals(gwNode.intgBridge());
963 }
964
Jian Li32b03622018-11-06 17:54:24 +0900965 private void processGarpPacketForComputeNode(OpenstackNode computeNode,
966 OpenstackNode gatewayNode) {
967 instancePortService.instancePort(computeNode.intgBridge())
968 .forEach(instancePort -> {
969 NetFloatingIP floatingIP =
970 floatingIpByInstancePort(instancePort, osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900971 Network network = osNetworkService.network(instancePort.networkId());
Jian Li32b03622018-11-06 17:54:24 +0900972 ExternalPeerRouter externalPeerRouter =
973 externalPeerRouterForNetwork(network, osNetworkService,
974 osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900975 if (floatingIP != null && externalPeerRouter != null) {
Jian Li32b03622018-11-06 17:54:24 +0900976 processGarpPacketForFloatingIp(
977 floatingIP, instancePort, externalPeerRouter.vlanId(),
978 gatewayNode, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900979 }
980 });
981 }
982
Jian Lif96685c2018-05-21 14:14:16 +0900983 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900984
985 if (getArpMode() == null) {
986 return;
987 }
Jian Liebde74d2018-11-14 00:18:57 +0900988 log.info("ARP mode is {}", getArpMode());
Jian Lib6969502018-10-30 20:38:07 +0900989
Jian Li7f70bb72018-07-06 23:35:30 +0900990 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900991 case ARP_PROXY_MODE:
992 setDefaultArpRuleForProxyMode(osNode, install);
993 break;
994 case ARP_BROADCAST_MODE:
995 setDefaultArpRuleForBroadcastMode(osNode, install);
996 break;
997 default:
998 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900999 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +09001000 break;
1001 }
1002 }
1003
Jian Li32b03622018-11-06 17:54:24 +09001004 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
1005 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +09001006 TrafficSelector selector = DefaultTrafficSelector.builder()
1007 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1008 .build();
1009
1010 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1011 .punt()
1012 .build();
1013
1014 osFlowRuleService.setRule(
1015 appId,
1016 osNode.intgBridge(),
1017 selector,
1018 treatment,
1019 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001020 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001021 install
1022 );
1023 }
1024
Jian Li32b03622018-11-06 17:54:24 +09001025 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
1026 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +09001027 // we only match ARP_REPLY in gateway node, because controller
1028 // somehow need to process ARP_REPLY which is issued from
1029 // external router...
1030 TrafficSelector selector = DefaultTrafficSelector.builder()
1031 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1032 .matchArpOp(ARP.OP_REPLY)
1033 .build();
1034
1035 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1036 .punt()
1037 .build();
1038
1039 osFlowRuleService.setRule(
1040 appId,
1041 osNode.intgBridge(),
1042 selector,
1043 treatment,
1044 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001045 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001046 install
1047 );
Daniel Park96f1e032018-08-09 13:30:57 +09001048
Jian Liebde74d2018-11-14 00:18:57 +09001049 log.info("calling setFakeGatewayArpRuleByRouter.. ");
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001050 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +09001051 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +09001052 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +09001053 }
1054 }
Daniel Park81a61a12016-02-26 08:24:44 +09001055}