blob: 6ae7100893fbb49a3c80f120b81ce2b319d2a006 [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 Li28ec77f2018-10-31 07:07:25 +090079import org.openstack4j.model.network.RouterInterface;
Jian Li60312252018-05-10 18:40:32 +090080import org.osgi.service.component.ComponentContext;
Daniel Park81a61a12016-02-26 08:24:44 +090081import org.slf4j.Logger;
82
83import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090084import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090085import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070086import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090087import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090088
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070089import static java.util.concurrent.Executors.newSingleThreadExecutor;
90import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090091import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
92import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
93import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_ARP_MODE_STR;
94import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
95import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
96import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090097import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090098import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li581f21a2018-10-12 09:33:56 +090099import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
Jian Li24ec59f2018-05-23 19:01:25 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900104import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900105import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGratuitousArpPacketForFloatingIp;
Jian Liec5c32b2018-07-13 14:28:58 +0900106import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900107import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900109import static org.slf4j.LoggerFactory.getLogger;
110
111/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900113 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700114@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +0900115public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900116
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700117 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900118
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
120 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900121 private static final String ARP_MODE = "arpMode";
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900128
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900130 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700131
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900133 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900134
daniel parkeeb8e042018-02-21 14:06:58 +0900135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +0900136 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900137
Jian Li60312252018-05-10 18:40:32 +0900138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li581f21a2018-10-12 09:33:56 +0900139 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900140
141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li60312252018-05-10 18:40:32 +0900142 protected ClusterService clusterService;
143
144 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
145 protected LeadershipService leadershipService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
148 protected OpenstackFlowRuleService osFlowRuleService;
149
150 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li1064e4f2018-05-29 16:16:53 +0900151 protected OpenstackNetworkService osNetworkService;
152
153 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900154 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900155
Jian Li581f21a2018-10-12 09:33:56 +0900156 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
157 protected PreCommitPortService preCommitPortService;
158
Jian Li60312252018-05-10 18:40:32 +0900159 @Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
Daniel Park6041f102018-07-06 18:49:45 +0900160 label = "ARP processing mode, broadcast | proxy (default)")
Jian Li60312252018-05-10 18:40:32 +0900161 protected String arpMode = DEFAULT_ARP_MODE_STR;
162
163 protected String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
164
165 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900166 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900167 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900168 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900169
170 private ApplicationId appId;
171 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900172
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 private final ExecutorService eventExecutor = newSingleThreadExecutor(
174 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700175
Hyunsun Moon0d457362017-06-27 17:19:41 +0900176 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700177
178 @Activate
179 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900180 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
181 configService.registerProperties(getClass());
182 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900183 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900184 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900185 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900186 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900187 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700188 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
189 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900190 }
191
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700192 @Deactivate
193 protected void deactivate() {
194 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900195 instancePortService.removeListener(instPortListener);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900196 osRouterAdminService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900197 osNodeService.removeListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900198 osNetworkService.removeListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900199 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900200 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900201 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900202 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700203 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900204 }
205
Jian Li60312252018-05-10 18:40:32 +0900206 @Modified
207 void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900208 log.info("Modified");
209 }
210
Jian Li7f70bb72018-07-06 23:35:30 +0900211 private String getArpMode() {
212 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
213 return getPropertyValue(properties, ARP_MODE);
214 }
215
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700216 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900217 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900218
Jian Li7f70bb72018-07-06 23:35:30 +0900219 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900220 if (log.isTraceEnabled()) {
221 log.trace("ARP request received from {} for {}",
222 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
223 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
224 }
225
226 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900227
228 MacAddress targetMac = null;
229
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900230 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900231 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
232 .findAny().orElse(null);
233
daniel park576969a2018-03-09 07:07:41 +0900234 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900235 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900236 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
237 if (instPort == null) {
238 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
239 return;
240 } else {
241 targetMac = instPort.macAddress();
242 }
243
244 OpenstackNode gw = getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
245
246 if (gw == null) {
247 return;
248 }
249
250 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
251 if (!Objects.equals(gw.intgBridge(), context.inPacket().receivedFrom().deviceId())) {
252 return;
253 }
daniel parkeeb8e042018-02-21 14:06:58 +0900254 }
255
Daniel Park96f1e032018-08-09 13:30:57 +0900256 if (isExternalGatewaySourceIp(targetIp)) {
daniel parkeeb8e042018-02-21 14:06:58 +0900257 targetMac = Constants.DEFAULT_GATEWAY_MAC;
258 }
259
260 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900261 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
262 return;
263 }
264
daniel parkb5817102018-02-15 00:18:51 +0900265 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
266 targetMac, ethernet);
267
268 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900269 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900270
271 packetService.emit(new DefaultOutboundPacket(
272 context.inPacket().receivedFrom().deviceId(),
273 treatment,
274 ByteBuffer.wrap(ethReply.serialize())));
275
276 context.block();
Jian Li60312252018-05-10 18:40:32 +0900277 }
278
279 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900280 ConnectPoint cp = context.inPacket().receivedFrom();
281 PortNumber receivedPortNum = cp.port();
282 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
283 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
284
285 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
286
daniel parkb5817102018-02-15 00:18:51 +0900287 try {
Jian Li14a79f22018-06-05 03:44:22 +0900288
Jian Lid4066ea2018-06-07 01:44:45 +0900289 Set<String> extRouterIps = osNetworkService.externalPeerRouters().
Jian Li5e2ad4a2018-07-16 13:40:53 +0900290 stream().map(r -> r.ipAddress().toString()).collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900291
Jian Lid4066ea2018-06-07 01:44:45 +0900292 // if SPA is NOT contained in existing external router IP set, we ignore it
293 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900294 return;
295 }
296
297 OpenstackNode node = osNodeService.node(cp.deviceId());
298
299 if (node == null) {
300 return;
301 }
302
303 // we only handles the ARP-Reply message received by gateway node
304 if (node.type() != GATEWAY) {
305 return;
306 }
307
308 if (receivedPortNum.equals(node.uplinkPortNum())) {
309 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900310 }
311 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900312 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900313 }
Daniel Park81a61a12016-02-26 08:24:44 +0900314 }
Daniel Park81a61a12016-02-26 08:24:44 +0900315 }
316
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700317 private class InternalPacketProcessor implements PacketProcessor {
318
319 @Override
320 public void process(PacketContext context) {
321 if (context.isHandled()) {
322 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900323 }
324
325 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
326 .stream().map(OpenstackNode::intgBridge)
327 .collect(Collectors.toSet());
328
329 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700330 // return if the packet is not from gateway nodes
331 return;
332 }
333
334 InboundPacket pkt = context.inPacket();
335 Ethernet ethernet = pkt.parsed();
336 if (ethernet != null &&
337 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900338 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700339 }
340 }
341 }
342
daniel parkeeb8e042018-02-21 14:06:58 +0900343 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900344 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900346 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900347 .flatMap(osPort -> osPort.getFixedIps().stream())
348 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900349 }
Jian Li60312252018-05-10 18:40:32 +0900350
Jian Li60312252018-05-10 18:40:32 +0900351 /**
352 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900353 *
354 * @param gateway gateway node
355 * @param install flow rule installation flag
356 */
357 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900358 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900359
360 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
361 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
362 finalGws.addAll(ImmutableSet.copyOf(completedGws));
363
364 if (install) {
365 if (completedGws.contains(gateway)) {
366 if (completedGws.size() > 1) {
367 finalGws.remove(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900368 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900369 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900370 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900371 finalGws.add(gateway);
372 }
373 });
374 }
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900375 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900376 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900377 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900378 }
379 });
380 } else {
381 log.warn("Detected node should be included in completed gateway set");
382 }
383 } else {
384 if (!completedGws.contains(gateway)) {
385 finalGws.add(gateway);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900386 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900387 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900388 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, false);
Jian Li1064e4f2018-05-29 16:16:53 +0900389 }
390 });
391 finalGws.remove(gateway);
392 if (completedGws.size() >= 1) {
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900393 osRouterAdminService.floatingIps().forEach(fip -> {
Jian Li1064e4f2018-05-29 16:16:53 +0900394 if (fip.getPortId() != null) {
Jian Li8f64feb2018-07-24 13:20:16 +0900395 setFloatingIpArpRule(fip, fip.getPortId(), finalGws, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900396 }
397 });
398 }
399 } else {
400 log.warn("Detected node should NOT be included in completed gateway set");
401 }
402 }
403 }
404 }
405
406 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900407 * Installs/uninstalls ARP flow rules to the corresponding gateway by
408 * looking for compute node's device ID.
409 *
410 * @param fip floating IP
411 * @param port instance port
412 * @param gateways a collection of gateways
413 * @param install install flag
414 */
415 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
416 InstancePort port,
417 Set<OpenstackNode> gateways,
418 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900419 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900420
421 OpenstackNode gw = getGwByInstancePort(gateways, port);
422
423 if (gw == null) {
424 return;
425 }
426
427 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
428
429 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
430 }
431 }
432
433 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900434 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900435 * Note that, those rules will be only matched ARP_REQUEST packets,
436 * used for telling gateway node the mapped MAC address of requested IP,
437 * without the helps from controller.
438 *
439 * @param fip floating IP address
Jian Li8f64feb2018-07-24 13:20:16 +0900440 * @param portId port identifier
Jian Li1064e4f2018-05-29 16:16:53 +0900441 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900442 * @param install flow rule installation flag
443 */
Jian Li8f64feb2018-07-24 13:20:16 +0900444 private synchronized void setFloatingIpArpRule(NetFloatingIP fip, String portId,
Jian Li1064e4f2018-05-29 16:16:53 +0900445 Set<OpenstackNode> gateways,
446 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900447 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900448
449 if (fip == null) {
450 log.warn("Failed to set ARP broadcast rule for floating IP");
451 return;
452 }
453
Jian Li581f21a2018-10-12 09:33:56 +0900454 if (portId == null || (install && fip.getPortId() == null)) {
Jian Lida03ce92018-07-24 21:41:53 +0900455 log.trace("Unknown target ARP request for {}, ignore it",
Jian Li581f21a2018-10-12 09:33:56 +0900456 fip.getFloatingIpAddress());
Jian Lida03ce92018-07-24 21:41:53 +0900457 return;
458 }
459
Jian Li8f64feb2018-07-24 13:20:16 +0900460 InstancePort instPort = instancePortService.instancePort(portId);
Jian Li46b74002018-07-15 18:39:08 +0900461 MacAddress targetMac = instPort.macAddress();
Jian Lif3a28b02018-06-11 21:29:13 +0900462
Jian Lia171a432018-06-11 11:52:11 +0900463 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900464
465 if (gw == null) {
466 return;
467 }
468
Jian Li581f21a2018-10-12 09:33:56 +0900469 if (install) {
470 preCommitPortService.subscribePreCommit(instPort.portId(),
471 OPENSTACK_PORT_PRE_REMOVE, this.getClass().getName());
472 log.info("Subscribed the port {} on listening pre-remove event", instPort.portId());
473 } else {
474 preCommitPortService.unsubscribePreCommit(instPort.portId(),
475 OPENSTACK_PORT_PRE_REMOVE, instancePortService, this.getClass().getName());
476 log.info("Unsubscribed the port {} on listening pre-remove event", instPort.portId());
477 }
478
Jian Li24ec59f2018-05-23 19:01:25 +0900479 setArpRule(fip, targetMac, gw, install);
480 }
481 }
Jian Li60312252018-05-10 18:40:32 +0900482
Jian Li24ec59f2018-05-23 19:01:25 +0900483 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
484 OpenstackNode gateway, boolean install) {
485 TrafficSelector selector = DefaultTrafficSelector.builder()
Jian Li2360acb2018-10-17 00:46:31 +0900486 .matchInPort(gateway.uplinkPortNum())
Jian Li24ec59f2018-05-23 19:01:25 +0900487 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
488 .matchArpOp(ARP.OP_REQUEST)
489 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
490 .build();
Jian Li60312252018-05-10 18:40:32 +0900491
Jian Li24ec59f2018-05-23 19:01:25 +0900492 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
493 .setArpOp(ARP.OP_REPLY)
494 .setArpSha(targetMac)
495 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
496 .setOutput(PortNumber.IN_PORT)
497 .build();
Jian Li60312252018-05-10 18:40:32 +0900498
Jian Li24ec59f2018-05-23 19:01:25 +0900499 osFlowRuleService.setRule(
500 appId,
501 gateway.intgBridge(),
502 selector,
503 treatment,
504 PRIORITY_ARP_GATEWAY_RULE,
505 GW_COMMON_TABLE,
506 install
507 );
508
509 if (install) {
510 log.info("Install ARP Rule for Floating IP {}",
511 fip.getFloatingIpAddress());
512 } else {
513 log.info("Uninstall ARP Rule for Floating IP {}",
514 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900515 }
516 }
517
Jian Li809b3ed2018-10-14 20:49:33 +0900518 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Jian Li28ec77f2018-10-31 07:07:25 +0900519 setFakeGatewayArpRuleByGateway(router.getId(), router.getExternalGatewayInfo(), install);
Daniel Park96f1e032018-08-09 13:30:57 +0900520 }
521
Jian Li28ec77f2018-10-31 07:07:25 +0900522 private Set<IP> getExternalGatewaySnatIps(String routerId, ExternalGateway extGw) {
523 if (routerId == null) {
524 return ImmutableSet.of();
525 }
526
527 Set<String> portIds = osRouterAdminService.routerInterfaces(routerId).stream()
528 .map(RouterInterface::getPortId)
529 .collect(Collectors.toSet());
530
531 return portIds.stream()
532 .map(pid -> osNetworkAdminService.port(pid))
533 .filter(p -> Objects.equals(p.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
534 .flatMap(p -> p.getFixedIps().stream())
Daniel Park96f1e032018-08-09 13:30:57 +0900535 .collect(Collectors.toSet());
536 }
537
Jian Li28ec77f2018-10-31 07:07:25 +0900538 private void setFakeGatewayArpRuleByGateway(String routerId, ExternalGateway extGw, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900539 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
540
541 if (extGw == null) {
542 return;
543 }
544
Jian Li28ec77f2018-10-31 07:07:25 +0900545 setFakeGatewayArpRuleByIps(getExternalGatewaySnatIps(routerId, extGw), install);
Jian Li809b3ed2018-10-14 20:49:33 +0900546 }
547 }
Daniel Park96f1e032018-08-09 13:30:57 +0900548
Jian Li809b3ed2018-10-14 20:49:33 +0900549 private void setFakeGatewayArpRuleByIps(Set<IP> ips, boolean install) {
550 ips.forEach(ip -> {
551 TrafficSelector selector = DefaultTrafficSelector.builder()
552 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
553 .matchArpOp(ARP.OP_REQUEST)
554 .matchArpTpa(Ip4Address.valueOf(ip.getIpAddress()))
555 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900556
Jian Li809b3ed2018-10-14 20:49:33 +0900557 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
558 .setArpOp(ARP.OP_REPLY)
559 .setArpSha(MacAddress.valueOf(gatewayMac))
560 .setArpSpa(Ip4Address.valueOf(ip.getIpAddress()))
561 .setOutput(PortNumber.IN_PORT)
562 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900563
Jian Li809b3ed2018-10-14 20:49:33 +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 );
Daniel Park96f1e032018-08-09 13:30:57 +0900575
Jian Li809b3ed2018-10-14 20:49:33 +0900576 if (install) {
577 log.info("Install ARP Rule for Gateway Snat {}", ip.getIpAddress());
578 } else {
579 log.info("Uninstall ARP Rule for Gateway Snat {}", ip.getIpAddress());
580 }
581 });
582 }
583
584 /**
585 * An internal network event listener, intended to uninstall ARP rules for
586 * routing the packets destined to external gateway.
587 */
588 private class InternalNetworkEventListener implements OpenstackNetworkListener {
589
590 @Override
591 public boolean isRelevant(OpenstackNetworkEvent event) {
592 Port osPort = event.port();
593 if (osPort == null || osPort.getFixedIps() == null) {
594 return false;
595 }
596
597 // do not allow to proceed without leadership
598 NodeId leader = leadershipService.getLeader(appId.name());
599 return Objects.equals(localNodeId, leader) &&
Jian Li2360acb2018-10-17 00:46:31 +0900600 DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
601 ARP_BROADCAST_MODE.equals(getArpMode());
Jian Li809b3ed2018-10-14 20:49:33 +0900602 }
603
604 @Override
605 public void event(OpenstackNetworkEvent event) {
606 switch (event.type()) {
607 case OPENSTACK_PORT_CREATED:
608 case OPENSTACK_PORT_UPDATED:
609 eventExecutor.execute(() ->
610 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), true)
611 );
612 break;
613 case OPENSTACK_PORT_REMOVED:
614 eventExecutor.execute(() ->
615 setFakeGatewayArpRuleByIps((Set<IP>) event.port().getFixedIps(), false)
616 );
617 break;
618 default:
619 // do nothing
620 break;
621 }
Daniel Park96f1e032018-08-09 13:30:57 +0900622 }
623 }
624
Jian Li60312252018-05-10 18:40:32 +0900625 /**
626 * An internal router event listener, intended to install/uninstall
627 * ARP rules for forwarding packets created from floating IPs.
628 */
629 private class InternalRouterEventListener implements OpenstackRouterListener {
630
631 @Override
632 public boolean isRelevant(OpenstackRouterEvent event) {
633 // do not allow to proceed without leadership
634 NodeId leader = leadershipService.getLeader(appId.name());
635 return Objects.equals(localNodeId, leader);
636 }
637
638 @Override
639 public void event(OpenstackRouterEvent event) {
Jian Li1064e4f2018-05-29 16:16:53 +0900640
641 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
642
Jian Li60312252018-05-10 18:40:32 +0900643 switch (event.type()) {
644 case OPENSTACK_ROUTER_CREATED:
645 eventExecutor.execute(() ->
646 // add a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900647 setFakeGatewayArpRuleByRouter(event.subject(), true)
Jian Li60312252018-05-10 18:40:32 +0900648 );
649 break;
650 case OPENSTACK_ROUTER_REMOVED:
651 eventExecutor.execute(() ->
652 // remove a router with external gateway
Jian Li809b3ed2018-10-14 20:49:33 +0900653 setFakeGatewayArpRuleByRouter(event.subject(), false)
Jian Li60312252018-05-10 18:40:32 +0900654 );
655 break;
656 case OPENSTACK_ROUTER_GATEWAY_ADDED:
657 eventExecutor.execute(() ->
658 // add a gateway manually after adding a router
Jian Li28ec77f2018-10-31 07:07:25 +0900659 setFakeGatewayArpRuleByGateway(event.subject().getId(),
660 event.externalGateway(), true)
Jian Li60312252018-05-10 18:40:32 +0900661 );
662 break;
663 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
664 eventExecutor.execute(() ->
665 // remove a gateway from an existing router
Jian Li28ec77f2018-10-31 07:07:25 +0900666 setFakeGatewayArpRuleByGateway(event.subject().getId(),
667 event.externalGateway(), false)
Jian Li60312252018-05-10 18:40:32 +0900668 );
669 break;
670 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900671 if (getValidPortId(event) != null) {
672 eventExecutor.execute(() -> {
673 // associate a floating IP with an existing VM
674 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
675 completedGws, true);
676 });
677 }
Jian Li60312252018-05-10 18:40:32 +0900678 break;
679 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Lida03ce92018-07-24 21:41:53 +0900680 if (getValidPortId(event) != null) {
681 eventExecutor.execute(() -> {
682 // disassociate a floating IP with an existing VM
683 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
684 completedGws, false);
685 });
686 }
Jian Li60312252018-05-10 18:40:32 +0900687 break;
688 case OPENSTACK_FLOATING_IP_CREATED:
Jian Lida03ce92018-07-24 21:41:53 +0900689 // during floating IP creation, if the floating IP is
690 // associated with any port of VM, then we will set
691 // floating IP related ARP rules to gateway node
692 if (getValidPortId(event) != null) {
693 eventExecutor.execute(() -> {
694 // associate a floating IP with an existing VM
695 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
696 completedGws, true);
697 });
698 }
Jian Li60312252018-05-10 18:40:32 +0900699 break;
700 case OPENSTACK_FLOATING_IP_REMOVED:
Jian Lida03ce92018-07-24 21:41:53 +0900701 // during floating IP deletion, if the floating IP is
702 // still associated with any port of VM, then we will
703 // remove floating IP related ARP rules from gateway node
704 if (getValidPortId(event) != null) {
705 eventExecutor.execute(() -> {
706 // associate a floating IP with an existing VM
707 setFloatingIpArpRule(event.floatingIp(), getValidPortId(event),
708 completedGws, false);
709 });
710 }
Jian Li60312252018-05-10 18:40:32 +0900711 break;
712 default:
713 // do nothing for the other events
714 break;
715 }
716 }
717
Jian Lida03ce92018-07-24 21:41:53 +0900718 private String getValidPortId(OpenstackRouterEvent event) {
719 NetFloatingIP osFip = event.floatingIp();
720 String portId = osFip.getPortId();
721
722 if (Strings.isNullOrEmpty(portId)) {
723 portId = event.portId();
724 }
725
726 if (portId != null && instancePortService.instancePort(portId) != null) {
727 return portId;
728 }
729
730 return null;
731 }
Jian Li60312252018-05-10 18:40:32 +0900732 }
733
Jian Lie1a39032018-06-19 21:49:36 +0900734 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900735
736 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900737 public boolean isRelevant(InstancePortEvent event) {
738 // do not allow to proceed without leadership
739 NodeId leader = leadershipService.getLeader(appId.name());
740 return Objects.equals(localNodeId, leader);
Jian Li60312252018-05-10 18:40:32 +0900741 }
742
743 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900744 public void event(InstancePortEvent event) {
745 InstancePort instPort = event.subject();
746
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900747 Set<NetFloatingIP> ips = osRouterAdminService.floatingIps();
Jian Lie1a39032018-06-19 21:49:36 +0900748 NetFloatingIP fip = associatedFloatingIp(instPort, ips);
749 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
750
Jian Li60312252018-05-10 18:40:32 +0900751 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900752 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Lie1a39032018-06-19 21:49:36 +0900753
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900754 osRouterAdminService.floatingIps().stream()
Jian Li46b74002018-07-15 18:39:08 +0900755 .filter(f -> f.getPortId() != null)
756 .filter(f -> f.getPortId().equals(instPort.portId()))
Jian Li8f64feb2018-07-24 13:20:16 +0900757 .forEach(f -> setFloatingIpArpRule(f, instPort.portId(), gateways, true));
Jian Lie1a39032018-06-19 21:49:36 +0900758
Jian Li60312252018-05-10 18:40:32 +0900759 break;
Jian Lie1a39032018-06-19 21:49:36 +0900760 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
761
762 if (gateways.size() == 1) {
763 return;
764 }
765
766 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900767 eventExecutor.execute(() ->
Jian Lie1a39032018-06-19 21:49:36 +0900768 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
Jian Liec5c32b2018-07-13 14:28:58 +0900769 gateways, true)
770 );
Jian Lie1a39032018-06-19 21:49:36 +0900771 }
772
773 break;
774 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
775
Jian Liec5c32b2018-07-13 14:28:58 +0900776 InstancePort revisedInstPort = swapStaleLocation(event.subject());
777
Jian Lie1a39032018-06-19 21:49:36 +0900778 if (gateways.size() == 1) {
779 return;
780 }
781
782 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
Jian Liec5c32b2018-07-13 14:28:58 +0900783 DeviceId newDeviceId = event.subject().deviceId();
784 DeviceId oldDeviceId = revisedInstPort.deviceId();
Jian Lie1a39032018-06-19 21:49:36 +0900785
786 OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
787 OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
788
789 if (oldGw != null && oldGw.equals(newGw)) {
790 return;
791 }
792
793 eventExecutor.execute(() ->
Jian Liec5c32b2018-07-13 14:28:58 +0900794 setFloatingIpArpRuleWithPortEvent(fip,
795 revisedInstPort, gateways, false));
Jian Lie1a39032018-06-19 21:49:36 +0900796 }
797 break;
798 default:
799 break;
800 }
Jian Li60312252018-05-10 18:40:32 +0900801 }
802 }
Jian Lif96685c2018-05-21 14:14:16 +0900803
804 private class InternalNodeEventListener implements OpenstackNodeListener {
805
806 @Override
807 public boolean isRelevant(OpenstackNodeEvent event) {
808 // do not allow to proceed without leadership
809 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900810 return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
Jian Lif96685c2018-05-21 14:14:16 +0900811 }
812
813 @Override
814 public void event(OpenstackNodeEvent event) {
815 OpenstackNode osNode = event.subject();
816 switch (event.type()) {
817 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900818 setDefaultArpRule(osNode, true);
819 setFloatingIpArpRuleForGateway(osNode, true);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900820 sendGratuitousArpToSwitch(event.subject(), true);
Jian Lif96685c2018-05-21 14:14:16 +0900821 break;
822 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900823 setDefaultArpRule(osNode, false);
824 setFloatingIpArpRuleForGateway(osNode, false);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900825 sendGratuitousArpToSwitch(event.subject(), false);
Jian Lif96685c2018-05-21 14:14:16 +0900826 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900827 case OPENSTACK_NODE_REMOVED:
828 sendGratuitousArpToSwitch(event.subject(), false);
829 break;
830
Jian Lif96685c2018-05-21 14:14:16 +0900831 default:
832 break;
833 }
834 }
835
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900836 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode, boolean isCompleteCase) {
837 Set<OpenstackNode> completeGws = ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
838
839 if (isCompleteCase) {
840 osNodeService.completeNodes(COMPUTE)
841 .stream()
842 .filter(node -> isGwSelectedByComputeNode(completeGws, node, gatewayNode))
843 .forEach(node -> processGratuitousArpPacketForComputeNode(node, gatewayNode));
844
845 } else {
846 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
847 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
848 oldCompleteGws.add(gatewayNode);
849
850 osNodeService.completeNodes(COMPUTE)
851 .stream()
852 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws, node, gatewayNode))
853 .forEach(node -> {
854 OpenstackNode newSelectedGatewayNode = getGwByComputeDevId(completeGws, node.intgBridge());
855 processGratuitousArpPacketForComputeNode(node, newSelectedGatewayNode);
856 });
857 }
858 }
859
860 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
861 OpenstackNode computeNode,
862 OpenstackNode gwNode) {
863 return OpenstackNetworkingUtil
864 .getGwByComputeDevId(gws, computeNode.intgBridge())
865 .intgBridge().equals(gwNode.intgBridge());
866 }
867
868 private void processGratuitousArpPacketForComputeNode(OpenstackNode computeNode, OpenstackNode gatewayNode) {
869 instancePortService.instancePort(computeNode.intgBridge()).forEach(instancePort -> {
870 NetFloatingIP floatingIP = OpenstackNetworkingUtil.floatingIpByInstancePort(instancePort,
871 osRouterAdminService);
872 Network network = osNetworkService.network(instancePort.networkId());
873 ExternalPeerRouter externalPeerRouter = OpenstackNetworkingUtil.externalPeerRouterForNetwork(network,
874 osNetworkService, osRouterAdminService);
875 if (floatingIP != null && externalPeerRouter != null) {
876 processGratuitousArpPacketForFloatingIp(
877 floatingIP, instancePort, externalPeerRouter.vlanId(), gatewayNode, packetService);
878 }
879 });
880 }
881
Jian Lif96685c2018-05-21 14:14:16 +0900882 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900883
884 if (getArpMode() == null) {
885 return;
886 }
887
Jian Li7f70bb72018-07-06 23:35:30 +0900888 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900889 case ARP_PROXY_MODE:
890 setDefaultArpRuleForProxyMode(osNode, install);
891 break;
892 case ARP_BROADCAST_MODE:
893 setDefaultArpRuleForBroadcastMode(osNode, install);
894 break;
895 default:
896 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900897 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900898 break;
899 }
900 }
901
902 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
903 TrafficSelector selector = DefaultTrafficSelector.builder()
904 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
905 .build();
906
907 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
908 .punt()
909 .build();
910
911 osFlowRuleService.setRule(
912 appId,
913 osNode.intgBridge(),
914 selector,
915 treatment,
916 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900917 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900918 install
919 );
920 }
921
922 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
923 // we only match ARP_REPLY in gateway node, because controller
924 // somehow need to process ARP_REPLY which is issued from
925 // external router...
926 TrafficSelector selector = DefaultTrafficSelector.builder()
927 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
928 .matchArpOp(ARP.OP_REPLY)
929 .build();
930
931 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
932 .punt()
933 .build();
934
935 osFlowRuleService.setRule(
936 appId,
937 osNode.intgBridge(),
938 selector,
939 treatment,
940 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900941 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900942 install
943 );
Daniel Park96f1e032018-08-09 13:30:57 +0900944
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900945 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +0900946 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +0900947 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +0900948 }
949 }
Daniel Park81a61a12016-02-26 08:24:44 +0900950}