blob: 6b96dfa2e8ba05e523f2e468bf98ce72aa1f7a18 [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();
319 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900320
SONA Project6bc5c4a2018-12-14 23:49:52 +0900321 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900322 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Daniel Park8a9220f2018-11-19 18:58:35 +0900323 tBuilder.popVlan();
Jian Li621f73c2018-12-15 01:49:22 +0900324 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900325 // do not remove fake gateway ARP rules, if there is another gateway
326 // which has the same subnet that to be removed
327 // this only occurs if we have duplicated subnets associated with
328 // different networks
329 if (!install) {
330 long numOfDupGws = osNetworkService.subnets().stream()
331 .filter(s -> !s.getId().equals(osSubnet.getId()))
332 .filter(s -> s.getGateway() != null)
333 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
334 .count();
335 if (numOfDupGws > 0) {
336 return;
337 }
338 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900339 }
340
341 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
342 .matchArpOp(ARP.OP_REQUEST)
343 .matchArpTpa(Ip4Address.valueOf(gateway));
344
Daniel Park613ac372018-06-28 14:30:11 +0900345 if (osNode == null) {
Jian Li4910c4b2019-04-01 18:06:40 +0900346 osNodeService.completeNodes(COMPUTE).forEach(n -> {
347 Device device = deviceService.getDevice(n.intgBridge());
348 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
349 .extension(buildMoveArpShaToThaExtension(device), device.id())
350 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
351 .setArpOp(ARP.OP_REPLY)
352 .setArpSha(MacAddress.valueOf(gatewayMac))
353 .setArpSpa(Ip4Address.valueOf(gateway))
354 .setOutput(PortNumber.IN_PORT);
355
356 osFlowRuleService.setRule(
357 appId,
358 n.intgBridge(),
359 sBuilder.build(),
360 tBuilder.build(),
361 PRIORITY_ARP_GATEWAY_RULE,
362 ARP_TABLE,
363 install
364 );
365 });
Daniel Park613ac372018-06-28 14:30:11 +0900366 } else {
Jian Li4910c4b2019-04-01 18:06:40 +0900367 Device device = deviceService.getDevice(osNode.intgBridge());
368 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
369 .extension(buildMoveArpShaToThaExtension(device), device.id())
370 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
371 .setArpOp(ARP.OP_REPLY)
372 .setArpSha(MacAddress.valueOf(gatewayMac))
373 .setArpSpa(Ip4Address.valueOf(gateway))
374 .setOutput(PortNumber.IN_PORT);
375
Daniel Park613ac372018-06-28 14:30:11 +0900376 osFlowRuleService.setRule(
377 appId,
378 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900379 sBuilder.build(),
380 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900381 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900382 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900383 install
384 );
385 }
Daniel Park613ac372018-06-28 14:30:11 +0900386 }
387 }
388
389 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900390 * Installs flow rules to match ARP request packets.
391 *
392 * @param port instance port
393 * @param install installation flag
394 */
395 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900396 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900397
SONA Project6bc5c4a2018-12-14 23:49:52 +0900398 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900399 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900400 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900401 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900402 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900403 break;
404 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900405 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900406 break;
407 default:
408 break;
409 }
410 }
411
412 /**
413 * Installs flow rules to match ARP reply packets.
414 *
415 * @param port instance port
416 * @param install installation flag
417 */
418 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900419 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900420
SONA Project6bc5c4a2018-12-14 23:49:52 +0900421 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900422 case VXLAN:
423 setArpReplyRuleForVxlan(port, install);
424 break;
Jian Li2d68c192018-12-13 15:52:59 +0900425 case GRE:
426 setArpReplyRuleForGre(port, install);
427 break;
Jian Li621f73c2018-12-15 01:49:22 +0900428 case GENEVE:
429 setArpReplyRuleForGeneve(port, install);
430 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900431 case VLAN:
432 setArpReplyRuleForVlan(port, install);
433 break;
434 default:
435 break;
436 }
437 }
438
439 /**
440 * Installs flow rules to match ARP request packets only for VxLAN.
441 *
442 * @param port instance port
443 * @param install installation flag
444 */
Jian Li2d68c192018-12-13 15:52:59 +0900445 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900446
447 OpenstackNode localNode = osNodeService.node(port.deviceId());
448
Jian Li5c09e212018-10-24 18:23:58 +0900449 String segId = osNetworkService.segmentId(port.networkId());
450
Jian Li7f70bb72018-07-06 23:35:30 +0900451 TrafficSelector selector = DefaultTrafficSelector.builder()
452 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
453 .matchArpOp(ARP.OP_REQUEST)
454 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900455 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900456 .build();
457
Jian Li2d68c192018-12-13 15:52:59 +0900458 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900459 }
460
461 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900462 * Installs flow rules to match ARP request packets for VLAN.
463 *
464 * @param port instance port
465 * @param install installation flag
466 */
467 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
468 TrafficSelector selector = getArpRequestSelectorForVlan(port);
469
470 setLocalArpRequestTreatmentForVlan(selector, port, install);
471 setRemoteArpRequestTreatmentForVlan(selector, port, install);
472 }
473
474 /**
475 * Obtains the ARP request selector for VLAN.
476 *
477 * @param port instance port
478 * @return traffic selector
479 */
480 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
481 String segId = osNetworkService.segmentId(port.networkId());
482
483 return DefaultTrafficSelector.builder()
484 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
485 .matchArpOp(ARP.OP_REQUEST)
486 .matchArpTpa(port.ipAddress().getIp4Address())
487 .matchVlanId(VlanId.vlanId(segId))
488 .build();
489 }
490
491 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900492 * Installs flow rules to match ARP reply packets only for VxLAN.
493 *
494 * @param port instance port
495 * @param install installation flag
496 */
497 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
498
499 OpenstackNode localNode = osNodeService.node(port.deviceId());
500
Jian Li5b155bf2018-11-21 18:16:26 +0900501 TrafficSelector selector = getArpReplySelectorForVxlan(port);
502
503 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900504 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
505 }
506
507 /**
508 * Installs flow rules to match ARP reply packets only for GRE.
509 *
510 * @param port instance port
511 * @param install installation flag
512 */
513 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
514
515 OpenstackNode localNode = osNodeService.node(port.deviceId());
516
517 TrafficSelector selector = getArpReplySelectorForGre(port);
518
519 setLocalArpReplyTreatmentForGre(selector, port, install);
520 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900521 }
522
523 /**
Jian Li621f73c2018-12-15 01:49:22 +0900524 * Installs flow rules to match ARP reply packets only for GENEVE.
525 *
526 * @param port instance port
527 * @param install installation flag
528 */
529 private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
530
531 OpenstackNode localNode = osNodeService.node(port.deviceId());
532
533 TrafficSelector selector = getArpReplySelectorForGeneve(port);
534
535 setLocalArpReplyTreatmentForGeneve(selector, port, install);
536 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
537 }
538
539 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900540 * Installs flow rules to match ARP reply packets only for VLAN.
541 *
542 * @param port instance port
543 * @param install installation flag
544 */
545 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
546
Jian Li5b155bf2018-11-21 18:16:26 +0900547 TrafficSelector selector = getArpReplySelectorForVlan(port);
548
549 setLocalArpReplyTreatmentForVlan(selector, port, install);
550 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900551 }
552
553 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900554 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900555 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900556 }
557
558 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900559 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900560 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900561 }
562
563 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900564 private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
565 return getArpReplySelectorForVnet(port, GENEVE);
566 }
567
568 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900569 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900570 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900571 }
572
573 // a helper method
574 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900575 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900576
577 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
578
SONA Project6bc5c4a2018-12-14 23:49:52 +0900579 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900580 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
581 sBuilder.matchVlanId(VlanId.vlanId(segId));
582 }
583
584 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900585 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
586 .matchArpOp(ARP.OP_REPLY)
587 .matchArpTpa(port.ipAddress().getIp4Address())
588 .matchArpTha(port.macAddress())
589 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900590 }
Jian Li7f70bb72018-07-06 23:35:30 +0900591
Jian Li5b155bf2018-11-21 18:16:26 +0900592 // a helper method
593 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
594 InstancePort port,
595 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900596 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900597 }
598
599 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900600 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
601 InstancePort port,
602 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900603 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900604 }
605
606 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900607 private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
608 InstancePort port,
609 boolean install) {
610 setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
611 }
612
613 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900614 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
615 InstancePort port,
616 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900617 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900618 }
619
620 // a helper method
621 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
622 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900623 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900624 boolean install) {
625 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
626
SONA Project6bc5c4a2018-12-14 23:49:52 +0900627 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900628 tBuilder.popVlan();
629 }
630
631 tBuilder.setOutput(port.portNumber());
632
633 osFlowRuleService.setRule(
634 appId,
635 port.deviceId(),
636 selector,
637 tBuilder.build(),
638 PRIORITY_ARP_REPLY_RULE,
639 ARP_TABLE,
640 install
641 );
642 }
643
644 // a helper method
645 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
646 InstancePort port,
647 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900648 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900649 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900650 .setOutput(port.portNumber())
651 .build();
652
653 osFlowRuleService.setRule(
654 appId,
655 port.deviceId(),
656 selector,
657 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900658 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900659 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900660 install
661 );
Jian Li7f70bb72018-07-06 23:35:30 +0900662 }
663
664 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900665 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
666 InstancePort port,
667 OpenstackNode localNode,
668 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900669 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
670 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900671
672 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
673 osNetworkService, remoteNode);
674
Jian Li7f70bb72018-07-06 23:35:30 +0900675 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900676 .extension(buildExtension(
677 deviceService,
678 remoteNode.intgBridge(),
679 localNode.dataIp().getIp4Address()),
680 remoteNode.intgBridge())
681 .setOutput(portNum)
682 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900683
684 osFlowRuleService.setRule(
685 appId,
686 remoteNode.intgBridge(),
687 selector,
688 treatmentToRemote,
689 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900690 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900691 install
692 );
693 }
694 }
695 }
696
697 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900698 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
699 InstancePort port,
700 boolean install) {
701 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
702 }
703
704 // a helper method
705 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
706 InstancePort port,
707 boolean install) {
708 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
709 }
710
711 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900712 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
713 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900714 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900715 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900716
717 int priority;
718 if (arpOp == ARP.OP_REQUEST) {
719 priority = PRIORITY_ARP_REQUEST_RULE;
720 } else if (arpOp == ARP.OP_REPLY) {
721 priority = PRIORITY_ARP_REPLY_RULE;
722 } else {
723 // if ARP op does not match with any operation mode, we simply
724 // configure the ARP request rule priority
725 priority = PRIORITY_ARP_REQUEST_RULE;
726 }
727
Jian Li7f70bb72018-07-06 23:35:30 +0900728 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900729 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
730 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900731 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
732 .setOutput(remoteNode.vlanPortNum())
733 .build();
734
735 osFlowRuleService.setRule(
736 appId,
737 remoteNode.intgBridge(),
738 selector,
739 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900740 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900741 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900742 install);
743 }
744 }
745 }
746
747 /**
748 * Extracts properties from the component configuration context.
749 *
750 * @param context the component context
751 */
752 private void readComponentConfiguration(ComponentContext context) {
753 Dictionary<?, ?> properties = context.getProperties();
754
755 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700756 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900757 log.info("Configured. Gateway MAC is {}", gatewayMac);
758 }
759
760 /**
Jian Lieae12362018-04-10 18:48:32 +0900761 * An internal packet processor which processes ARP request, and results in
762 * packet-out ARP reply.
763 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700764 private class InternalPacketProcessor implements PacketProcessor {
765
766 @Override
767 public void process(PacketContext context) {
768 if (context.isHandled()) {
769 return;
770 }
771
772 Ethernet ethPacket = context.inPacket().parsed();
773 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
774 return;
775 }
Jian Li32b03622018-11-06 17:54:24 +0900776
777 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700778 }
779 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900780
Jian Lieae12362018-04-10 18:48:32 +0900781 /**
782 * An internal network listener which listens to openstack network event,
783 * manages the gateway collection and installs flow rule that handles
784 * ARP request in data plane.
785 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900786 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
787
788 @Override
789 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900790 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900791
Jian Lieae12362018-04-10 18:48:32 +0900792 if (network == null) {
793 log.warn("Network is not specified.");
794 return false;
795 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900796 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900797 }
Jian Li5b155bf2018-11-21 18:16:26 +0900798 }
Jian Lieae12362018-04-10 18:48:32 +0900799
Jian Li5b155bf2018-11-21 18:16:26 +0900800 private boolean isRelevantHelper() {
801 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900802 }
803
804 @Override
805 public void event(OpenstackNetworkEvent event) {
806 switch (event.type()) {
807 case OPENSTACK_SUBNET_CREATED:
808 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900809 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900810 break;
811 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900812 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900813 break;
814 case OPENSTACK_NETWORK_CREATED:
815 case OPENSTACK_NETWORK_UPDATED:
816 case OPENSTACK_NETWORK_REMOVED:
817 case OPENSTACK_PORT_CREATED:
818 case OPENSTACK_PORT_UPDATED:
819 case OPENSTACK_PORT_REMOVED:
820 default:
821 // do nothing for the other events
822 break;
823 }
824 }
Jian Li6a47fd02018-11-27 21:51:03 +0900825
826 private void processSubnetCreation(OpenstackNetworkEvent event) {
827 if (!isRelevantHelper()) {
828 return;
829 }
830
831 setFakeGatewayArpRule(event.subnet(), event.subject(),
832 true, null);
833 }
834
835 private void processSubnetRemoval(OpenstackNetworkEvent event) {
836 if (!isRelevantHelper()) {
837 return;
838 }
839
840 setFakeGatewayArpRule(event.subnet(), event.subject(),
841 false, null);
842 }
Jian Lieae12362018-04-10 18:48:32 +0900843 }
844
845 /**
846 * An internal openstack node listener which is used for listening openstack
847 * node activity. As long as a node is in complete state, we will install
848 * default ARP rule to handle ARP request.
849 */
850 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900851 @Override
852 public boolean isRelevant(OpenstackNodeEvent event) {
853 return event.subject().type() == COMPUTE;
854 }
855
Jian Li34220ea2018-11-14 01:30:24 +0900856 private boolean isRelevantHelper() {
857 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900858 }
859
860 @Override
861 public void event(OpenstackNodeEvent event) {
862 OpenstackNode osNode = event.subject();
863 switch (event.type()) {
864 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900865 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900866 break;
867 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900868 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900869 break;
Jian Lieae12362018-04-10 18:48:32 +0900870 default:
871 break;
872 }
873 }
874
Jian Li6a47fd02018-11-27 21:51:03 +0900875 private void processNodeCompletion(OpenstackNode osNode) {
876 if (!isRelevantHelper()) {
877 return;
878 }
879
880 setDefaultArpRule(osNode, true);
881 setAllArpRules(osNode, true);
882 }
883
884 private void processNodeIncompletion(OpenstackNode osNode) {
885 if (!isRelevantHelper()) {
886 return;
887 }
888
889 setDefaultArpRule(osNode, false);
890 setAllArpRules(osNode, false);
891 }
892
Jian Lif96685c2018-05-21 14:14:16 +0900893 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900894
895 if (getArpMode() == null) {
896 return;
897 }
898
Jian Li7f70bb72018-07-06 23:35:30 +0900899 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900900 case ARP_PROXY_MODE:
901 setDefaultArpRuleForProxyMode(osNode, install);
902 break;
903 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900904 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900905 break;
906 default:
907 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900908 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900909 break;
Jian Lieae12362018-04-10 18:48:32 +0900910 }
911 }
Jian Lif96685c2018-05-21 14:14:16 +0900912
Jian Li6a47fd02018-11-27 21:51:03 +0900913 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
914 boolean install) {
915 setDefaultArpRuleForBroadcastMode(osNode, install);
916
917 // we do not add fake gateway ARP rules for FLAT network
918 // ARP packets generated by FLAT typed VM should not be
919 // delegated to switch to handle
920 osNetworkService.subnets().stream().filter(subnet ->
921 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +0900922 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +0900923 .forEach(subnet -> {
924 String netId = subnet.getNetworkId();
925 Network net = osNetworkService.network(netId);
926 setFakeGatewayArpRule(subnet, net, install, osNode);
927 });
928 }
929
Jian Lif96685c2018-05-21 14:14:16 +0900930 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
931 TrafficSelector selector = DefaultTrafficSelector.builder()
932 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
933 .build();
934
935 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
936 .punt()
937 .build();
938
939 osFlowRuleService.setRule(
940 appId,
941 osNode.intgBridge(),
942 selector,
943 treatment,
944 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900945 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900946 install
947 );
948 }
949
950 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
951 TrafficSelector selector = DefaultTrafficSelector.builder()
952 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
953 .matchArpOp(ARP.OP_REQUEST)
954 .build();
955
956 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
957 .setOutput(PortNumber.FLOOD)
958 .build();
959
960 osFlowRuleService.setRule(
961 appId,
962 osNode.intgBridge(),
963 selector,
964 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900965 PRIORITY_ARP_FLOOD_RULE,
966 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900967 install
968 );
969 }
Jian Li7f70bb72018-07-06 23:35:30 +0900970
Jian Li5b66ce02018-07-09 22:43:54 +0900971 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900972 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900973 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900974 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900975 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
976 .forEach(p -> {
977 setArpRequestRule(p, install);
978 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900979 });
980 }
981 }
Jian Lieae12362018-04-10 18:48:32 +0900982 }
983
984 /**
985 * An internal instance port listener which listens the port events generated
986 * from VM. When ARP a host which located in a remote compute node, we specify
987 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
988 * host IP address. When ARP a host which located in a local compute node,
989 * we specify only ARP OP mode as REQUEST.
990 */
991 private class InternalInstancePortListener implements InstancePortListener {
992
993 @Override
994 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900995 return ARP_BROADCAST_MODE.equals(getArpMode());
996 }
Jian Lieae12362018-04-10 18:48:32 +0900997
Jian Li34220ea2018-11-14 01:30:24 +0900998 private boolean isRelevantHelper(InstancePortEvent event) {
999 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +09001000 }
1001
1002 @Override
1003 public void event(InstancePortEvent event) {
1004 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +09001005 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001006 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +09001007 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +09001008 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +09001009 break;
1010 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +09001011 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +09001012 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001013 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +09001014 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +09001015 break;
Jian Lieae12362018-04-10 18:48:32 +09001016 default:
1017 break;
1018 }
1019 }
Jian Li6a47fd02018-11-27 21:51:03 +09001020
1021 private void processInstanceMigrationStart(InstancePortEvent event) {
1022 if (!isRelevantHelper(event)) {
1023 return;
1024 }
1025
1026 setArpRequestRule(event.subject(), true);
1027 setArpReplyRule(event.subject(), true);
1028 }
1029
1030 private void processInstanceMigrationEnd(InstancePortEvent event) {
1031 if (!isRelevantHelper(event)) {
1032 return;
1033 }
1034
1035 InstancePort revisedInstPort = swapStaleLocation(event.subject());
1036 setArpRequestRule(revisedInstPort, false);
1037 }
1038
1039 private void processInstanceRemoval(InstancePortEvent event) {
1040 if (!isRelevantHelper(event)) {
1041 return;
1042 }
1043
1044 setArpRequestRule(event.subject(), false);
1045 setArpReplyRule(event.subject(), false);
1046 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001047 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001048}