blob: 0ea250486b14447a5d811ff25cf09b4daead906d [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 Liebde74d2018-11-14 00:18:57 +0900575 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
576 .setArpOp(ARP.OP_REPLY)
577 .setArpSha(MacAddress.valueOf(gatewayMac))
578 .setArpSpa(ipAddress.getIp4Address())
579 .setOutput(PortNumber.IN_PORT)
580 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900581
Jian Liebde74d2018-11-14 00:18:57 +0900582 osNodeService.completeNodes(GATEWAY).forEach(n ->
583 osFlowRuleService.setRule(
584 appId,
585 n.intgBridge(),
586 selector,
587 treatment,
588 PRIORITY_ARP_GATEWAY_RULE,
589 GW_COMMON_TABLE,
590 install
591 )
592 );
593
594 if (install) {
595 log.info("Install ARP Rule for Gateway Snat {}", ipAddress);
596 } else {
597 log.info("Uninstall ARP Rule for Gateway Snat {}", ipAddress);
598 }
Jian Li809b3ed2018-10-14 20:49:33 +0900599 }
600
601 /**
602 * An internal network event listener, intended to uninstall ARP rules for
603 * routing the packets destined to external gateway.
604 */
605 private class InternalNetworkEventListener implements OpenstackNetworkListener {
606
607 @Override
608 public boolean isRelevant(OpenstackNetworkEvent event) {
609 Port osPort = event.port();
610 if (osPort == null || osPort.getFixedIps() == null) {
611 return false;
612 }
613
Jian Li34220ea2018-11-14 01:30:24 +0900614 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
615 ARP_BROADCAST_MODE.equals(getArpMode());
616 }
617
618 private boolean isRelevantHelper() {
619 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li809b3ed2018-10-14 20:49:33 +0900620 }
621
622 @Override
623 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900624 IpAddress ipAddress = externalIp(event.port());
Jian Li809b3ed2018-10-14 20:49:33 +0900625 switch (event.type()) {
626 case OPENSTACK_PORT_CREATED:
627 case OPENSTACK_PORT_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900628 eventExecutor.execute(() -> processPortCreation(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900629 break;
630 case OPENSTACK_PORT_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900631 eventExecutor.execute(() -> processPortRemoval(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900632 break;
633 default:
634 // do nothing
635 break;
636 }
Daniel Park96f1e032018-08-09 13:30:57 +0900637 }
Jian Li34220ea2018-11-14 01:30:24 +0900638
Jian Li4d138702018-11-27 17:25:28 +0900639 private void processPortCreation(IpAddress ipAddress) {
640 if (!isRelevantHelper() || ipAddress == null) {
641 return;
642 }
643
644 setFakeGatewayArpRuleByExternalIp(ipAddress, true);
645 }
646
647 private void processPortRemoval(IpAddress ipAddress) {
648 if (!isRelevantHelper() || ipAddress == null) {
649 return;
650 }
651
652 setFakeGatewayArpRuleByExternalIp(ipAddress, false);
653 }
654
Jian Li34220ea2018-11-14 01:30:24 +0900655 private IpAddress externalIp(Port port) {
656 IP ip = port.getFixedIps().stream().findAny().orElse(null);
657
658 if (ip != null && ip.getIpAddress() != null) {
659 return IpAddress.valueOf(ip.getIpAddress());
660 }
661
662 return null;
663 }
Daniel Park96f1e032018-08-09 13:30:57 +0900664 }
665
Jian Li60312252018-05-10 18:40:32 +0900666 /**
667 * An internal router event listener, intended to install/uninstall
668 * ARP rules for forwarding packets created from floating IPs.
669 */
670 private class InternalRouterEventListener implements OpenstackRouterListener {
671
Jian Li34220ea2018-11-14 01:30:24 +0900672 private boolean isRelevantHelper() {
673 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900674 }
675
676 @Override
677 public void event(OpenstackRouterEvent event) {
678 switch (event.type()) {
679 case OPENSTACK_ROUTER_CREATED:
Jian Liebde74d2018-11-14 00:18:57 +0900680 // add a router with external gateway
681 case OPENSTACK_ROUTER_GATEWAY_ADDED:
682 // add a gateway manually after adding a router
Jian Li4d138702018-11-27 17:25:28 +0900683 eventExecutor.execute(() -> processRouterGwCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900684 break;
685 case OPENSTACK_ROUTER_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900686 // remove a router with external gateway
Jian Li60312252018-05-10 18:40:32 +0900687 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900688 // remove a gateway from an existing router
Jian Li4d138702018-11-27 17:25:28 +0900689 eventExecutor.execute(() -> processRouterGwRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900690 break;
691 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900692 // during floating IP creation, if the floating IP is
693 // associated with any port of VM, then we will set
694 // floating IP related ARP rules to gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900695 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900696 eventExecutor.execute(() -> processFloatingIpCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900697 break;
698 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900699 // during floating IP deletion, if the floating IP is
700 // still associated with any port of VM, then we will
701 // remove floating IP related ARP rules from gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900702 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li4d138702018-11-27 17:25:28 +0900703 eventExecutor.execute(() -> processFloatingIpRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900704 break;
705 default:
706 // do nothing for the other events
707 break;
708 }
709 }
710
Jian Li4d138702018-11-27 17:25:28 +0900711 private void processRouterGwCreation(OpenstackRouterEvent event) {
712 if (!isRelevantHelper()) {
713 return;
714 }
715
716 // add a router with external gateway
717 setFakeGatewayArpRuleByRouter(event.subject(), true);
718 }
719
720 private void processRouterGwRemoval(OpenstackRouterEvent event) {
721 if (!isRelevantHelper()) {
722 return;
723 }
724
725 setFakeGatewayArpRuleByRouter(event.subject(), false);
726 }
727
728 private void processFloatingIpCreation(OpenstackRouterEvent event) {
729 if (!isRelevantHelper()) {
730 return;
731 }
732
733 if (getValidPortId(event) == null) {
734 return;
735 }
736
737 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
738
739 // associate a floating IP with an existing VM
740 setFloatingIpArpRule(event.floatingIp(),
741 getValidPortId(event), completedGws, true);
742 }
743
744 private void processFloatingIpRemoval(OpenstackRouterEvent event) {
745 if (!isRelevantHelper()) {
746 return;
747 }
748
749 if (getValidPortId(event) == null) {
750 return;
751 }
752
753 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
754
755 // disassociate a floating IP with an existing VM
756 setFloatingIpArpRule(event.floatingIp(),
757 getValidPortId(event), completedGws, false);
758 }
759
Jian Lida03ce92018-07-24 21:41:53 +0900760 private String getValidPortId(OpenstackRouterEvent event) {
761 NetFloatingIP osFip = event.floatingIp();
762 String portId = osFip.getPortId();
763
764 if (Strings.isNullOrEmpty(portId)) {
765 portId = event.portId();
766 }
767
768 if (portId != null && instancePortService.instancePort(portId) != null) {
769 return portId;
770 }
771
772 return null;
773 }
Jian Li60312252018-05-10 18:40:32 +0900774 }
775
Jian Lie1a39032018-06-19 21:49:36 +0900776 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900777
Jian Li34220ea2018-11-14 01:30:24 +0900778 private boolean isRelevantHelper() {
779 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900780 }
781
782 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900783 public void event(InstancePortEvent event) {
784 InstancePort instPort = event.subject();
Jian Li60312252018-05-10 18:40:32 +0900785 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900786 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li4d138702018-11-27 17:25:28 +0900787 eventExecutor.execute(() ->
788 processInstanceDetection(event, instPort));
Jian Li34220ea2018-11-14 01:30:24 +0900789
Jian Li60312252018-05-10 18:40:32 +0900790 break;
Jian Lie1a39032018-06-19 21:49:36 +0900791 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li4d138702018-11-27 17:25:28 +0900792 eventExecutor.execute(() ->
793 processInstanceMigrationStart(event, instPort));
Jian Li32b03622018-11-06 17:54:24 +0900794
795 break;
796 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li4d138702018-11-27 17:25:28 +0900797 eventExecutor.execute(() ->
798 processInstanceMigrationEnd(event, instPort));
Jian Lie1a39032018-06-19 21:49:36 +0900799 break;
800 default:
801 break;
802 }
Jian Li60312252018-05-10 18:40:32 +0900803 }
Jian Li4d138702018-11-27 17:25:28 +0900804
805 private void processInstanceDetection(InstancePortEvent event,
806 InstancePort instPort) {
807 if (!isRelevantHelper()) {
808 return;
809 }
810
811 osRouterAdminService.floatingIps().stream()
812 .filter(f -> f.getPortId() != null)
813 .filter(f -> f.getPortId().equals(instPort.portId()))
814 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(),
815 osNodeService.completeNodes(GATEWAY), true));
816 }
817
818 private void processInstanceMigrationStart(InstancePortEvent event,
819 InstancePort instPort) {
820 if (!isRelevantHelper()) {
821 return;
822 }
823
824 NetFloatingIP fip = associatedFloatingIp(instPort,
825 osRouterAdminService.floatingIps());
826
827 if (osNodeService.completeNodes(GATEWAY).size() == 1) {
828 return;
829 }
830
831 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
832 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
833 osNodeService.completeNodes(GATEWAY), true);
834 }
835 }
836
837 private void processInstanceMigrationEnd(InstancePortEvent event,
838 InstancePort instPort) {
839 if (!isRelevantHelper()) {
840 return;
841 }
842
843 NetFloatingIP fip = associatedFloatingIp(instPort,
844 osRouterAdminService.floatingIps());
845 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
846
847 InstancePort revisedInstPort = swapStaleLocation(event.subject());
848
849 if (gateways.size() == 1) {
850 return;
851 }
852
853 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
854 DeviceId newDeviceId = event.subject().deviceId();
855 DeviceId oldDeviceId = revisedInstPort.deviceId();
856
857 OpenstackNode oldGw =
858 getGwByComputeDevId(gateways, oldDeviceId);
859 OpenstackNode newGw =
860 getGwByComputeDevId(gateways, newDeviceId);
861
862 if (oldGw != null && oldGw.equals(newGw)) {
863 return;
864 }
865
866 setFloatingIpArpRuleWithPortEvent(fip,
867 revisedInstPort, gateways, false);
868 }
869 }
Jian Li60312252018-05-10 18:40:32 +0900870 }
Jian Lif96685c2018-05-21 14:14:16 +0900871
872 private class InternalNodeEventListener implements OpenstackNodeListener {
873
874 @Override
875 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900876 return event.subject().type() == GATEWAY;
877 }
878
879 private boolean isRelevantHelper() {
880 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lif96685c2018-05-21 14:14:16 +0900881 }
882
883 @Override
884 public void event(OpenstackNodeEvent event) {
885 OpenstackNode osNode = event.subject();
886 switch (event.type()) {
887 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900888 eventExecutor.execute(() -> processNodeCompletion(event, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900889 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900890 case OPENSTACK_NODE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900891 eventExecutor.execute(() -> processNodeRemoval(event));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900892 break;
Jian Li238552d2019-09-24 22:32:02 +0900893 case OPENSTACK_NODE_INCOMPLETE:
Jian Lif96685c2018-05-21 14:14:16 +0900894 default:
895 break;
896 }
897 }
898
Jian Li4d138702018-11-27 17:25:28 +0900899 private void processNodeCompletion(OpenstackNodeEvent event, OpenstackNode node) {
900 if (!isRelevantHelper()) {
901 return;
902 }
903 setDefaultArpRule(node, true);
904 setFloatingIpArpRuleForGateway(node, true);
905 sendGratuitousArpToSwitch(event.subject(), true);
906 }
907
908 private void processNodeIncompletion(OpenstackNodeEvent event, OpenstackNode node) {
909 if (!isRelevantHelper()) {
910 return;
911 }
912 setDefaultArpRule(node, false);
913 setFloatingIpArpRuleForGateway(node, false);
914 sendGratuitousArpToSwitch(event.subject(), false);
915 }
916
917 private void processNodeRemoval(OpenstackNodeEvent event) {
918 if (!isRelevantHelper()) {
919 return;
920 }
921 sendGratuitousArpToSwitch(event.subject(), false);
922 }
923
Jian Li32b03622018-11-06 17:54:24 +0900924 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
925 boolean isCompleteCase) {
926 Set<OpenstackNode> completeGws =
927 ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900928
929 if (isCompleteCase) {
Jian Li32b03622018-11-06 17:54:24 +0900930 osNodeService.completeNodes(COMPUTE).stream()
931 .filter(node -> isGwSelectedByComputeNode(completeGws,
932 node, gatewayNode))
933 .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900934
935 } else {
936 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
937 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
938 oldCompleteGws.add(gatewayNode);
939
Jian Li32b03622018-11-06 17:54:24 +0900940 osNodeService.completeNodes(COMPUTE).stream()
941 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
942 node, gatewayNode))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900943 .forEach(node -> {
Jian Li32b03622018-11-06 17:54:24 +0900944 OpenstackNode newSelectedGatewayNode =
945 getGwByComputeDevId(completeGws, node.intgBridge());
946 processGarpPacketForComputeNode(node, newSelectedGatewayNode);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900947 });
948 }
949 }
950
951 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
952 OpenstackNode computeNode,
953 OpenstackNode gwNode) {
Jian Li4d138702018-11-27 17:25:28 +0900954 return requireNonNull(getGwByComputeDevId(gws, computeNode.intgBridge()))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900955 .intgBridge().equals(gwNode.intgBridge());
956 }
957
Jian Li32b03622018-11-06 17:54:24 +0900958 private void processGarpPacketForComputeNode(OpenstackNode computeNode,
959 OpenstackNode gatewayNode) {
960 instancePortService.instancePort(computeNode.intgBridge())
961 .forEach(instancePort -> {
962 NetFloatingIP floatingIP =
963 floatingIpByInstancePort(instancePort, osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900964 Network network = osNetworkService.network(instancePort.networkId());
Jian Li32b03622018-11-06 17:54:24 +0900965 ExternalPeerRouter externalPeerRouter =
966 externalPeerRouterForNetwork(network, osNetworkService,
967 osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900968 if (floatingIP != null && externalPeerRouter != null) {
Jian Li32b03622018-11-06 17:54:24 +0900969 processGarpPacketForFloatingIp(
970 floatingIP, instancePort, externalPeerRouter.vlanId(),
971 gatewayNode, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900972 }
973 });
974 }
975
Jian Lif96685c2018-05-21 14:14:16 +0900976 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900977
978 if (getArpMode() == null) {
979 return;
980 }
Jian Liebde74d2018-11-14 00:18:57 +0900981 log.info("ARP mode is {}", getArpMode());
Jian Lib6969502018-10-30 20:38:07 +0900982
Jian Li7f70bb72018-07-06 23:35:30 +0900983 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900984 case ARP_PROXY_MODE:
985 setDefaultArpRuleForProxyMode(osNode, install);
986 break;
987 case ARP_BROADCAST_MODE:
988 setDefaultArpRuleForBroadcastMode(osNode, install);
989 break;
990 default:
991 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900992 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900993 break;
994 }
995 }
996
Jian Li32b03622018-11-06 17:54:24 +0900997 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
998 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900999 TrafficSelector selector = DefaultTrafficSelector.builder()
1000 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1001 .build();
1002
1003 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1004 .punt()
1005 .build();
1006
1007 osFlowRuleService.setRule(
1008 appId,
1009 osNode.intgBridge(),
1010 selector,
1011 treatment,
1012 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001013 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001014 install
1015 );
1016 }
1017
Jian Li32b03622018-11-06 17:54:24 +09001018 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
1019 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +09001020 // we only match ARP_REPLY in gateway node, because controller
1021 // somehow need to process ARP_REPLY which is issued from
1022 // external router...
1023 TrafficSelector selector = DefaultTrafficSelector.builder()
1024 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1025 .matchArpOp(ARP.OP_REPLY)
1026 .build();
1027
1028 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1029 .punt()
1030 .build();
1031
1032 osFlowRuleService.setRule(
1033 appId,
1034 osNode.intgBridge(),
1035 selector,
1036 treatment,
1037 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +09001038 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001039 install
1040 );
Daniel Park96f1e032018-08-09 13:30:57 +09001041
Jian Liebde74d2018-11-14 00:18:57 +09001042 log.info("calling setFakeGatewayArpRuleByRouter.. ");
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001043 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +09001044 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +09001045 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +09001046 }
1047 }
Daniel Park81a61a12016-02-26 08:24:44 +09001048}