blob: 304258fa372f5132041910d08e088a2b53010bea [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;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
Jian Li60312252018-05-10 18:40:32 +090024import org.apache.felix.scr.annotations.Modified;
25import org.apache.felix.scr.annotations.Property;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090028import org.onlab.packet.ARP;
Jian Li60312252018-05-10 18:40:32 +090029import org.onlab.packet.EthType;
Daniel Park81a61a12016-02-26 08:24:44 +090030import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090031import org.onlab.packet.Ip4Address;
32import org.onlab.packet.IpAddress;
33import org.onlab.packet.MacAddress;
Jian Li60312252018-05-10 18:40:32 +090034import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090035import org.onosproject.cfg.ConfigProperty;
Jian Li60312252018-05-10 18:40:32 +090036import org.onosproject.cluster.ClusterService;
37import org.onosproject.cluster.LeadershipService;
38import org.onosproject.cluster.NodeId;
39import org.onosproject.core.ApplicationId;
40import org.onosproject.core.CoreService;
Jian Li14a79f22018-06-05 03:44:22 +090041import org.onosproject.net.ConnectPoint;
Hyunsun Moon0d457362017-06-27 17:19:41 +090042import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090043import org.onosproject.net.PortNumber;
Jian Li60312252018-05-10 18:40:32 +090044import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090045import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090046import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090047import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070049import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090050import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070051import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090052import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090053import org.onosproject.openstacknetworking.api.Constants;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090054import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Li60312252018-05-10 18:40:32 +090055import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li581f21a2018-10-12 09:33:56 +090056import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li24ec59f2018-05-23 19:01:25 +090057import org.onosproject.openstacknetworking.api.InstancePortEvent;
58import org.onosproject.openstacknetworking.api.InstancePortListener;
Jian Li60312252018-05-10 18:40:32 +090059import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090060import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Li809b3ed2018-10-14 20:49:33 +090061import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
62import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090063import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090064import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Li60312252018-05-10 18:40:32 +090065import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
66import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Jian Li581f21a2018-10-12 09:33:56 +090067import org.onosproject.openstacknetworking.api.PreCommitPortService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090068import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
Hyunsun Moon0d457362017-06-27 17:19:41 +090069import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090070import org.onosproject.openstacknode.api.OpenstackNodeEvent;
71import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090072import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li60312252018-05-10 18:40:32 +090073import org.openstack4j.model.network.ExternalGateway;
Jian Li4df657b2018-05-29 16:39:00 +090074import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090075import org.openstack4j.model.network.NetFloatingIP;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090076import org.openstack4j.model.network.Network;
Jian Li809b3ed2018-10-14 20:49:33 +090077import org.openstack4j.model.network.Port;
Jian Li60312252018-05-10 18:40:32 +090078import org.openstack4j.model.network.Router;
Jian Li60312252018-05-10 18:40:32 +090079import org.osgi.service.component.ComponentContext;
Daniel Park81a61a12016-02-26 08:24:44 +090080import org.slf4j.Logger;
81
82import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090083import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090084import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070085import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090086import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090087
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070088import static java.util.concurrent.Executors.newSingleThreadExecutor;
89import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090090import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
91import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
92import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_ARP_MODE_STR;
93import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
94import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
95import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090096import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090097import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li581f21a2018-10-12 09:33:56 +090098import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900106import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900108import static org.slf4j.LoggerFactory.getLogger;
109
110/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900111 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900112 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700113@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +0900114public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700116 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900117
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
119 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900120 private static final String ARP_MODE = "arpMode";
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900124
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900127
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900129 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700130
Hyunsun Moon44aac662017-02-18 02:07:01 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900132 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900133
daniel parkeeb8e042018-02-21 14:06:58 +0900134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +0900135 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900136
Jian Li60312252018-05-10 18:40:32 +0900137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li581f21a2018-10-12 09:33:56 +0900138 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li60312252018-05-10 18:40:32 +0900141 protected ClusterService clusterService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
144 protected LeadershipService leadershipService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
147 protected OpenstackFlowRuleService osFlowRuleService;
148
149 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li1064e4f2018-05-29 16:16:53 +0900150 protected OpenstackNetworkService osNetworkService;
151
152 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900153 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900154
Jian Li581f21a2018-10-12 09:33:56 +0900155 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
156 protected PreCommitPortService preCommitPortService;
157
Jian Li60312252018-05-10 18:40:32 +0900158 @Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
Daniel Park6041f102018-07-06 18:49:45 +0900159 label = "ARP processing mode, broadcast | proxy (default)")
Jian Li60312252018-05-10 18:40:32 +0900160 protected String arpMode = DEFAULT_ARP_MODE_STR;
161
162 protected String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
163
164 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900165 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900166 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900167 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900168
169 private ApplicationId appId;
170 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900171
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172 private final ExecutorService eventExecutor = newSingleThreadExecutor(
173 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700174
Hyunsun Moon0d457362017-06-27 17:19:41 +0900175 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700176
177 @Activate
178 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900179 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
180 configService.registerProperties(getClass());
181 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900182 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900183 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900184 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900185 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900186 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700187 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
188 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900189 }
190
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700191 @Deactivate
192 protected void deactivate() {
193 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900194 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900195 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900196 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900197 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900198 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900199 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900200 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900201 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700202 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900203 }
204
Jian Li60312252018-05-10 18:40:32 +0900205 @Modified
206 void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900207 log.info("Modified");
208 }
209
Jian Li7f70bb72018-07-06 23:35:30 +0900210 private String getArpMode() {
211 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
212 return getPropertyValue(properties, ARP_MODE);
213 }
214
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700215 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900216 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900217
Jian Li7f70bb72018-07-06 23:35:30 +0900218 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900219 if (log.isTraceEnabled()) {
220 log.trace("ARP request received from {} for {}",
221 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
222 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
223 }
224
225 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900226
227 MacAddress targetMac = null;
228
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900229 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900230 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
231 .findAny().orElse(null);
232
daniel park576969a2018-03-09 07:07:41 +0900233 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900234 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900235 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
236 if (instPort == null) {
237 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
238 return;
239 } else {
240 targetMac = instPort.macAddress();
241 }
242
243 OpenstackNode gw = getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
244
245 if (gw == null) {
246 return;
247 }
248
249 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
250 if (!Objects.equals(gw.intgBridge(), context.inPacket().receivedFrom().deviceId())) {
251 return;
252 }
daniel parkeeb8e042018-02-21 14:06:58 +0900253 }
254
Daniel Park96f1e032018-08-09 13:30:57 +0900255 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900256 targetMac = Constants.DEFAULT_GATEWAY_MAC;
257 }
258
259 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900260 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
261 return;
262 }
263
daniel parkb5817102018-02-15 00:18:51 +0900264 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
265 targetMac, ethernet);
266
267 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900268 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900269
270 packetService.emit(new DefaultOutboundPacket(
271 context.inPacket().receivedFrom().deviceId(),
272 treatment,
273 ByteBuffer.wrap(ethReply.serialize())));
274
275 context.block();
Jian Li60312252018-05-10 18:40:32 +0900276 }
277
278 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900279 ConnectPoint cp = context.inPacket().receivedFrom();
280 PortNumber receivedPortNum = cp.port();
281 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
282 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
283
284 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
285
daniel parkb5817102018-02-15 00:18:51 +0900286 try {
Jian Li14a79f22018-06-05 03:44:22 +0900287
Jian Lid4066ea2018-06-07 01:44:45 +0900288 Set<String> extRouterIps = osNetworkService.externalPeerRouters().
Jian Li5e2ad4a2018-07-16 13:40:53 +0900289 stream().map(r -> r.ipAddress().toString()).collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900290
Jian Lid4066ea2018-06-07 01:44:45 +0900291 // if SPA is NOT contained in existing external router IP set, we ignore it
292 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900293 return;
294 }
295
296 OpenstackNode node = osNodeService.node(cp.deviceId());
297
298 if (node == null) {
299 return;
300 }
301
302 // we only handles the ARP-Reply message received by gateway node
303 if (node.type() != GATEWAY) {
304 return;
305 }
306
307 if (receivedPortNum.equals(node.uplinkPortNum())) {
308 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900309 }
310 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900311 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900312 }
Daniel Park81a61a12016-02-26 08:24:44 +0900313 }
Daniel Park81a61a12016-02-26 08:24:44 +0900314 }
315
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700316 private class InternalPacketProcessor implements PacketProcessor {
317
318 @Override
319 public void process(PacketContext context) {
320 if (context.isHandled()) {
321 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900322 }
323
324 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
325 .stream().map(OpenstackNode::intgBridge)
326 .collect(Collectors.toSet());
327
328 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700329 // return if the packet is not from gateway nodes
330 return;
331 }
332
333 InboundPacket pkt = context.inPacket();
334 Ethernet ethernet = pkt.parsed();
335 if (ethernet != null &&
336 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700338 }
339 }
340 }
341
daniel parkeeb8e042018-02-21 14:06:58 +0900342 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900343 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900344 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900345 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 .flatMap(osPort -> osPort.getFixedIps().stream())
347 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900348 }
Jian Li60312252018-05-10 18:40:32 +0900349
Jian Li60312252018-05-10 18:40:32 +0900350 /**
351 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900352 *
353 * @param gateway gateway node
354 * @param install flow rule installation flag
355 */
356 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900357 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900358
359 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
360 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
361 finalGws.addAll(ImmutableSet.copyOf(completedGws));
362
363 if (install) {
364 if (completedGws.contains(gateway)) {
365 if (completedGws.size() > 1) {
366 finalGws.remove(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900367 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900368 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900369 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900370 finalGws.add(gateway);
371 }
372 });
373 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900374 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900375 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900376 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900377 }
378 });
379 } else {
380 log.warn("Detected node should be included in completed gateway set");
381 }
382 } else {
383 if (!completedGws.contains(gateway)) {
384 finalGws.add(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900385 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900386 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900387 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900388 }
389 });
390 finalGws.remove(gateway);
391 if (completedGws.size() >= 1) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900392 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900393 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900394 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900395 }
396 });
397 }
398 } else {
399 log.warn("Detected node should NOT be included in completed gateway set");
400 }
401 }
402 }
403 }
404
405 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900406 * Installs/uninstalls ARP flow rules to the corresponding gateway by
407 * looking for compute node's device ID.
408 *
409 * @param fip floating IP
410 * @param port instance port
411 * @param gateways a collection of gateways
412 * @param install install flag
413 */
414 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
415 InstancePort port,
416 Set<OpenstackNode> gateways,
417 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900418 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900419
420 OpenstackNode gw = getGwByInstancePort(gateways, port);
421
422 if (gw == null) {
423 return;
424 }
425
426 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
427
428 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
429 }
430 }
431
432 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900433 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900434 * Note that, those rules will be only matched ARP_REQUEST packets,
435 * used for telling gateway node the mapped MAC address of requested IP,
436 * without the helps from controller.
437 *
438 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900439 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900440 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900441 * @param install flow rule installation flag
442 */
Jian Li8f64feb2018-07-24 13:20:16 +0900443 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900444 Set<OpenstackNode> gateways,
445 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900446 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900447
448 if (fip == null) {
449 log.warn("Failed to set ARP broadcast rule for floating IP");
450 return;
451 }
452
Jian Li581f21a2018-10-12 09:33:56 +0900453 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900454 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900455 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900456 return;
457 }
458
Jian Li8f64feb2018-07-24 13:20:16 +0900459 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900460 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900461
Jian Lia171a432018-06-11 11:52:11 +0900462 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900463
464 if (gw == null) {
465 return;
466 }
467
Jian Li581f21a2018-10-12 09:33:56 +0900468 if (install) {
469 preCommitPortService.subscribePreCommit(instPort.portId(),
470 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
471 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
472 } else {
473 preCommitPortService.unsubscribePreCommit(instPort.portId(),
474 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
475 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
476 }
477
Jian Li24ec59f2018-05-23 19:01:25 +0900478 setArpRule(fip, targetMac, gw, install);
479 }
480 }
Jian Li60312252018-05-10 18:40:32 +0900481
Jian Li24ec59f2018-05-23 19:01:25 +0900482 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
483 OpenstackNode gateway, boolean install) {
484 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900485 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900486 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
487 .matchArpOp(ARP.OP_REQUEST)
488 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
489 .build();
Jian Li60312252018-05-10 18:40:32 +0900490
Jian Li24ec59f2018-05-23 19:01:25 +0900491 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
492 .setArpOp(ARP.OP_REPLY)
493 .setArpSha(targetMac)
494 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
495 .setOutput(PortNumber.IN_PORT)
496 .build();
Jian Li60312252018-05-10 18:40:32 +0900497
Jian Li24ec59f2018-05-23 19:01:25 +0900498 osFlowRuleService.setRule(
499 appId,
500 gateway.intgBridge(),
501 selector,
502 treatment,
503 PRIORITY_ARP_GATEWAY_RULE,
504 GW_COMMON_TABLE,
505 install
506 );
507
508 if (install) {
509 log.info("Install ARP Rule for Floating IP {}",
510 fip.getFloatingIpAddress());
511 } else {
512 log.info("Uninstall ARP Rule for Floating IP {}",
513 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900514 }
515 }
516
Jian Li809b3ed2018-10-14 20:49:33 +0900517 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
518 setFakeGatewayArpRuleByGateway(router.getExternalGatewayInfo(), install);
Daniel Park96f1e032018-08-09 13:30:57 +0900519 }
520
521 private Set<IP> getExternalGatewaySnatIps(ExternalGateway extGw) {
522 return osNetworkAdminService.ports().stream()
523 .filter(port ->
524 Objects.equals(port.getNetworkId(), extGw.getNetworkId()))
525 .filter(port ->
526 Objects.equals(port.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
527 .flatMap(port -> port.getFixedIps().stream())
528 .collect(Collectors.toSet());
529 }
530
Jian Li809b3ed2018-10-14 20:49:33 +0900531 private void setFakeGatewayArpRuleByGateway(ExternalGateway extGw, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900532 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
533
534 if (extGw == null) {
535 return;
536 }
537
Jian Li809b3ed2018-10-14 20:49:33 +0900538 setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(extGw), install);
539 }
540 }
Daniel Park96f1e032018-08-09 13:30:57 +0900541
Jian Li809b3ed2018-10-14 20:49:33 +0900542 private void setFakeGatewayArpRuleByIps(Set<IP> ips, boolean install) {
543 ips.forEach(ip -> {
544 TrafficSelector selector = DefaultTrafficSelector.builder()
545 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
546 .matchArpOp(ARP.OP_REQUEST)
547 .matchArpTpa(Ip4Address.valueOf(ip.getIpAddress()))
548 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900549
Jian Li809b3ed2018-10-14 20:49:33 +0900550 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
551 .setArpOp(ARP.OP_REPLY)
552 .setArpSha(MacAddress.valueOf(gatewayMac))
553 .setArpSpa(Ip4Address.valueOf(ip.getIpAddress()))
554 .setOutput(PortNumber.IN_PORT)
555 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900556
Jian Li809b3ed2018-10-14 20:49:33 +0900557 osNodeService.completeNodes(GATEWAY).forEach(n ->
558 osFlowRuleService.setRule(
559 appId,
560 n.intgBridge(),
561 selector,
562 treatment,
563 PRIORITY_ARP_GATEWAY_RULE,
564 GW_COMMON_TABLE,
565 install
566 )
567 );
Daniel Park96f1e032018-08-09 13:30:57 +0900568
Jian Li809b3ed2018-10-14 20:49:33 +0900569 if (install) {
570 log.info("Install ARP Rule for Gateway Snat {}", ip.getIpAddress());
571 } else {
572 log.info("Uninstall ARP Rule for Gateway Snat {}", ip.getIpAddress());
573 }
574 });
575 }
576
577 /**
578 * An internal network event listener, intended to uninstall ARP rules for
579 * routing the packets destined to external gateway.
580 */
581 private class InternalNetworkEventListener implements OpenstackNetworkListener {
582
583 @Override
584 public boolean isRelevant(OpenstackNetworkEvent event) {
585 Port osPort = event.port();
586 if (osPort == null || osPort.getFixedIps() == null) {
587 return false;
588 }
589
590 // do not allow to proceed without leadership
591 NodeId leader = leadershipService.getLeader(appId.name());
592 return Objects.equals(localNodeId, leader) &&
Jian Li2360acb2018-10-17 00:46:31 +0900593 DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
594 ARP_BROADCAST_MODE.equals(getArpMode());
Jian Li809b3ed2018-10-14 20:49:33 +0900595 }
596
597 @Override
598 public void event(OpenstackNetworkEvent event) {
599 switch (event.type()) {
600 case OPENSTACK_PORT_CREATED:
601 case OPENSTACK_PORT_UPDATED:
602 eventExecutor.execute(() ->
603 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), true)
604 );
605 break;
606 case OPENSTACK_PORT_REMOVED:
607 eventExecutor.execute(() ->
608 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), false)
609 );
610 break;
611 default:
612 // do nothing
613 break;
614 }
Daniel Park96f1e032018-08-09 13:30:57 +0900615 }
616 }
617
Jian Li60312252018-05-10 18:40:32 +0900618 /**
619 * An internal router event listener, intended to install/uninstall
620 * ARP rules for forwarding packets created from floating IPs.
621 */
622 private class InternalRouterEventListener implements OpenstackRouterListener {
623
624 @Override
625 public boolean isRelevant(OpenstackRouterEvent event) {
626 // do not allow to proceed without leadership
627 NodeId leader = leadershipService.getLeader(appId.name());
628 return Objects.equals(localNodeId, leader);
629 }
630
631 @Override
632 public void event(OpenstackRouterEvent event) {
Jian Li1064e4f2018-05-29 16:16:53 +0900633
634 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
635
Jian Li60312252018-05-10 18:40:32 +0900636 switch (event.type()) {
637 case OPENSTACK_ROUTER_CREATED:
638 eventExecutor.execute(() ->
639 // add a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900640 setFakeGatewayArpRuleByRouter(event.subject(), true)
Jian Li60312252018-05-10 18:40:32 +0900641 );
642 break;
643 case OPENSTACK_ROUTER_REMOVED:
644 eventExecutor.execute(() ->
645 // remove a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900646 setFakeGatewayArpRuleByRouter(event.subject(), false)
Jian Li60312252018-05-10 18:40:32 +0900647 );
648 break;
649 case OPENSTACK_ROUTER_GATEWAY_ADDED:
650 eventExecutor.execute(() ->
651 // add a gateway manually after adding a router
Jian Li809b3ed2018-10-14 20:49:33 +0900652 setFakeGatewayArpRuleByGateway(event.externalGateway(), true)
Jian Li60312252018-05-10 18:40:32 +0900653 );
654 break;
655 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
656 eventExecutor.execute(() ->
657 // remove a gateway from an existing router
Jian Li809b3ed2018-10-14 20:49:33 +0900658 setFakeGatewayArpRuleByGateway(event.externalGateway(), false)
Jian Li60312252018-05-10 18:40:32 +0900659 );
660 break;
661 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900662 if (getValidPortId(event) != null) {
663 eventExecutor.execute(() -> {
664 // associate a floating IP with an existing VM
665 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
666 completedGws, true);
667 });
668 }
Jian Li60312252018-05-10 18:40:32 +0900669 break;
670 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900671 if (getValidPortId(event) != null) {
672 eventExecutor.execute(() -> {
673 // disassociate a floating IP with an existing VM
674 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
675 completedGws, false);
676 });
677 }
Jian Li60312252018-05-10 18:40:32 +0900678 break;
679 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900680 // during floating IP creation, if the floating IP is
681 // associated with any port of VM, then we will set
682 // floating IP related ARP rules to gateway node
683 if (getValidPortId(event) != null) {
684 eventExecutor.execute(() -> {
685 // associate a floating IP with an existing VM
686 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
687 completedGws, true);
688 });
689 }
Jian Li60312252018-05-10 18:40:32 +0900690 break;
691 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900692 // during floating IP deletion, if the floating IP is
693 // still associated with any port of VM, then we will
694 // remove floating IP related ARP rules from gateway node
695 if (getValidPortId(event) != null) {
696 eventExecutor.execute(() -> {
697 // associate a floating IP with an existing VM
698 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
699 completedGws, false);
700 });
701 }
Jian Li60312252018-05-10 18:40:32 +0900702 break;
703 default:
704 // do nothing for the other events
705 break;
706 }
707 }
708
Jian Lida03ce92018-07-24 21:41:53 +0900709 private String getValidPortId(OpenstackRouterEvent event) {
710 NetFloatingIP osFip = event.floatingIp();
711 String portId = osFip.getPortId();
712
713 if (Strings.isNullOrEmpty(portId)) {
714 portId = event.portId();
715 }
716
717 if (portId != null && instancePortService.instancePort(portId) != null) {
718 return portId;
719 }
720
721 return null;
722 }
Jian Li60312252018-05-10 18:40:32 +0900723 }
724
Jian Lie1a39032018-06-19 21:49:36 +0900725 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900726
727 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900728 public boolean isRelevant(InstancePortEvent event) {
729 // do not allow to proceed without leadership
730 NodeId leader = leadershipService.getLeader(appId.name());
731 return Objects.equals(localNodeId, leader);
Jian Li60312252018-05-10 18:40:32 +0900732 }
733
734 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900735 public void event(InstancePortEvent event) {
736 InstancePort instPort = event.subject();
737
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900738 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
Jian Lie1a39032018-06-19 21:49:36 +0900739 NetFloatingIP fip = associatedFloatingIp(instPort, ips);
740 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
741
Jian Li60312252018-05-10 18:40:32 +0900742 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900743 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Lie1a39032018-06-19 21:49:36 +0900744
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900745 osRouterAdminService.floatingIps().stream()
Jian Li46b74002018-07-15 18:39:08 +0900746 .filter(f -> f.getPortId() != null)
747 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li8f64feb2018-07-24 13:20:16 +0900748 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
Jian Lie1a39032018-06-19 21:49:36 +0900749
Jian Li60312252018-05-10 18:40:32 +0900750 break;
Jian Lie1a39032018-06-19 21:49:36 +0900751 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
752
753 if (gateways.size() == 1) {
754 return;
755 }
756
757 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900758 eventExecutor.execute(() ->
Jian Lie1a39032018-06-19 21:49:36 +0900759 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
Jian Liec5c32b2018-07-13 14:28:58 +0900760 gateways, true)
761 );
Jian Lie1a39032018-06-19 21:49:36 +0900762 }
763
764 break;
765 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
766
Jian Liec5c32b2018-07-13 14:28:58 +0900767 InstancePort revisedInstPort = swapStaleLocation(event.subject());
768
Jian Lie1a39032018-06-19 21:49:36 +0900769 if (gateways.size() == 1) {
770 return;
771 }
772
773 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900774 DeviceId newDeviceId = event.subject().deviceId();
775 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Lie1a39032018-06-19 21:49:36 +0900776
777 OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
778 OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
779
780 if (oldGw != null && oldGw.equals(newGw)) {
781 return;
782 }
783
784 eventExecutor.execute(() ->
Jian Liec5c32b2018-07-13 14:28:58 +0900785 setFloatingIpArpRuleWithPortEvent(fip,
786 revisedInstPort, gateways, false));
Jian Lie1a39032018-06-19 21:49:36 +0900787 }
788 break;
789 default:
790 break;
791 }
Jian Li60312252018-05-10 18:40:32 +0900792 }
793 }
Jian Lif96685c2018-05-21 14:14:16 +0900794
795 private class InternalNodeEventListener implements OpenstackNodeListener {
796
797 @Override
798 public boolean isRelevant(OpenstackNodeEvent event) {
799 // do not allow to proceed without leadership
800 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900801 return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
Jian Lif96685c2018-05-21 14:14:16 +0900802 }
803
804 @Override
805 public void event(OpenstackNodeEvent event) {
806 OpenstackNode osNode = event.subject();
807 switch (event.type()) {
808 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900809 setDefaultArpRule(osNode, true);
810 setFloatingIpArpRuleForGateway(osNode, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900811 sendGratuitousArpToSwitch(event.subject(), true);
Jian Lif96685c2018-05-21 14:14:16 +0900812 break;
813 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900814 setDefaultArpRule(osNode, false);
815 setFloatingIpArpRuleForGateway(osNode, false);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900816 sendGratuitousArpToSwitch(event.subject(), false);
Jian Lif96685c2018-05-21 14:14:16 +0900817 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900818 case OPENSTACK_NODE_REMOVED:
819 sendGratuitousArpToSwitch(event.subject(), false);
820 break;
821
Jian Lif96685c2018-05-21 14:14:16 +0900822 default:
823 break;
824 }
825 }
826
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900827 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
828 Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
829
830 if (isCompleteCase) {
831 osNodeService.completeNodes(COMPUTE)
832 .stream()
833 .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
834 .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
835
836 } else {
837 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
838 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
839 oldCompleteGws.add(gatewayNode);
840
841 osNodeService.completeNodes(COMPUTE)
842 .stream()
843 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
844 .forEach(node -> {
845 OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
846 processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
847 });
848 }
849 }
850
851 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
852 OpenstackNode computeNode,
853 OpenstackNode gwNode) {
854 return OpenstackNetworkingUtil
855 .getGwByComputeDevId(gws, computeNode.intgBridge())
856 .intgBridge().equals(gwNode.intgBridge());
857 }
858
859 private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
860 instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
861 NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
862 osRouterAdminService);
863 Network network = osNetworkService.network(instancePort.networkId());
864 ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
865 osNetworkService, osRouterAdminService);
866 if (floatingIP != null && externalPeerRouter != null) {
867 processGratuitousArpPacketForFloatingIp(
868 floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
869 }
870 });
871 }
872
Jian Lif96685c2018-05-21 14:14:16 +0900873 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900874
875 if (getArpMode() == null) {
876 return;
877 }
878
Jian Li7f70bb72018-07-06 23:35:30 +0900879 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900880 case ARP_PROXY_MODE:
881 setDefaultArpRuleForProxyMode(osNode, install);
882 break;
883 case ARP_BROADCAST_MODE:
884 setDefaultArpRuleForBroadcastMode(osNode, install);
885 break;
886 default:
887 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900888 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900889 break;
890 }
891 }
892
893 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
894 TrafficSelector selector = DefaultTrafficSelector.builder()
895 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
896 .build();
897
898 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
899 .punt()
900 .build();
901
902 osFlowRuleService.setRule(
903 appId,
904 osNode.intgBridge(),
905 selector,
906 treatment,
907 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900908 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900909 install
910 );
911 }
912
913 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
914 // we only match ARP_REPLY in gateway node, because controller
915 // somehow need to process ARP_REPLY which is issued from
916 // external router...
917 TrafficSelector selector = DefaultTrafficSelector.builder()
918 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
919 .matchArpOp(ARP.OP_REPLY)
920 .build();
921
922 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
923 .punt()
924 .build();
925
926 osFlowRuleService.setRule(
927 appId,
928 osNode.intgBridge(),
929 selector,
930 treatment,
931 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900932 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900933 install
934 );
Daniel Park96f1e032018-08-09 13:30:57 +0900935
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900936 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +0900937 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +0900938 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +0900939 }
940 }
Daniel Park81a61a12016-02-26 08:24:44 +0900941}