blob: be7616bcadcbd494866ed72eeb6c0e63df1ba3a0 [file] [log] [blame]
Daniel Park81a61a12016-02-26 08:24:44 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Daniel Park81a61a12016-02-26 08:24:44 +09003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Hyunsun Moon05400872017-02-07 17:11:25 +090016package org.onosproject.openstacknetworking.impl;
Daniel Park81a61a12016-02-26 08:24:44 +090017
Jian Lida03ce92018-07-24 21:41:53 +090018import com.google.common.base.Strings;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li1064e4f2018-05-29 16:16:53 +090020import com.google.common.collect.Sets;
Daniel Park81a61a12016-02-26 08:24:44 +090021import org.onlab.packet.ARP;
Jian Li60312252018-05-10 18:40:32 +090022import org.onlab.packet.EthType;
Daniel Park81a61a12016-02-26 08:24:44 +090023import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090024import org.onlab.packet.Ip4Address;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
Jian Li60312252018-05-10 18:40:32 +090027import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090028import org.onosproject.cfg.ConfigProperty;
Jian Li60312252018-05-10 18:40:32 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Jian Li14a79f22018-06-05 03:44:22 +090034import org.onosproject.net.ConnectPoint;
Hyunsun Moon0d457362017-06-27 17:19:41 +090035import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090036import org.onosproject.net.PortNumber;
Jian Li60312252018-05-10 18:40:32 +090037import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090038import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090039import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090040import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070042import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090043import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070044import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090045import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090046import org.onosproject.openstacknetworking.api.Constants;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090047import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Li60312252018-05-10 18:40:32 +090048import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li581f21a2018-10-12 09:33:56 +090049import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090050import org.onosproject.openstacknetworking.api.InstancePortEvent;
51import org.onosproject.openstacknetworking.api.InstancePortListener;
Jian Li60312252018-05-10 18:40:32 +090052import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090053import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Li809b3ed2018-10-14 20:49:33 +090054import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
55import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090056import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090057import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Li60312252018-05-10 18:40:32 +090058import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
59import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li581f21a2018-10-12 09:33:56 +090060import org.onosproject.openstacknetworking.api.PreCommitPortService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090061import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090062import org.onosproject.openstacknode.api.OpenstackNodeEvent;
63import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090064import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li34220ea2018-11-14 01:30:24 +090065import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090066import org.openstack4j.model.network.NetFloatingIP;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090067import org.openstack4j.model.network.Network;
Jian Li809b3ed2018-10-14 20:49:33 +090068import org.openstack4j.model.network.Port;
Jian Li60312252018-05-10 18:40:32 +090069import org.openstack4j.model.network.Router;
Jian Li60312252018-05-10 18:40:32 +090070import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070071import org.osgi.service.component.annotations.Activate;
72import org.osgi.service.component.annotations.Component;
73import org.osgi.service.component.annotations.Deactivate;
74import org.osgi.service.component.annotations.Modified;
75import org.osgi.service.component.annotations.Reference;
76import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090077import org.slf4j.Logger;
78
79import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090080import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070082import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090083import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090084
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085import static java.util.concurrent.Executors.newSingleThreadExecutor;
86import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090087import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
88import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li60312252018-05-10 18:40:32 +090089import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
90import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090091import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090092import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li581f21a2018-10-12 09:33:56 +090093import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Ray Milkey8e406512018-10-24 15:56:50 -070094import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
95import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
96import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li24ec59f2018-05-23 19:01:25 +090097import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
Jian Li32b03622018-11-06 17:54:24 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
99import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.floatingIpByInstancePort;
Jian Liebde74d2018-11-14 00:18:57 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getExternalIp;
Jian Li24ec59f2018-05-23 19:01:25 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Jian Li32b03622018-11-06 17:54:24 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900109import static org.slf4j.LoggerFactory.getLogger;
110
111/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900113 */
Ray Milkey8e406512018-10-24 15:56:50 -0700114@Component(
115 immediate = true,
116 property = {
117 ARP_MODE + "=" + ARP_MODE_DEFAULT
118 }
119)
Daniel Park81a61a12016-02-26 08:24:44 +0900120public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900121
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700122 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900123
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
125 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900126 private static final String ARP_MODE = "arpMode";
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900129 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700132 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900135 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900138 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parke49eb382017-04-05 16:48:28 +0900141 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900144 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900147 protected ClusterService clusterService;
148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900150 protected LeadershipService leadershipService;
151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900153 protected OpenstackFlowRuleService osFlowRuleService;
154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li1064e4f2018-05-29 16:16:53 +0900156 protected OpenstackNetworkService osNetworkService;
157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900159 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900160
Ray Milkey0b18b722018-10-16 13:19:15 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900162 protected PreCommitPortService preCommitPortService;
163
Ray Milkey8e406512018-10-24 15:56:50 -0700164 /** ARP processing mode, broadcast | proxy (default). **/
165 protected String arpMode = ARP_MODE_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900166
Ray Milkey8e406512018-10-24 15:56:50 -0700167 protected String gatewayMac = GATEWAY_MAC_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900168
169 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900170 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900171 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900172 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900173
174 private ApplicationId appId;
175 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900176
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 private final ExecutorService eventExecutor = newSingleThreadExecutor(
178 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700179
Hyunsun Moon0d457362017-06-27 17:19:41 +0900180 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700181
182 @Activate
183 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900184 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
185 configService.registerProperties(getClass());
186 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900187 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900188 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900189 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900190 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900191 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700192 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
193 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900194 }
195
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700196 @Deactivate
197 protected void deactivate() {
198 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900199 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900200 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900201 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900202 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900203 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900204 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900205 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900206 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700207 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900208 }
209
Jian Li60312252018-05-10 18:40:32 +0900210 @Modified
211 void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900212 log.info("Modified");
213 }
214
Jian Li7f70bb72018-07-06 23:35:30 +0900215 private String getArpMode() {
216 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
217 return getPropertyValue(properties, ARP_MODE);
218 }
219
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700220 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900221 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900222
Jian Li7f70bb72018-07-06 23:35:30 +0900223 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900224 if (log.isTraceEnabled()) {
225 log.trace("ARP request received from {} for {}",
226 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
227 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
228 }
229
230 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900231
232 MacAddress targetMac = null;
233
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900234 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900235 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
236 .findAny().orElse(null);
237
daniel park576969a2018-03-09 07:07:41 +0900238 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900239 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900240 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
241 if (instPort == null) {
242 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
243 return;
244 } else {
245 targetMac = instPort.macAddress();
246 }
247
Jian Li32b03622018-11-06 17:54:24 +0900248 OpenstackNode gw =
249 getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
Daniel Park96f1e032018-08-09 13:30:57 +0900250
251 if (gw == null) {
252 return;
253 }
254
255 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
Jian Li32b03622018-11-06 17:54:24 +0900256 if (!Objects.equals(gw.intgBridge(),
257 context.inPacket().receivedFrom().deviceId())) {
Daniel Park96f1e032018-08-09 13:30:57 +0900258 return;
259 }
daniel parkeeb8e042018-02-21 14:06:58 +0900260 }
261
Daniel Park96f1e032018-08-09 13:30:57 +0900262 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900263 targetMac = Constants.DEFAULT_GATEWAY_MAC;
264 }
265
266 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900267 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
268 return;
269 }
270
daniel parkb5817102018-02-15 00:18:51 +0900271 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
272 targetMac, ethernet);
273
274 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900275 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900276
277 packetService.emit(new DefaultOutboundPacket(
278 context.inPacket().receivedFrom().deviceId(),
279 treatment,
280 ByteBuffer.wrap(ethReply.serialize())));
281
282 context.block();
Jian Li60312252018-05-10 18:40:32 +0900283 }
284
285 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900286 ConnectPoint cp = context.inPacket().receivedFrom();
287 PortNumber receivedPortNum = cp.port();
288 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
289 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
290
291 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
292
daniel parkb5817102018-02-15 00:18:51 +0900293 try {
Jian Li14a79f22018-06-05 03:44:22 +0900294
Jian Li32b03622018-11-06 17:54:24 +0900295 Set<String> extRouterIps = osNetworkService.externalPeerRouters()
296 .stream()
297 .map(r -> r.ipAddress().toString())
298 .collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900299
Jian Lid4066ea2018-06-07 01:44:45 +0900300 // if SPA is NOT contained in existing external router IP set, we ignore it
301 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900302 return;
303 }
304
305 OpenstackNode node = osNodeService.node(cp.deviceId());
306
307 if (node == null) {
308 return;
309 }
310
311 // we only handles the ARP-Reply message received by gateway node
312 if (node.type() != GATEWAY) {
313 return;
314 }
315
316 if (receivedPortNum.equals(node.uplinkPortNum())) {
317 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900318 }
319 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900320 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900321 }
Daniel Park81a61a12016-02-26 08:24:44 +0900322 }
Daniel Park81a61a12016-02-26 08:24:44 +0900323 }
324
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700325 private class InternalPacketProcessor implements PacketProcessor {
326
327 @Override
328 public void process(PacketContext context) {
329 if (context.isHandled()) {
330 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900331 }
332
Jian Li34220ea2018-11-14 01:30:24 +0900333 InboundPacket pkt = context.inPacket();
334 Ethernet ethernet = pkt.parsed();
335 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
336 eventExecutor.execute(() -> {
337
338 if (!isRelevantHelper(context)) {
339 return;
340 }
341
342 processArpPacket(context, ethernet);
343 });
344 }
345 }
346
347 private boolean isRelevantHelper(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900348 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
349 .stream().map(OpenstackNode::intgBridge)
350 .collect(Collectors.toSet());
351
Jian Li34220ea2018-11-14 01:30:24 +0900352 return gateways.contains(context.inPacket().receivedFrom().deviceId());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700353 }
354 }
355
daniel parkeeb8e042018-02-21 14:06:58 +0900356 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900357 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900358 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900359 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 .flatMap(osPort -> osPort.getFixedIps().stream())
361 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900362 }
Jian Li60312252018-05-10 18:40:32 +0900363
Jian Li60312252018-05-10 18:40:32 +0900364 /**
365 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900366 *
367 * @param gateway gateway node
368 * @param install flow rule installation flag
369 */
Jian Li32b03622018-11-06 17:54:24 +0900370 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway,
371 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900372 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900373
374 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
375 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
376 finalGws.addAll(ImmutableSet.copyOf(completedGws));
377
378 if (install) {
379 if (completedGws.contains(gateway)) {
380 if (completedGws.size() > 1) {
381 finalGws.remove(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900382 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900383 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900384 setFloatingIpArpRule(fip, fip.getPortId(),
385 finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900386 finalGws.add(gateway);
387 }
388 });
389 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900390 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900391 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900392 setFloatingIpArpRule(fip, fip.getPortId(),
393 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900394 }
395 });
396 } else {
397 log.warn("Detected node should be included in completed gateway set");
398 }
399 } else {
400 if (!completedGws.contains(gateway)) {
401 finalGws.add(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900402 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900403 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900404 setFloatingIpArpRule(fip, fip.getPortId(),
405 finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900406 }
407 });
408 finalGws.remove(gateway);
409 if (completedGws.size() >= 1) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900410 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900411 if (fip.getPortId() != null) {
Jian Li32b03622018-11-06 17:54:24 +0900412 setFloatingIpArpRule(fip, fip.getPortId(),
413 finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900414 }
415 });
416 }
417 } else {
418 log.warn("Detected node should NOT be included in completed gateway set");
419 }
420 }
421 }
422 }
423
424 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900425 * Installs/uninstalls ARP flow rules to the corresponding gateway by
426 * looking for compute node's device ID.
427 *
428 * @param fip floating IP
429 * @param port instance port
430 * @param gateways a collection of gateways
431 * @param install install flag
432 */
433 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
434 InstancePort port,
435 Set<OpenstackNode> gateways,
436 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900437 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900438
439 OpenstackNode gw = getGwByInstancePort(gateways, port);
440
441 if (gw == null) {
442 return;
443 }
444
445 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
446
447 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
448 }
449 }
450
451 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900452 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900453 * Note that, those rules will be only matched ARP_REQUEST packets,
454 * used for telling gateway node the mapped MAC address of requested IP,
455 * without the helps from controller.
456 *
457 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900458 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900459 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900460 * @param install flow rule installation flag
461 */
Jian Li8f64feb2018-07-24 13:20:16 +0900462 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900463 Set<OpenstackNode> gateways,
464 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900465 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900466
467 if (fip == null) {
468 log.warn("Failed to set ARP broadcast rule for floating IP");
469 return;
470 }
471
Jian Li581f21a2018-10-12 09:33:56 +0900472 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900473 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900474 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900475 return;
476 }
477
Jian Li8f64feb2018-07-24 13:20:16 +0900478 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900479 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900480
Jian Lia171a432018-06-11 11:52:11 +0900481 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900482
483 if (gw == null) {
484 return;
485 }
486
Jian Li581f21a2018-10-12 09:33:56 +0900487 if (install) {
488 preCommitPortService.subscribePreCommit(instPort.portId(),
489 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
490 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
491 } else {
492 preCommitPortService.unsubscribePreCommit(instPort.portId(),
493 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
494 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
495 }
496
Jian Li24ec59f2018-05-23 19:01:25 +0900497 setArpRule(fip, targetMac, gw, install);
498 }
499 }
Jian Li60312252018-05-10 18:40:32 +0900500
Jian Li24ec59f2018-05-23 19:01:25 +0900501 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
502 OpenstackNode gateway, boolean install) {
503 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900504 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900505 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
506 .matchArpOp(ARP.OP_REQUEST)
507 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
508 .build();
Jian Li60312252018-05-10 18:40:32 +0900509
Jian Li24ec59f2018-05-23 19:01:25 +0900510 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
511 .setArpOp(ARP.OP_REPLY)
512 .setArpSha(targetMac)
513 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
514 .setOutput(PortNumber.IN_PORT)
515 .build();
Jian Li60312252018-05-10 18:40:32 +0900516
Jian Li24ec59f2018-05-23 19:01:25 +0900517 osFlowRuleService.setRule(
518 appId,
519 gateway.intgBridge(),
520 selector,
521 treatment,
522 PRIORITY_ARP_GATEWAY_RULE,
523 GW_COMMON_TABLE,
524 install
525 );
526
527 if (install) {
528 log.info("Install ARP Rule for Floating IP {}",
529 fip.getFloatingIpAddress());
530 } else {
531 log.info("Uninstall ARP Rule for Floating IP {}",
532 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900533 }
534 }
535
Jian Li809b3ed2018-10-14 20:49:33 +0900536 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900537 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li34220ea2018-11-14 01:30:24 +0900538 IpAddress externalIp = getExternalIp(router, osNetworkService);
539
540 if (externalIp == null) {
541 log.debug("External IP is not found");
542 return;
543 }
544
545 setFakeGatewayArpRuleByExternalIp(externalIp, install);
Jian Li809b3ed2018-10-14 20:49:33 +0900546 }
547 }
Daniel Park96f1e032018-08-09 13:30:57 +0900548
Jian Liebde74d2018-11-14 00:18:57 +0900549 private void setFakeGatewayArpRuleByExternalIp(IpAddress ipAddress, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900550
Jian Liebde74d2018-11-14 00:18:57 +0900551 TrafficSelector selector = DefaultTrafficSelector.builder()
552 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
553 .matchArpOp(ARP.OP_REQUEST)
554 .matchArpTpa(ipAddress.getIp4Address())
555 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900556
Jian Liebde74d2018-11-14 00:18:57 +0900557 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
558 .setArpOp(ARP.OP_REPLY)
559 .setArpSha(MacAddress.valueOf(gatewayMac))
560 .setArpSpa(ipAddress.getIp4Address())
561 .setOutput(PortNumber.IN_PORT)
562 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900563
Jian Liebde74d2018-11-14 00:18:57 +0900564 osNodeService.completeNodes(GATEWAY).forEach(n ->
565 osFlowRuleService.setRule(
566 appId,
567 n.intgBridge(),
568 selector,
569 treatment,
570 PRIORITY_ARP_GATEWAY_RULE,
571 GW_COMMON_TABLE,
572 install
573 )
574 );
575
576 if (install) {
577 log.info("Install ARP Rule for Gateway Snat {}", ipAddress);
578 } else {
579 log.info("Uninstall ARP Rule for Gateway Snat {}", ipAddress);
580 }
Jian Li809b3ed2018-10-14 20:49:33 +0900581 }
582
583 /**
584 * An internal network event listener, intended to uninstall ARP rules for
585 * routing the packets destined to external gateway.
586 */
587 private class InternalNetworkEventListener implements OpenstackNetworkListener {
588
589 @Override
590 public boolean isRelevant(OpenstackNetworkEvent event) {
591 Port osPort = event.port();
592 if (osPort == null || osPort.getFixedIps() == null) {
593 return false;
594 }
595
Jian Li34220ea2018-11-14 01:30:24 +0900596 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
597 ARP_BROADCAST_MODE.equals(getArpMode());
598 }
599
600 private boolean isRelevantHelper() {
601 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li809b3ed2018-10-14 20:49:33 +0900602 }
603
604 @Override
605 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900606 IpAddress ipAddress = externalIp(event.port());
Jian Li809b3ed2018-10-14 20:49:33 +0900607 switch (event.type()) {
608 case OPENSTACK_PORT_CREATED:
609 case OPENSTACK_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +0900610 eventExecutor.execute(() -> {
611
612 if (!isRelevantHelper() || ipAddress == null) {
613 return;
614 }
615
616 setFakeGatewayArpRuleByExternalIp(ipAddress, true);
617 });
Jian Li809b3ed2018-10-14 20:49:33 +0900618 break;
619 case OPENSTACK_PORT_REMOVED:
Jian Li34220ea2018-11-14 01:30:24 +0900620 eventExecutor.execute(() -> {
621
622 if (!isRelevantHelper() || ipAddress == null) {
623 return;
624 }
625
626 setFakeGatewayArpRuleByExternalIp(ipAddress, false);
627 });
Jian Li809b3ed2018-10-14 20:49:33 +0900628 break;
629 default:
630 // do nothing
631 break;
632 }
Daniel Park96f1e032018-08-09 13:30:57 +0900633 }
Jian Li34220ea2018-11-14 01:30:24 +0900634
635 private IpAddress externalIp(Port port) {
636 IP ip = port.getFixedIps().stream().findAny().orElse(null);
637
638 if (ip != null && ip.getIpAddress() != null) {
639 return IpAddress.valueOf(ip.getIpAddress());
640 }
641
642 return null;
643 }
Daniel Park96f1e032018-08-09 13:30:57 +0900644 }
645
Jian Li60312252018-05-10 18:40:32 +0900646 /**
647 * An internal router event listener, intended to install/uninstall
648 * ARP rules for forwarding packets created from floating IPs.
649 */
650 private class InternalRouterEventListener implements OpenstackRouterListener {
651
Jian Li34220ea2018-11-14 01:30:24 +0900652 private boolean isRelevantHelper() {
653 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900654 }
655
656 @Override
657 public void event(OpenstackRouterEvent event) {
Jian Li1064e4f2018-05-29 16:16:53 +0900658
659 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
660
Jian Li60312252018-05-10 18:40:32 +0900661 switch (event.type()) {
662 case OPENSTACK_ROUTER_CREATED:
Jian Liebde74d2018-11-14 00:18:57 +0900663 // add a router with external gateway
664 case OPENSTACK_ROUTER_GATEWAY_ADDED:
665 // add a gateway manually after adding a router
Jian Li34220ea2018-11-14 01:30:24 +0900666 eventExecutor.execute(() -> {
667
668 if (!isRelevantHelper()) {
669 return;
670 }
671
672 // add a router with external gateway
673 setFakeGatewayArpRuleByRouter(event.subject(), true);
674 });
Jian Li60312252018-05-10 18:40:32 +0900675 break;
676 case OPENSTACK_ROUTER_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900677 // remove a router with external gateway
Jian Li60312252018-05-10 18:40:32 +0900678 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900679 // remove a gateway from an existing router
Jian Li32b03622018-11-06 17:54:24 +0900680 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900681
682 if (!isRelevantHelper()) {
Jian Li32b03622018-11-06 17:54:24 +0900683 return;
684 }
Jian Li34220ea2018-11-14 01:30:24 +0900685
686 setFakeGatewayArpRuleByRouter(event.subject(), false);
Jian Li32b03622018-11-06 17:54:24 +0900687 });
Jian Li60312252018-05-10 18:40:32 +0900688 break;
689 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900690 // during floating IP creation, if the floating IP is
691 // associated with any port of VM, then we will set
692 // floating IP related ARP rules to gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900693 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Li32b03622018-11-06 17:54:24 +0900694 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900695
696 if (!isRelevantHelper()) {
697 return;
698 }
699
Jian Li32b03622018-11-06 17:54:24 +0900700 if (getValidPortId(event) == null) {
701 return;
702 }
703 // associate a floating IP with an existing VM
704 setFloatingIpArpRule(event.floatingIp(),
705 getValidPortId(event), completedGws, true);
706 });
Jian Li60312252018-05-10 18:40:32 +0900707 break;
708 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900709 // during floating IP deletion, if the floating IP is
710 // still associated with any port of VM, then we will
711 // remove floating IP related ARP rules from gateway node
Jian Li34220ea2018-11-14 01:30:24 +0900712 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Li32b03622018-11-06 17:54:24 +0900713 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900714
715 if (!isRelevantHelper()) {
716 return;
717 }
718
Jian Li32b03622018-11-06 17:54:24 +0900719 if (getValidPortId(event) == null) {
720 return;
721 }
Jian Li34220ea2018-11-14 01:30:24 +0900722 // disassociate a floating IP with an existing VM
Jian Li32b03622018-11-06 17:54:24 +0900723 setFloatingIpArpRule(event.floatingIp(),
724 getValidPortId(event), completedGws, false);
725 });
Jian Li60312252018-05-10 18:40:32 +0900726 break;
727 default:
728 // do nothing for the other events
729 break;
730 }
731 }
732
Jian Lida03ce92018-07-24 21:41:53 +0900733 private String getValidPortId(OpenstackRouterEvent event) {
734 NetFloatingIP osFip = event.floatingIp();
735 String portId = osFip.getPortId();
736
737 if (Strings.isNullOrEmpty(portId)) {
738 portId = event.portId();
739 }
740
741 if (portId != null && instancePortService.instancePort(portId) != null) {
742 return portId;
743 }
744
745 return null;
746 }
Jian Li60312252018-05-10 18:40:32 +0900747 }
748
Jian Lie1a39032018-06-19 21:49:36 +0900749 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900750
Jian Li34220ea2018-11-14 01:30:24 +0900751 private boolean isRelevantHelper() {
752 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900753 }
754
755 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900756 public void event(InstancePortEvent event) {
757 InstancePort instPort = event.subject();
758
Jian Li60312252018-05-10 18:40:32 +0900759 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900760 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Li34220ea2018-11-14 01:30:24 +0900761 eventExecutor.execute(() -> {
762
763 if (!isRelevantHelper()) {
764 return;
765 }
766
767 osRouterAdminService.floatingIps().stream()
Jian Li32b03622018-11-06 17:54:24 +0900768 .filter(f -> f.getPortId() != null)
769 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li34220ea2018-11-14 01:30:24 +0900770 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(),
771 osNodeService.completeNodes(GATEWAY), true));
772 });
773
Jian Li60312252018-05-10 18:40:32 +0900774 break;
Jian Lie1a39032018-06-19 21:49:36 +0900775 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li32b03622018-11-06 17:54:24 +0900776 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900777
778 if (!isRelevantHelper()) {
779 return;
780 }
781
782 NetFloatingIP fip = associatedFloatingIp(instPort,
783 osRouterAdminService.floatingIps());
784
785 if (osNodeService.completeNodes(GATEWAY).size() == 1) {
Jian Lie1a39032018-06-19 21:49:36 +0900786 return;
787 }
788
Jian Li32b03622018-11-06 17:54:24 +0900789 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Li34220ea2018-11-14 01:30:24 +0900790 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
791 osNodeService.completeNodes(GATEWAY), true);
Jian Li32b03622018-11-06 17:54:24 +0900792 }
793 });
794
795 break;
796 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
797 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900798
799 if (!isRelevantHelper()) {
800 return;
801 }
802
803 NetFloatingIP fip = associatedFloatingIp(instPort,
804 osRouterAdminService.floatingIps());
805 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
806
Jian Li32b03622018-11-06 17:54:24 +0900807 InstancePort revisedInstPort = swapStaleLocation(event.subject());
808
809 if (gateways.size() == 1) {
810 return;
811 }
812
813 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
814 DeviceId newDeviceId = event.subject().deviceId();
815 DeviceId oldDeviceId = revisedInstPort.deviceId();
816
817 OpenstackNode oldGw =
818 getGwByComputeDevId(gateways, oldDeviceId);
819 OpenstackNode newGw =
820 getGwByComputeDevId(gateways, newDeviceId);
821
822 if (oldGw != null && oldGw.equals(newGw)) {
823 return;
824 }
825
826 setFloatingIpArpRuleWithPortEvent(fip,
827 revisedInstPort, gateways, false);
828 }
829 });
Jian Lie1a39032018-06-19 21:49:36 +0900830 break;
831 default:
832 break;
833 }
Jian Li60312252018-05-10 18:40:32 +0900834 }
835 }
Jian Lif96685c2018-05-21 14:14:16 +0900836
837 private class InternalNodeEventListener implements OpenstackNodeListener {
838
839 @Override
840 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900841 return event.subject().type() == GATEWAY;
842 }
843
844 private boolean isRelevantHelper() {
845 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lif96685c2018-05-21 14:14:16 +0900846 }
847
848 @Override
849 public void event(OpenstackNodeEvent event) {
850 OpenstackNode osNode = event.subject();
851 switch (event.type()) {
852 case OPENSTACK_NODE_COMPLETE:
Jian Li32b03622018-11-06 17:54:24 +0900853 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900854 if (!isRelevantHelper()) {
855 return;
856 }
Jian Li32b03622018-11-06 17:54:24 +0900857 setDefaultArpRule(osNode, true);
858 setFloatingIpArpRuleForGateway(osNode, true);
859 sendGratuitousArpToSwitch(event.subject(), true);
860 });
Jian Lif96685c2018-05-21 14:14:16 +0900861 break;
862 case OPENSTACK_NODE_INCOMPLETE:
Jian Li32b03622018-11-06 17:54:24 +0900863 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900864 if (!isRelevantHelper()) {
865 return;
866 }
Jian Li32b03622018-11-06 17:54:24 +0900867 setDefaultArpRule(osNode, false);
868 setFloatingIpArpRuleForGateway(osNode, false);
869 sendGratuitousArpToSwitch(event.subject(), false);
870 });
Jian Lif96685c2018-05-21 14:14:16 +0900871 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900872 case OPENSTACK_NODE_REMOVED:
Jian Li32b03622018-11-06 17:54:24 +0900873 eventExecutor.execute(() -> {
Jian Li34220ea2018-11-14 01:30:24 +0900874 if (!isRelevantHelper()) {
875 return;
876 }
Jian Li32b03622018-11-06 17:54:24 +0900877 sendGratuitousArpToSwitch(event.subject(), false);
878 });
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900879 break;
Jian Lif96685c2018-05-21 14:14:16 +0900880 default:
881 break;
882 }
883 }
884
Jian Li32b03622018-11-06 17:54:24 +0900885 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
886 boolean isCompleteCase) {
887 Set<OpenstackNode> completeGws =
888 ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900889
890 if (isCompleteCase) {
Jian Li32b03622018-11-06 17:54:24 +0900891 osNodeService.completeNodes(COMPUTE).stream()
892 .filter(node -> isGwSelectedByComputeNode(completeGws,
893 node, gatewayNode))
894 .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900895
896 } else {
897 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
898 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
899 oldCompleteGws.add(gatewayNode);
900
Jian Li32b03622018-11-06 17:54:24 +0900901 osNodeService.completeNodes(COMPUTE).stream()
902 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
903 node, gatewayNode))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900904 .forEach(node -> {
Jian Li32b03622018-11-06 17:54:24 +0900905 OpenstackNode newSelectedGatewayNode =
906 getGwByComputeDevId(completeGws, node.intgBridge());
907 processGarpPacketForComputeNode(node, newSelectedGatewayNode);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900908 });
909 }
910 }
911
912 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
913 OpenstackNode computeNode,
914 OpenstackNode gwNode) {
Jian Liebde74d2018-11-14 00:18:57 +0900915 return getGwByComputeDevId(gws, computeNode.intgBridge())
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900916 .intgBridge().equals(gwNode.intgBridge());
917 }
918
Jian Li32b03622018-11-06 17:54:24 +0900919 private void processGarpPacketForComputeNode(OpenstackNode computeNode,
920 OpenstackNode gatewayNode) {
921 instancePortService.instancePort(computeNode.intgBridge())
922 .forEach(instancePort -> {
923 NetFloatingIP floatingIP =
924 floatingIpByInstancePort(instancePort, osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900925 Network network = osNetworkService.network(instancePort.networkId());
Jian Li32b03622018-11-06 17:54:24 +0900926 ExternalPeerRouter externalPeerRouter =
927 externalPeerRouterForNetwork(network, osNetworkService,
928 osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900929 if (floatingIP != null && externalPeerRouter != null) {
Jian Li32b03622018-11-06 17:54:24 +0900930 processGarpPacketForFloatingIp(
931 floatingIP, instancePort, externalPeerRouter.vlanId(),
932 gatewayNode, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900933 }
934 });
935 }
936
Jian Lif96685c2018-05-21 14:14:16 +0900937 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900938
939 if (getArpMode() == null) {
940 return;
941 }
Jian Liebde74d2018-11-14 00:18:57 +0900942 log.info("ARP mode is {}", getArpMode());
Jian Lib6969502018-10-30 20:38:07 +0900943
Jian Li7f70bb72018-07-06 23:35:30 +0900944 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900945 case ARP_PROXY_MODE:
946 setDefaultArpRuleForProxyMode(osNode, install);
947 break;
948 case ARP_BROADCAST_MODE:
949 setDefaultArpRuleForBroadcastMode(osNode, install);
950 break;
951 default:
952 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900953 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900954 break;
955 }
956 }
957
Jian Li32b03622018-11-06 17:54:24 +0900958 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
959 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900960 TrafficSelector selector = DefaultTrafficSelector.builder()
961 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
962 .build();
963
964 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
965 .punt()
966 .build();
967
968 osFlowRuleService.setRule(
969 appId,
970 osNode.intgBridge(),
971 selector,
972 treatment,
973 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900974 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900975 install
976 );
977 }
978
Jian Li32b03622018-11-06 17:54:24 +0900979 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
980 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900981 // we only match ARP_REPLY in gateway node, because controller
982 // somehow need to process ARP_REPLY which is issued from
983 // external router...
984 TrafficSelector selector = DefaultTrafficSelector.builder()
985 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
986 .matchArpOp(ARP.OP_REPLY)
987 .build();
988
989 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
990 .punt()
991 .build();
992
993 osFlowRuleService.setRule(
994 appId,
995 osNode.intgBridge(),
996 selector,
997 treatment,
998 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900999 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001000 install
1001 );
Daniel Park96f1e032018-08-09 13:30:57 +09001002
Jian Liebde74d2018-11-14 00:18:57 +09001003 log.info("calling setFakeGatewayArpRuleByRouter.. ");
Daniel Park4fa1f5e2018-10-17 12:41:52 +09001004 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +09001005 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +09001006 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +09001007 }
1008 }
Daniel Park81a61a12016-02-26 08:24:44 +09001009}