blob: 3b805e8f971789108af4531ff9a59f6ede5bd986 [file] [log] [blame]
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001/*
Jian Li8e7e6cd2018-03-30 13:33:08 +09002 * Copyright 2016-present Open Networking Foundation
3 *
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;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070017
Hyunsun Moonb974fca2016-06-30 21:20:39 -070018import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090019import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070020import org.onlab.packet.Ethernet;
21import org.onlab.packet.Ip4Address;
22import org.onlab.packet.IpAddress;
23import org.onlab.packet.MacAddress;
Daniel Park8a9220f2018-11-19 18:58:35 +090024import org.onlab.packet.VlanId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070025import org.onlab.util.Tools;
Hyunsun Moon44aac662017-02-18 02:07:01 +090026import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090027import org.onosproject.cfg.ConfigProperty;
Jian Lieae12362018-04-10 18:48:32 +090028import org.onosproject.cluster.ClusterService;
29import org.onosproject.cluster.LeadershipService;
30import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090031import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
Jian Lieae12362018-04-10 18:48:32 +090033import org.onosproject.mastership.MastershipService;
Jian Li4910c4b2019-04-01 18:06:40 +090034import org.onosproject.net.Device;
Jian Lieae12362018-04-10 18:48:32 +090035import org.onosproject.net.PortNumber;
36import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070038import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070040import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.packet.DefaultOutboundPacket;
42import org.onosproject.net.packet.PacketContext;
43import org.onosproject.net.packet.PacketProcessor;
44import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090046import org.onosproject.openstacknetworking.api.InstancePortEvent;
47import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090049import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090050import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Hyunsun Moon44aac662017-02-18 02:07:01 +090051import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
52import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
53import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090054import org.onosproject.openstacknode.api.OpenstackNode;
55import org.onosproject.openstacknode.api.OpenstackNodeEvent;
56import org.onosproject.openstacknode.api.OpenstackNodeListener;
57import org.onosproject.openstacknode.api.OpenstackNodeService;
58import org.openstack4j.model.network.Network;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070060import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Modified;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069
Hyunsun Moonb974fca2016-06-30 21:20:39 -070070import java.nio.ByteBuffer;
71import java.util.Dictionary;
Jian Lieae12362018-04-10 18:48:32 +090072import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070073import java.util.Set;
Jian Li32b03622018-11-06 17:54:24 +090074import java.util.concurrent.ExecutorService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070075
76import static com.google.common.base.Preconditions.checkNotNull;
Jian Li32b03622018-11-06 17:54:24 +090077import static java.util.concurrent.Executors.newSingleThreadExecutor;
78import static org.onlab.util.Tools.groupedThreads;
Jian Lieae12362018-04-10 18:48:32 +090079import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
80import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li5c09e212018-10-24 18:23:58 +090081import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090082import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090083import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li5c09e212018-10-24 18:23:58 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_FLOOD_RULE;
Jian Lieae12362018-04-10 18:48:32 +090085import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
86import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
87import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
Jian Lic2403592018-07-18 12:56:45 +090088import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090089import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
Jian Li621f73c2018-12-15 01:49:22 +090090import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090091import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
92import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
93import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -070094import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
95import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
96import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
97import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +0900101import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Jian Li4910c4b2019-04-01 18:06:40 +0900102import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
103import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
104import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Jian Lieae12362018-04-10 18:48:32 +0900105import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700106
107/**
108 * Handles ARP packet from VMs.
109 */
Ray Milkey8e406512018-10-24 15:56:50 -0700110@Component(
111 immediate = true,
112 property = {
113 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900114 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700115 }
116)
Jian Li6a47fd02018-11-27 21:51:03 +0900117public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700118
119 private final Logger log = LoggerFactory.getLogger(getClass());
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900122 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900125 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900128 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900131 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900134 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900137 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900140 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900143 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900144
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900146 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900149 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900152 protected OpenstackNodeService osNodeService;
153
Ray Milkey8e406512018-10-24 15:56:50 -0700154 /** Fake MAC address for virtual network subnet gateway. */
155 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700156
Ray Milkey8e406512018-10-24 15:56:50 -0700157 /** ARP processing mode, broadcast | proxy (default). */
158 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900159
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700160 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900161 private final InternalOpenstackNetworkListener osNetworkListener =
162 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900163 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
164 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
165
Jian Li32b03622018-11-06 17:54:24 +0900166 private final ExecutorService eventExecutor = newSingleThreadExecutor(
167 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
168
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169
170 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900171 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700172
173 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800174 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
176 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900177 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900179 osNodeService.addListener(osNodeListener);
180 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700181 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900182
183 instancePortService.addListener(instancePortListener);
184
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700186 }
187
188 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800189 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700190 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900192 osNodeService.removeListener(osNodeListener);
193 instancePortService.removeListener(instancePortListener);
194 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900195 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900196 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900197
198 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700199 }
200
201 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800202 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900203 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900204
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700205 log.info("Modified");
206 }
207
Jian Li7f70bb72018-07-06 23:35:30 +0900208 private String getArpMode() {
209 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
210 return getPropertyValue(properties, ARP_MODE);
211 }
212
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700213 /**
214 * Processes ARP request packets.
215 * It checks if the target IP is owned by a known host first and then ask to
216 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
217 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900218 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700219 * @param ethPacket ethernet packet
220 */
221 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900222
223 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900224 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900225 return;
226 }
227
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700228 ARP arpPacket = (ARP) ethPacket.getPayload();
229 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
230 return;
231 }
232
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
234 if (srcInstPort == null) {
235 log.trace("Failed to find source instance port(MAC:{})",
236 ethPacket.getSourceMAC());
237 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700238 }
239
Hyunsun Moon44aac662017-02-18 02:07:01 +0900240 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900241
Jian Liac30e272018-10-18 23:08:03 +0900242 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700244 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900245 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700246 return;
247 }
248
249 Ethernet ethReply = ARP.buildArpReply(
250 targetIp.getIp4Address(),
251 replyMac,
252 ethPacket);
253
254 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
255 .setOutput(context.inPacket().receivedFrom().port())
256 .build();
257
258 packetService.emit(new DefaultOutboundPacket(
259 context.inPacket().receivedFrom().deviceId(),
260 treatment,
261 ByteBuffer.wrap(ethReply.serialize())));
262 }
263
Jian Liac30e272018-10-18 23:08:03 +0900264 /**
265 * Denotes whether the given target IP is gateway IP.
266 *
267 * @param targetIp target IP address
268 * @return true if the given targetIP is gateway IP, false otherwise.
269 */
270 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900271 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900272 .filter(Objects::nonNull)
273 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900274 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
275 }
276
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700277 /**
278 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700280 *
281 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 * @param osNetId openstack network id of the source instance port
283 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700284 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700286 checkNotNull(targetIp);
287
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
289 if (instPort != null) {
290 log.trace("Found MAC from host service for {}", targetIp);
291 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700292 } else {
293 return MacAddress.NONE;
294 }
295 }
296
Jian Lieae12362018-04-10 18:48:32 +0900297 /**
Daniel Park613ac372018-06-28 14:30:11 +0900298 * Installs flow rules which convert ARP request packet into ARP reply
299 * by adding a fake gateway MAC address as Source Hardware Address.
300 *
301 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900302 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900303 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900304 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900305 */
Jian Li5b155bf2018-11-21 18:16:26 +0900306 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
307 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900308
Jian Li7f70bb72018-07-06 23:35:30 +0900309 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900310
SONA Project6bc5c4a2018-12-14 23:49:52 +0900311 Type netType = osNetworkService.networkType(network.getId());
312
Daniel Park613ac372018-06-28 14:30:11 +0900313 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900314 if (gateway == null) {
315 return;
316 }
Daniel Park613ac372018-06-28 14:30:11 +0900317
Daniel Park8a9220f2018-11-19 18:58:35 +0900318 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900319
SONA Project6bc5c4a2018-12-14 23:49:52 +0900320 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900321 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Jian Lia2995192019-04-02 14:13:04 +0900322
Jian Li621f73c2018-12-15 01:49:22 +0900323 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900324 // do not remove fake gateway ARP rules, if there is another gateway
325 // which has the same subnet that to be removed
326 // this only occurs if we have duplicated subnets associated with
327 // different networks
328 if (!install) {
329 long numOfDupGws = osNetworkService.subnets().stream()
330 .filter(s -> !s.getId().equals(osSubnet.getId()))
331 .filter(s -> s.getGateway() != null)
332 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
333 .count();
334 if (numOfDupGws > 0) {
335 return;
336 }
337 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900338 }
339
340 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
341 .matchArpOp(ARP.OP_REQUEST)
342 .matchArpTpa(Ip4Address.valueOf(gateway));
343
Daniel Park613ac372018-06-28 14:30:11 +0900344 if (osNode == null) {
Jian Li4910c4b2019-04-01 18:06:40 +0900345 osNodeService.completeNodes(COMPUTE).forEach(n -> {
346 Device device = deviceService.getDevice(n.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900347
348 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
349
350 if (netType == VLAN) {
351 tBuilder.popVlan();
352 }
353
Jian Li4910c4b2019-04-01 18:06:40 +0900354 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
355 .extension(buildMoveArpShaToThaExtension(device), device.id())
356 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
357 .setArpOp(ARP.OP_REPLY)
358 .setArpSha(MacAddress.valueOf(gatewayMac))
359 .setArpSpa(Ip4Address.valueOf(gateway))
Jian Li1b5c5fa2019-04-24 13:51:28 +0900360 .setEthSrc(MacAddress.valueOf(gatewayMac))
Jian Li4910c4b2019-04-01 18:06:40 +0900361 .setOutput(PortNumber.IN_PORT);
362
363 osFlowRuleService.setRule(
364 appId,
365 n.intgBridge(),
366 sBuilder.build(),
367 tBuilder.build(),
368 PRIORITY_ARP_GATEWAY_RULE,
369 ARP_TABLE,
370 install
371 );
372 });
Daniel Park613ac372018-06-28 14:30:11 +0900373 } else {
Jian Li4910c4b2019-04-01 18:06:40 +0900374 Device device = deviceService.getDevice(osNode.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900375
376 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
377
378 if (netType == VLAN) {
379 tBuilder.popVlan();
380 }
381
Jian Li4910c4b2019-04-01 18:06:40 +0900382 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
383 .extension(buildMoveArpShaToThaExtension(device), device.id())
384 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
385 .setArpOp(ARP.OP_REPLY)
386 .setArpSha(MacAddress.valueOf(gatewayMac))
387 .setArpSpa(Ip4Address.valueOf(gateway))
388 .setOutput(PortNumber.IN_PORT);
389
Daniel Park613ac372018-06-28 14:30:11 +0900390 osFlowRuleService.setRule(
391 appId,
392 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900393 sBuilder.build(),
394 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900395 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900396 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900397 install
398 );
399 }
Daniel Park613ac372018-06-28 14:30:11 +0900400 }
401 }
402
403 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900404 * Installs flow rules to match ARP request packets.
405 *
406 * @param port instance port
407 * @param install installation flag
408 */
409 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900410 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900411
SONA Project6bc5c4a2018-12-14 23:49:52 +0900412 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900413 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900414 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900415 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900416 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900417 break;
418 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900419 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900420 break;
421 default:
422 break;
423 }
424 }
425
426 /**
427 * Installs flow rules to match ARP reply packets.
428 *
429 * @param port instance port
430 * @param install installation flag
431 */
432 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900433 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900434
SONA Project6bc5c4a2018-12-14 23:49:52 +0900435 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900436 case VXLAN:
437 setArpReplyRuleForVxlan(port, install);
438 break;
Jian Li2d68c192018-12-13 15:52:59 +0900439 case GRE:
440 setArpReplyRuleForGre(port, install);
441 break;
Jian Li621f73c2018-12-15 01:49:22 +0900442 case GENEVE:
443 setArpReplyRuleForGeneve(port, install);
444 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900445 case VLAN:
446 setArpReplyRuleForVlan(port, install);
447 break;
448 default:
449 break;
450 }
451 }
452
453 /**
454 * Installs flow rules to match ARP request packets only for VxLAN.
455 *
456 * @param port instance port
457 * @param install installation flag
458 */
Jian Li2d68c192018-12-13 15:52:59 +0900459 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900460
461 OpenstackNode localNode = osNodeService.node(port.deviceId());
462
Jian Li5c09e212018-10-24 18:23:58 +0900463 String segId = osNetworkService.segmentId(port.networkId());
464
Jian Li7f70bb72018-07-06 23:35:30 +0900465 TrafficSelector selector = DefaultTrafficSelector.builder()
466 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
467 .matchArpOp(ARP.OP_REQUEST)
468 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900469 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900470 .build();
471
Jian Li2d68c192018-12-13 15:52:59 +0900472 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900473 }
474
475 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900476 * Installs flow rules to match ARP request packets for VLAN.
477 *
478 * @param port instance port
479 * @param install installation flag
480 */
481 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
482 TrafficSelector selector = getArpRequestSelectorForVlan(port);
483
484 setLocalArpRequestTreatmentForVlan(selector, port, install);
485 setRemoteArpRequestTreatmentForVlan(selector, port, install);
486 }
487
488 /**
489 * Obtains the ARP request selector for VLAN.
490 *
491 * @param port instance port
492 * @return traffic selector
493 */
494 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
495 String segId = osNetworkService.segmentId(port.networkId());
496
497 return DefaultTrafficSelector.builder()
498 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
499 .matchArpOp(ARP.OP_REQUEST)
500 .matchArpTpa(port.ipAddress().getIp4Address())
501 .matchVlanId(VlanId.vlanId(segId))
502 .build();
503 }
504
505 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900506 * Installs flow rules to match ARP reply packets only for VxLAN.
507 *
508 * @param port instance port
509 * @param install installation flag
510 */
511 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
512
513 OpenstackNode localNode = osNodeService.node(port.deviceId());
514
Jian Li5b155bf2018-11-21 18:16:26 +0900515 TrafficSelector selector = getArpReplySelectorForVxlan(port);
516
517 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900518 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
519 }
520
521 /**
522 * Installs flow rules to match ARP reply packets only for GRE.
523 *
524 * @param port instance port
525 * @param install installation flag
526 */
527 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
528
529 OpenstackNode localNode = osNodeService.node(port.deviceId());
530
531 TrafficSelector selector = getArpReplySelectorForGre(port);
532
533 setLocalArpReplyTreatmentForGre(selector, port, install);
534 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900535 }
536
537 /**
Jian Li621f73c2018-12-15 01:49:22 +0900538 * Installs flow rules to match ARP reply packets only for GENEVE.
539 *
540 * @param port instance port
541 * @param install installation flag
542 */
543 private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
544
545 OpenstackNode localNode = osNodeService.node(port.deviceId());
546
547 TrafficSelector selector = getArpReplySelectorForGeneve(port);
548
549 setLocalArpReplyTreatmentForGeneve(selector, port, install);
550 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
551 }
552
553 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900554 * Installs flow rules to match ARP reply packets only for VLAN.
555 *
556 * @param port instance port
557 * @param install installation flag
558 */
559 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
560
Jian Li5b155bf2018-11-21 18:16:26 +0900561 TrafficSelector selector = getArpReplySelectorForVlan(port);
562
563 setLocalArpReplyTreatmentForVlan(selector, port, install);
564 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900565 }
566
567 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900568 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900569 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900570 }
571
572 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900573 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900574 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900575 }
576
577 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900578 private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
579 return getArpReplySelectorForVnet(port, GENEVE);
580 }
581
582 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900583 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900584 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900585 }
586
587 // a helper method
588 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900589 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900590
591 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
592
SONA Project6bc5c4a2018-12-14 23:49:52 +0900593 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900594 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
595 sBuilder.matchVlanId(VlanId.vlanId(segId));
596 }
597
598 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900599 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
600 .matchArpOp(ARP.OP_REPLY)
601 .matchArpTpa(port.ipAddress().getIp4Address())
602 .matchArpTha(port.macAddress())
603 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900604 }
Jian Li7f70bb72018-07-06 23:35:30 +0900605
Jian Li5b155bf2018-11-21 18:16:26 +0900606 // a helper method
607 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
608 InstancePort port,
609 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900610 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900611 }
612
613 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900614 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
615 InstancePort port,
616 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900617 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900618 }
619
620 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900621 private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
622 InstancePort port,
623 boolean install) {
624 setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
625 }
626
627 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900628 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
629 InstancePort port,
630 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900631 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900632 }
633
634 // a helper method
635 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
636 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900637 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900638 boolean install) {
639 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
640
SONA Project6bc5c4a2018-12-14 23:49:52 +0900641 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900642 tBuilder.popVlan();
643 }
644
645 tBuilder.setOutput(port.portNumber());
646
647 osFlowRuleService.setRule(
648 appId,
649 port.deviceId(),
650 selector,
651 tBuilder.build(),
652 PRIORITY_ARP_REPLY_RULE,
653 ARP_TABLE,
654 install
655 );
656 }
657
658 // a helper method
659 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
660 InstancePort port,
661 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900662 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900663 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900664 .setOutput(port.portNumber())
665 .build();
666
667 osFlowRuleService.setRule(
668 appId,
669 port.deviceId(),
670 selector,
671 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900672 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900673 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900674 install
675 );
Jian Li7f70bb72018-07-06 23:35:30 +0900676 }
677
678 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900679 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
680 InstancePort port,
681 OpenstackNode localNode,
682 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900683 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
684 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900685
686 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
687 osNetworkService, remoteNode);
688
Jian Li7f70bb72018-07-06 23:35:30 +0900689 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900690 .extension(buildExtension(
691 deviceService,
692 remoteNode.intgBridge(),
693 localNode.dataIp().getIp4Address()),
694 remoteNode.intgBridge())
695 .setOutput(portNum)
696 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900697
698 osFlowRuleService.setRule(
699 appId,
700 remoteNode.intgBridge(),
701 selector,
702 treatmentToRemote,
703 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900704 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900705 install
706 );
707 }
708 }
709 }
710
711 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900712 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
713 InstancePort port,
714 boolean install) {
715 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
716 }
717
718 // a helper method
719 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
720 InstancePort port,
721 boolean install) {
722 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
723 }
724
725 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900726 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
727 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900728 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900729 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900730
731 int priority;
732 if (arpOp == ARP.OP_REQUEST) {
733 priority = PRIORITY_ARP_REQUEST_RULE;
734 } else if (arpOp == ARP.OP_REPLY) {
735 priority = PRIORITY_ARP_REPLY_RULE;
736 } else {
737 // if ARP op does not match with any operation mode, we simply
738 // configure the ARP request rule priority
739 priority = PRIORITY_ARP_REQUEST_RULE;
740 }
741
Jian Li7f70bb72018-07-06 23:35:30 +0900742 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900743 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
744 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900745 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
746 .setOutput(remoteNode.vlanPortNum())
747 .build();
748
749 osFlowRuleService.setRule(
750 appId,
751 remoteNode.intgBridge(),
752 selector,
753 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900754 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900755 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900756 install);
757 }
758 }
759 }
760
761 /**
762 * Extracts properties from the component configuration context.
763 *
764 * @param context the component context
765 */
766 private void readComponentConfiguration(ComponentContext context) {
767 Dictionary<?, ?> properties = context.getProperties();
768
769 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700770 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900771 log.info("Configured. Gateway MAC is {}", gatewayMac);
772 }
773
774 /**
Jian Lieae12362018-04-10 18:48:32 +0900775 * An internal packet processor which processes ARP request, and results in
776 * packet-out ARP reply.
777 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700778 private class InternalPacketProcessor implements PacketProcessor {
779
780 @Override
781 public void process(PacketContext context) {
782 if (context.isHandled()) {
783 return;
784 }
785
786 Ethernet ethPacket = context.inPacket().parsed();
787 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
788 return;
789 }
Jian Li32b03622018-11-06 17:54:24 +0900790
791 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700792 }
793 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900794
Jian Lieae12362018-04-10 18:48:32 +0900795 /**
796 * An internal network listener which listens to openstack network event,
797 * manages the gateway collection and installs flow rule that handles
798 * ARP request in data plane.
799 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900800 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
801
802 @Override
803 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900804 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900805
Jian Lieae12362018-04-10 18:48:32 +0900806 if (network == null) {
807 log.warn("Network is not specified.");
808 return false;
809 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900810 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900811 }
Jian Li5b155bf2018-11-21 18:16:26 +0900812 }
Jian Lieae12362018-04-10 18:48:32 +0900813
Jian Li5b155bf2018-11-21 18:16:26 +0900814 private boolean isRelevantHelper() {
815 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900816 }
817
818 @Override
819 public void event(OpenstackNetworkEvent event) {
820 switch (event.type()) {
821 case OPENSTACK_SUBNET_CREATED:
822 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900823 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900824 break;
825 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900826 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900827 break;
828 case OPENSTACK_NETWORK_CREATED:
829 case OPENSTACK_NETWORK_UPDATED:
830 case OPENSTACK_NETWORK_REMOVED:
831 case OPENSTACK_PORT_CREATED:
832 case OPENSTACK_PORT_UPDATED:
833 case OPENSTACK_PORT_REMOVED:
834 default:
835 // do nothing for the other events
836 break;
837 }
838 }
Jian Li6a47fd02018-11-27 21:51:03 +0900839
840 private void processSubnetCreation(OpenstackNetworkEvent event) {
841 if (!isRelevantHelper()) {
842 return;
843 }
844
845 setFakeGatewayArpRule(event.subnet(), event.subject(),
846 true, null);
847 }
848
849 private void processSubnetRemoval(OpenstackNetworkEvent event) {
850 if (!isRelevantHelper()) {
851 return;
852 }
853
854 setFakeGatewayArpRule(event.subnet(), event.subject(),
855 false, null);
856 }
Jian Lieae12362018-04-10 18:48:32 +0900857 }
858
859 /**
860 * An internal openstack node listener which is used for listening openstack
861 * node activity. As long as a node is in complete state, we will install
862 * default ARP rule to handle ARP request.
863 */
864 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900865 @Override
866 public boolean isRelevant(OpenstackNodeEvent event) {
867 return event.subject().type() == COMPUTE;
868 }
869
Jian Li34220ea2018-11-14 01:30:24 +0900870 private boolean isRelevantHelper() {
871 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900872 }
873
874 @Override
875 public void event(OpenstackNodeEvent event) {
876 OpenstackNode osNode = event.subject();
877 switch (event.type()) {
878 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900879 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900880 break;
881 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900882 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900883 break;
Jian Lieae12362018-04-10 18:48:32 +0900884 default:
885 break;
886 }
887 }
888
Jian Li6a47fd02018-11-27 21:51:03 +0900889 private void processNodeCompletion(OpenstackNode osNode) {
890 if (!isRelevantHelper()) {
891 return;
892 }
893
894 setDefaultArpRule(osNode, true);
895 setAllArpRules(osNode, true);
896 }
897
898 private void processNodeIncompletion(OpenstackNode osNode) {
899 if (!isRelevantHelper()) {
900 return;
901 }
902
903 setDefaultArpRule(osNode, false);
904 setAllArpRules(osNode, false);
905 }
906
Jian Lif96685c2018-05-21 14:14:16 +0900907 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900908
909 if (getArpMode() == null) {
910 return;
911 }
912
Jian Li7f70bb72018-07-06 23:35:30 +0900913 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900914 case ARP_PROXY_MODE:
915 setDefaultArpRuleForProxyMode(osNode, install);
916 break;
917 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900918 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900919 break;
920 default:
921 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900922 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900923 break;
Jian Lieae12362018-04-10 18:48:32 +0900924 }
925 }
Jian Lif96685c2018-05-21 14:14:16 +0900926
Jian Li6a47fd02018-11-27 21:51:03 +0900927 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
928 boolean install) {
929 setDefaultArpRuleForBroadcastMode(osNode, install);
930
931 // we do not add fake gateway ARP rules for FLAT network
932 // ARP packets generated by FLAT typed VM should not be
933 // delegated to switch to handle
934 osNetworkService.subnets().stream().filter(subnet ->
935 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +0900936 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +0900937 .forEach(subnet -> {
938 String netId = subnet.getNetworkId();
939 Network net = osNetworkService.network(netId);
940 setFakeGatewayArpRule(subnet, net, install, osNode);
941 });
942 }
943
Jian Lif96685c2018-05-21 14:14:16 +0900944 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
945 TrafficSelector selector = DefaultTrafficSelector.builder()
946 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
947 .build();
948
949 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
950 .punt()
951 .build();
952
953 osFlowRuleService.setRule(
954 appId,
955 osNode.intgBridge(),
956 selector,
957 treatment,
958 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900959 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900960 install
961 );
962 }
963
964 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
965 TrafficSelector selector = DefaultTrafficSelector.builder()
966 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
967 .matchArpOp(ARP.OP_REQUEST)
968 .build();
969
970 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
971 .setOutput(PortNumber.FLOOD)
972 .build();
973
974 osFlowRuleService.setRule(
975 appId,
976 osNode.intgBridge(),
977 selector,
978 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900979 PRIORITY_ARP_FLOOD_RULE,
980 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900981 install
982 );
983 }
Jian Li7f70bb72018-07-06 23:35:30 +0900984
Jian Li5b66ce02018-07-09 22:43:54 +0900985 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900986 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900987 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900988 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900989 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
990 .forEach(p -> {
991 setArpRequestRule(p, install);
992 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900993 });
994 }
995 }
Jian Lieae12362018-04-10 18:48:32 +0900996 }
997
998 /**
999 * An internal instance port listener which listens the port events generated
1000 * from VM. When ARP a host which located in a remote compute node, we specify
1001 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
1002 * host IP address. When ARP a host which located in a local compute node,
1003 * we specify only ARP OP mode as REQUEST.
1004 */
1005 private class InternalInstancePortListener implements InstancePortListener {
1006
1007 @Override
1008 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +09001009 return ARP_BROADCAST_MODE.equals(getArpMode());
1010 }
Jian Lieae12362018-04-10 18:48:32 +09001011
Jian Li34220ea2018-11-14 01:30:24 +09001012 private boolean isRelevantHelper(InstancePortEvent event) {
1013 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +09001014 }
1015
1016 @Override
1017 public void event(InstancePortEvent event) {
1018 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +09001019 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001020 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +09001021 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +09001022 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +09001023 break;
1024 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +09001025 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +09001026 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001027 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +09001028 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +09001029 break;
Jian Lieae12362018-04-10 18:48:32 +09001030 default:
1031 break;
1032 }
1033 }
Jian Li6a47fd02018-11-27 21:51:03 +09001034
1035 private void processInstanceMigrationStart(InstancePortEvent event) {
1036 if (!isRelevantHelper(event)) {
1037 return;
1038 }
1039
1040 setArpRequestRule(event.subject(), true);
1041 setArpReplyRule(event.subject(), true);
1042 }
1043
1044 private void processInstanceMigrationEnd(InstancePortEvent event) {
1045 if (!isRelevantHelper(event)) {
1046 return;
1047 }
1048
1049 InstancePort revisedInstPort = swapStaleLocation(event.subject());
1050 setArpRequestRule(revisedInstPort, false);
1051 }
1052
1053 private void processInstanceRemoval(InstancePortEvent event) {
1054 if (!isRelevantHelper(event)) {
1055 return;
1056 }
1057
1058 setArpRequestRule(event.subject(), false);
1059 setArpReplyRule(event.subject(), false);
1060 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001061 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001062}