blob: 6c3c16bdbf67b0bf8e723d41d01c9900282ef1de [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 Li1064e4f2018-05-29 16:16:53 +090018import com.google.common.collect.ImmutableSet;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.Sets;
Daniel Park81a61a12016-02-26 08:24:44 +090020import org.onlab.packet.ARP;
Jian Li60312252018-05-10 18:40:32 +090021import org.onlab.packet.EthType;
Daniel Park81a61a12016-02-26 08:24:44 +090022import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090023import org.onlab.packet.Ip4Address;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.MacAddress;
Jian Li60312252018-05-10 18:40:32 +090026import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090027import org.onosproject.cfg.ConfigProperty;
Jian Li60312252018-05-10 18:40:32 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Jian Li14a79f22018-06-05 03:44:22 +090033import org.onosproject.net.ConnectPoint;
Jian Li528f96e2020-04-29 23:36:15 +090034import org.onosproject.net.Device;
Hyunsun Moon0d457362017-06-27 17:19:41 +090035import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090036import org.onosproject.net.PortNumber;
Jian Li528f96e2020-04-29 23:36:15 +090037import org.onosproject.net.device.DeviceService;
Jian Li60312252018-05-10 18:40:32 +090038import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090039import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090040import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090041import org.onosproject.net.flow.TrafficTreatment;
42import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070043import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090044import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070045import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090046import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090047import org.onosproject.openstacknetworking.api.Constants;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090048import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
Jian Li60312252018-05-10 18:40:32 +090049import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li581f21a2018-10-12 09:33:56 +090050import org.onosproject.openstacknetworking.api.InstancePortAdminService;
Jian Li60312252018-05-10 18:40:32 +090051import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090052import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Li809b3ed2018-10-14 20:49:33 +090053import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
54import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090055import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090056import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Jian Li60312252018-05-10 18:40:32 +090057import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
58import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090059import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090060import org.onosproject.openstacknode.api.OpenstackNodeEvent;
61import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090062import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li34220ea2018-11-14 01:30:24 +090063import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090064import org.openstack4j.model.network.NetFloatingIP;
Daniel Park4fa1f5e2018-10-17 12:41:52 +090065import org.openstack4j.model.network.Network;
Jian Li809b3ed2018-10-14 20:49:33 +090066import org.openstack4j.model.network.Port;
Jian Li60312252018-05-10 18:40:32 +090067import org.openstack4j.model.network.Router;
Jian Li60312252018-05-10 18:40:32 +090068import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070069import org.osgi.service.component.annotations.Activate;
70import org.osgi.service.component.annotations.Component;
71import org.osgi.service.component.annotations.Deactivate;
72import org.osgi.service.component.annotations.Modified;
73import org.osgi.service.component.annotations.Reference;
74import org.osgi.service.component.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090075import org.slf4j.Logger;
76
77import java.nio.ByteBuffer;
Hyunsun Moon44aac662017-02-18 02:07:01 +090078import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090079import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070080import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090081import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090082
Jian Li4d138702018-11-27 17:25:28 +090083import static java.util.Objects.requireNonNull;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070084import static java.util.concurrent.Executors.newSingleThreadExecutor;
85import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090086import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
87import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li60312252018-05-10 18:40:32 +090088import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
89import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090090import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090091import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Ray Milkey8e406512018-10-24 15:56:50 -070092import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
93import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
94import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Lia5c7edf2020-02-24 16:42:24 +090095import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalGatewayIp;
Jian Li32b03622018-11-06 17:54:24 +090096import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
97import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.floatingIpByInstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li32b03622018-11-06 17:54:24 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.processGarpPacketForFloatingIp;
Jian Li528f96e2020-04-29 23:36:15 +0900102import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
103import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
104import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900105import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900106import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900107import static org.slf4j.LoggerFactory.getLogger;
108
109/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900110 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900111 */
Ray Milkey8e406512018-10-24 15:56:50 -0700112@Component(
113 immediate = true,
114 property = {
115 ARP_MODE + "=" + ARP_MODE_DEFAULT
116 }
117)
Daniel Park81a61a12016-02-26 08:24:44 +0900118public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700120 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900121
Hyunsun Moon44aac662017-02-18 02:07:01 +0900122 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
123 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900124 private static final String ARP_MODE = "arpMode";
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900127 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700130 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel park32b42202018-03-14 16:53:44 +0900133 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900136 protected OpenstackRouterAdminService osRouterAdminService;
daniel parkeeb8e042018-02-21 14:06:58 +0900137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parke49eb382017-04-05 16:48:28 +0900139 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li581f21a2018-10-12 09:33:56 +0900142 protected InstancePortAdminService instancePortService;
Jian Li1064e4f2018-05-29 16:16:53 +0900143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li528f96e2020-04-29 23:36:15 +0900145 protected DeviceService deviceService;
146
147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900148 protected ClusterService clusterService;
149
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700150 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900151 protected LeadershipService leadershipService;
152
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700153 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li60312252018-05-10 18:40:32 +0900154 protected OpenstackFlowRuleService osFlowRuleService;
155
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700156 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li1064e4f2018-05-29 16:16:53 +0900157 protected OpenstackNetworkService osNetworkService;
158
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lif3a28b02018-06-11 21:29:13 +0900160 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900161
Ray Milkey8e406512018-10-24 15:56:50 -0700162 /** ARP processing mode, broadcast | proxy (default). **/
163 protected String arpMode = ARP_MODE_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900164
Ray Milkey8e406512018-10-24 15:56:50 -0700165 protected String gatewayMac = GATEWAY_MAC_DEFAULT;
Jian Li60312252018-05-10 18:40:32 +0900166
167 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900168 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li809b3ed2018-10-14 20:49:33 +0900169 private final OpenstackNetworkListener osNetworkListener = new InternalNetworkEventListener();
Jian Li60312252018-05-10 18:40:32 +0900170
171 private ApplicationId appId;
172 private NodeId localNodeId;
Jian Liec5c32b2018-07-13 14:28:58 +0900173
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 private final ExecutorService eventExecutor = newSingleThreadExecutor(
175 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700176
Hyunsun Moon0d457362017-06-27 17:19:41 +0900177 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700178
179 @Activate
180 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900181 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
182 configService.registerProperties(getClass());
183 localNodeId = clusterService.getLocalNode().id();
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900184 osRouterAdminService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900185 osNodeService.addListener(osNodeListener);
Jian Li809b3ed2018-10-14 20:49:33 +0900186 osNetworkService.addListener(osNetworkListener);
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);
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 Li60312252018-05-10 18:40:32 +0900198 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900200 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700201 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900202 }
203
Jian Li60312252018-05-10 18:40:32 +0900204 @Modified
Jian Li4d138702018-11-27 17:25:28 +0900205 protected void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900206 log.info("Modified");
207 }
208
Jian Li7f70bb72018-07-06 23:35:30 +0900209 private String getArpMode() {
210 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
211 return getPropertyValue(properties, ARP_MODE);
212 }
213
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700214 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900215 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900216
Jian Li7f70bb72018-07-06 23:35:30 +0900217 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900218 if (log.isTraceEnabled()) {
219 log.trace("ARP request received from {} for {}",
220 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
221 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
222 }
223
224 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900225
226 MacAddress targetMac = null;
227
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900228 NetFloatingIP floatingIP = osRouterAdminService.floatingIps().stream()
daniel parkeeb8e042018-02-21 14:06:58 +0900229 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
230 .findAny().orElse(null);
231
daniel park576969a2018-03-09 07:07:41 +0900232 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900233 if (floatingIP != null && floatingIP.getPortId() != null) {
Daniel Park96f1e032018-08-09 13:30:57 +0900234 InstancePort instPort = instancePortService.instancePort(floatingIP.getPortId());
235 if (instPort == null) {
236 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
237 return;
238 } else {
239 targetMac = instPort.macAddress();
240 }
241
Jian Li32b03622018-11-06 17:54:24 +0900242 OpenstackNode gw =
243 getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
Daniel Park96f1e032018-08-09 13:30:57 +0900244
245 if (gw == null) {
246 return;
247 }
248
249 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
Jian Li32b03622018-11-06 17:54:24 +0900250 if (!Objects.equals(gw.intgBridge(),
251 context.inPacket().receivedFrom().deviceId())) {
Daniel Park96f1e032018-08-09 13:30:57 +0900252 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 Li32b03622018-11-06 17:54:24 +0900289 Set<String> extRouterIps = osNetworkService.externalPeerRouters()
290 .stream()
291 .map(r -> r.ipAddress().toString())
292 .collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900293
Jian Lid4066ea2018-06-07 01:44:45 +0900294 // if SPA is NOT contained in existing external router IP set, we ignore it
295 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900296 return;
297 }
298
299 OpenstackNode node = osNodeService.node(cp.deviceId());
300
301 if (node == null) {
302 return;
303 }
304
305 // we only handles the ARP-Reply message received by gateway node
306 if (node.type() != GATEWAY) {
307 return;
308 }
309
310 if (receivedPortNum.equals(node.uplinkPortNum())) {
311 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900312 }
313 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900314 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900315 }
Daniel Park81a61a12016-02-26 08:24:44 +0900316 }
Daniel Park81a61a12016-02-26 08:24:44 +0900317 }
318
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700319 private class InternalPacketProcessor implements PacketProcessor {
320
321 @Override
322 public void process(PacketContext context) {
323 if (context.isHandled()) {
324 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900325 }
326
Jian Li34220ea2018-11-14 01:30:24 +0900327 InboundPacket pkt = context.inPacket();
328 Ethernet ethernet = pkt.parsed();
329 if (ethernet != null && ethernet.getEtherType() == Ethernet.TYPE_ARP) {
330 eventExecutor.execute(() -> {
331
332 if (!isRelevantHelper(context)) {
333 return;
334 }
335
336 processArpPacket(context, ethernet);
337 });
338 }
339 }
340
341 private boolean isRelevantHelper(PacketContext context) {
Hyunsun Moon0d457362017-06-27 17:19:41 +0900342 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
343 .stream().map(OpenstackNode::intgBridge)
344 .collect(Collectors.toSet());
345
Jian Li34220ea2018-11-14 01:30:24 +0900346 return gateways.contains(context.inPacket().receivedFrom().deviceId());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700347 }
348 }
349
daniel parkeeb8e042018-02-21 14:06:58 +0900350 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900351 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900352 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900353 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 .flatMap(osPort -> osPort.getFixedIps().stream())
355 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900356 }
Jian Li60312252018-05-10 18:40:32 +0900357
Jian Li809b3ed2018-10-14 20:49:33 +0900358 private void setFakeGatewayArpRuleByRouter(Router router, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900359 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lia5c7edf2020-02-24 16:42:24 +0900360 IpAddress externalIp = externalGatewayIp(router, osNetworkService);
Jian Li34220ea2018-11-14 01:30:24 +0900361
362 if (externalIp == null) {
363 log.debug("External IP is not found");
364 return;
365 }
366
367 setFakeGatewayArpRuleByExternalIp(externalIp, install);
Jian Li809b3ed2018-10-14 20:49:33 +0900368 }
369 }
Daniel Park96f1e032018-08-09 13:30:57 +0900370
Jian Liebde74d2018-11-14 00:18:57 +0900371 private void setFakeGatewayArpRuleByExternalIp(IpAddress ipAddress, boolean install) {
Daniel Park96f1e032018-08-09 13:30:57 +0900372
Jian Liebde74d2018-11-14 00:18:57 +0900373 TrafficSelector selector = DefaultTrafficSelector.builder()
374 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
375 .matchArpOp(ARP.OP_REQUEST)
376 .matchArpTpa(ipAddress.getIp4Address())
377 .build();
Daniel Park96f1e032018-08-09 13:30:57 +0900378
Jian Liaec1b132020-04-30 12:00:13 +0900379 osNodeService.completeNodes(GATEWAY).forEach(n -> {
380 Device device = deviceService.getDevice(n.intgBridge());
Daniel Park96f1e032018-08-09 13:30:57 +0900381
Jian Liaec1b132020-04-30 12:00:13 +0900382 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
383 .extension(buildMoveEthSrcToDstExtension(device), device.id())
384 .extension(buildMoveArpShaToThaExtension(device), device.id())
385 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
386 .setArpOp(ARP.OP_REPLY)
387 .setEthSrc(MacAddress.valueOf(gatewayMac))
388 .setArpSha(MacAddress.valueOf(gatewayMac))
389 .setArpSpa(ipAddress.getIp4Address())
390 .setOutput(PortNumber.IN_PORT)
391 .build();
392
Jian Liebde74d2018-11-14 00:18:57 +0900393 osFlowRuleService.setRule(
394 appId,
395 n.intgBridge(),
396 selector,
397 treatment,
398 PRIORITY_ARP_GATEWAY_RULE,
399 GW_COMMON_TABLE,
400 install
Jian Liaec1b132020-04-30 12:00:13 +0900401 );
402 }
Jian Liebde74d2018-11-14 00:18:57 +0900403 );
404
405 if (install) {
406 log.info("Install ARP Rule for Gateway Snat {}", ipAddress);
407 } else {
408 log.info("Uninstall ARP Rule for Gateway Snat {}", ipAddress);
409 }
Jian Li809b3ed2018-10-14 20:49:33 +0900410 }
411
412 /**
413 * An internal network event listener, intended to uninstall ARP rules for
414 * routing the packets destined to external gateway.
415 */
416 private class InternalNetworkEventListener implements OpenstackNetworkListener {
417
418 @Override
419 public boolean isRelevant(OpenstackNetworkEvent event) {
420 Port osPort = event.port();
421 if (osPort == null || osPort.getFixedIps() == null) {
422 return false;
423 }
424
Jian Li34220ea2018-11-14 01:30:24 +0900425 return DEVICE_OWNER_ROUTER_GW.equals(osPort.getDeviceOwner()) &&
426 ARP_BROADCAST_MODE.equals(getArpMode());
427 }
428
429 private boolean isRelevantHelper() {
430 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li809b3ed2018-10-14 20:49:33 +0900431 }
432
433 @Override
434 public void event(OpenstackNetworkEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900435 IpAddress ipAddress = externalIp(event.port());
Jian Li809b3ed2018-10-14 20:49:33 +0900436 switch (event.type()) {
437 case OPENSTACK_PORT_CREATED:
438 case OPENSTACK_PORT_UPDATED:
Jian Li4d138702018-11-27 17:25:28 +0900439 eventExecutor.execute(() -> processPortCreation(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900440 break;
441 case OPENSTACK_PORT_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900442 eventExecutor.execute(() -> processPortRemoval(ipAddress));
Jian Li809b3ed2018-10-14 20:49:33 +0900443 break;
444 default:
445 // do nothing
446 break;
447 }
Daniel Park96f1e032018-08-09 13:30:57 +0900448 }
Jian Li34220ea2018-11-14 01:30:24 +0900449
Jian Li4d138702018-11-27 17:25:28 +0900450 private void processPortCreation(IpAddress ipAddress) {
451 if (!isRelevantHelper() || ipAddress == null) {
452 return;
453 }
454
455 setFakeGatewayArpRuleByExternalIp(ipAddress, true);
456 }
457
458 private void processPortRemoval(IpAddress ipAddress) {
459 if (!isRelevantHelper() || ipAddress == null) {
460 return;
461 }
462
463 setFakeGatewayArpRuleByExternalIp(ipAddress, false);
464 }
465
Jian Li34220ea2018-11-14 01:30:24 +0900466 private IpAddress externalIp(Port port) {
467 IP ip = port.getFixedIps().stream().findAny().orElse(null);
468
469 if (ip != null && ip.getIpAddress() != null) {
470 return IpAddress.valueOf(ip.getIpAddress());
471 }
472
473 return null;
474 }
Daniel Park96f1e032018-08-09 13:30:57 +0900475 }
476
Jian Li60312252018-05-10 18:40:32 +0900477 /**
478 * An internal router event listener, intended to install/uninstall
479 * ARP rules for forwarding packets created from floating IPs.
480 */
481 private class InternalRouterEventListener implements OpenstackRouterListener {
482
Jian Li34220ea2018-11-14 01:30:24 +0900483 private boolean isRelevantHelper() {
484 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Li60312252018-05-10 18:40:32 +0900485 }
486
487 @Override
488 public void event(OpenstackRouterEvent event) {
489 switch (event.type()) {
490 case OPENSTACK_ROUTER_CREATED:
Jian Liebde74d2018-11-14 00:18:57 +0900491 // add a router with external gateway
492 case OPENSTACK_ROUTER_GATEWAY_ADDED:
493 // add a gateway manually after adding a router
Jian Li4d138702018-11-27 17:25:28 +0900494 eventExecutor.execute(() -> processRouterGwCreation(event));
Jian Li60312252018-05-10 18:40:32 +0900495 break;
496 case OPENSTACK_ROUTER_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900497 // remove a router with external gateway
Jian Li60312252018-05-10 18:40:32 +0900498 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
Jian Liebde74d2018-11-14 00:18:57 +0900499 // remove a gateway from an existing router
Jian Li4d138702018-11-27 17:25:28 +0900500 eventExecutor.execute(() -> processRouterGwRemoval(event));
Jian Li60312252018-05-10 18:40:32 +0900501 break;
Jian Li60312252018-05-10 18:40:32 +0900502 default:
503 // do nothing for the other events
504 break;
505 }
506 }
507
Jian Li4d138702018-11-27 17:25:28 +0900508 private void processRouterGwCreation(OpenstackRouterEvent event) {
509 if (!isRelevantHelper()) {
510 return;
511 }
512
513 // add a router with external gateway
514 setFakeGatewayArpRuleByRouter(event.subject(), true);
515 }
516
517 private void processRouterGwRemoval(OpenstackRouterEvent event) {
518 if (!isRelevantHelper()) {
519 return;
520 }
521
522 setFakeGatewayArpRuleByRouter(event.subject(), false);
523 }
Jian Li60312252018-05-10 18:40:32 +0900524 }
Jian Lif96685c2018-05-21 14:14:16 +0900525
526 private class InternalNodeEventListener implements OpenstackNodeListener {
527
528 @Override
529 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900530 return event.subject().type() == GATEWAY;
531 }
532
533 private boolean isRelevantHelper() {
534 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lif96685c2018-05-21 14:14:16 +0900535 }
536
537 @Override
538 public void event(OpenstackNodeEvent event) {
539 OpenstackNode osNode = event.subject();
540 switch (event.type()) {
541 case OPENSTACK_NODE_COMPLETE:
Jian Li4d138702018-11-27 17:25:28 +0900542 eventExecutor.execute(() -> processNodeCompletion(event, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900543 break;
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900544 case OPENSTACK_NODE_REMOVED:
Jian Li4d138702018-11-27 17:25:28 +0900545 eventExecutor.execute(() -> processNodeRemoval(event));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900546 break;
Jian Li238552d2019-09-24 22:32:02 +0900547 case OPENSTACK_NODE_INCOMPLETE:
Jian Lif96685c2018-05-21 14:14:16 +0900548 default:
549 break;
550 }
551 }
552
Jian Li4d138702018-11-27 17:25:28 +0900553 private void processNodeCompletion(OpenstackNodeEvent event, OpenstackNode node) {
554 if (!isRelevantHelper()) {
555 return;
556 }
557 setDefaultArpRule(node, true);
Jian Li4d138702018-11-27 17:25:28 +0900558 sendGratuitousArpToSwitch(event.subject(), true);
559 }
560
561 private void processNodeIncompletion(OpenstackNodeEvent event, OpenstackNode node) {
562 if (!isRelevantHelper()) {
563 return;
564 }
565 setDefaultArpRule(node, false);
Jian Li4d138702018-11-27 17:25:28 +0900566 sendGratuitousArpToSwitch(event.subject(), false);
567 }
568
569 private void processNodeRemoval(OpenstackNodeEvent event) {
570 if (!isRelevantHelper()) {
571 return;
572 }
573 sendGratuitousArpToSwitch(event.subject(), false);
574 }
575
Jian Li32b03622018-11-06 17:54:24 +0900576 private void sendGratuitousArpToSwitch(OpenstackNode gatewayNode,
577 boolean isCompleteCase) {
578 Set<OpenstackNode> completeGws =
579 ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900580
581 if (isCompleteCase) {
Jian Li32b03622018-11-06 17:54:24 +0900582 osNodeService.completeNodes(COMPUTE).stream()
583 .filter(node -> isGwSelectedByComputeNode(completeGws,
584 node, gatewayNode))
585 .forEach(node -> processGarpPacketForComputeNode(node, gatewayNode));
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900586
587 } else {
588 Set<OpenstackNode> oldCompleteGws = Sets.newConcurrentHashSet();
589 oldCompleteGws.addAll(ImmutableSet.copyOf(osNodeService.completeNodes(GATEWAY)));
590 oldCompleteGws.add(gatewayNode);
591
Jian Li32b03622018-11-06 17:54:24 +0900592 osNodeService.completeNodes(COMPUTE).stream()
593 .filter(node -> isGwSelectedByComputeNode(oldCompleteGws,
594 node, gatewayNode))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900595 .forEach(node -> {
Jian Li32b03622018-11-06 17:54:24 +0900596 OpenstackNode newSelectedGatewayNode =
597 getGwByComputeDevId(completeGws, node.intgBridge());
598 processGarpPacketForComputeNode(node, newSelectedGatewayNode);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900599 });
600 }
601 }
602
603 private boolean isGwSelectedByComputeNode(Set<OpenstackNode> gws,
604 OpenstackNode computeNode,
605 OpenstackNode gwNode) {
Jian Li4d138702018-11-27 17:25:28 +0900606 return requireNonNull(getGwByComputeDevId(gws, computeNode.intgBridge()))
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900607 .intgBridge().equals(gwNode.intgBridge());
608 }
609
Jian Li32b03622018-11-06 17:54:24 +0900610 private void processGarpPacketForComputeNode(OpenstackNode computeNode,
611 OpenstackNode gatewayNode) {
612 instancePortService.instancePort(computeNode.intgBridge())
613 .forEach(instancePort -> {
614 NetFloatingIP floatingIP =
615 floatingIpByInstancePort(instancePort, osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900616 Network network = osNetworkService.network(instancePort.networkId());
Jian Li32b03622018-11-06 17:54:24 +0900617 ExternalPeerRouter externalPeerRouter =
618 externalPeerRouterForNetwork(network, osNetworkService,
619 osRouterAdminService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900620 if (floatingIP != null && externalPeerRouter != null) {
Jian Li32b03622018-11-06 17:54:24 +0900621 processGarpPacketForFloatingIp(
622 floatingIP, instancePort, externalPeerRouter.vlanId(),
623 gatewayNode, packetService);
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900624 }
625 });
626 }
627
Jian Lif96685c2018-05-21 14:14:16 +0900628 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Lib6969502018-10-30 20:38:07 +0900629
630 if (getArpMode() == null) {
631 return;
632 }
Jian Liebde74d2018-11-14 00:18:57 +0900633 log.info("ARP mode is {}", getArpMode());
Jian Lib6969502018-10-30 20:38:07 +0900634
Jian Li7f70bb72018-07-06 23:35:30 +0900635 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900636 case ARP_PROXY_MODE:
637 setDefaultArpRuleForProxyMode(osNode, install);
638 break;
639 case ARP_BROADCAST_MODE:
640 setDefaultArpRuleForBroadcastMode(osNode, install);
641 break;
642 default:
643 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900644 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900645 break;
646 }
647 }
648
Jian Li32b03622018-11-06 17:54:24 +0900649 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode,
650 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900651 TrafficSelector selector = DefaultTrafficSelector.builder()
652 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
653 .build();
654
655 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
656 .punt()
657 .build();
658
659 osFlowRuleService.setRule(
660 appId,
661 osNode.intgBridge(),
662 selector,
663 treatment,
664 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900665 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900666 install
667 );
668 }
669
Jian Li32b03622018-11-06 17:54:24 +0900670 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
671 boolean install) {
Jian Lif96685c2018-05-21 14:14:16 +0900672 // we only match ARP_REPLY in gateway node, because controller
673 // somehow need to process ARP_REPLY which is issued from
674 // external router...
675 TrafficSelector selector = DefaultTrafficSelector.builder()
676 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
677 .matchArpOp(ARP.OP_REPLY)
678 .build();
679
680 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
681 .punt()
682 .build();
683
684 osFlowRuleService.setRule(
685 appId,
686 osNode.intgBridge(),
687 selector,
688 treatment,
689 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900690 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900691 install
692 );
Daniel Park96f1e032018-08-09 13:30:57 +0900693
Jian Liebde74d2018-11-14 00:18:57 +0900694 log.info("calling setFakeGatewayArpRuleByRouter.. ");
Daniel Park4fa1f5e2018-10-17 12:41:52 +0900695 osRouterAdminService.routers().stream()
Daniel Park96f1e032018-08-09 13:30:57 +0900696 .filter(router -> router.getExternalGatewayInfo() != null)
Jian Li809b3ed2018-10-14 20:49:33 +0900697 .forEach(router -> setFakeGatewayArpRuleByRouter(router, install));
Jian Lif96685c2018-05-21 14:14:16 +0900698 }
699 }
Daniel Park81a61a12016-02-26 08:24:44 +0900700}