blob: a4e817f12ae4fd163f8bb3938c52ac26a53983bd [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;
Jian Lidaa91152019-09-08 00:35:11 +090058import org.openstack4j.model.common.IdEntity;
Jian Lieae12362018-04-10 18:48:32 +090059import org.openstack4j.model.network.Network;
Jian Lidaa91152019-09-08 00:35:11 +090060import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090061import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070062import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070063import org.osgi.service.component.annotations.Activate;
64import org.osgi.service.component.annotations.Component;
65import org.osgi.service.component.annotations.Deactivate;
66import org.osgi.service.component.annotations.Modified;
67import org.osgi.service.component.annotations.Reference;
68import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070069import org.slf4j.Logger;
70import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090071
Hyunsun Moonb974fca2016-06-30 21:20:39 -070072import java.nio.ByteBuffer;
73import java.util.Dictionary;
Jian Lieae12362018-04-10 18:48:32 +090074import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070075import java.util.Set;
Jian Li32b03622018-11-06 17:54:24 +090076import java.util.concurrent.ExecutorService;
Jian Lidaa91152019-09-08 00:35:11 +090077import java.util.stream.Collectors;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070078
79import static com.google.common.base.Preconditions.checkNotNull;
Jian Li32b03622018-11-06 17:54:24 +090080import static java.util.concurrent.Executors.newSingleThreadExecutor;
81import static org.onlab.util.Tools.groupedThreads;
Jian Lieae12362018-04-10 18:48:32 +090082import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
83import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li5c09e212018-10-24 18:23:58 +090084import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090085import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090086import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li5c09e212018-10-24 18:23:58 +090087import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_FLOOD_RULE;
Jian Lieae12362018-04-10 18:48:32 +090088import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
89import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
90import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
Jian Lic2403592018-07-18 12:56:45 +090091import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090092import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
Jian Li621f73c2018-12-15 01:49:22 +090093import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090094import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
95import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
96import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -070097import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
98import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
99import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
100import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900101import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +0900102import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +0900103import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +0900104import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Jian Li4910c4b2019-04-01 18:06:40 +0900105import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
106import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
107import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Jian Lieae12362018-04-10 18:48:32 +0900108import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700109
110/**
111 * Handles ARP packet from VMs.
112 */
Ray Milkey8e406512018-10-24 15:56:50 -0700113@Component(
114 immediate = true,
115 property = {
116 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900117 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700118 }
119)
Jian Li6a47fd02018-11-27 21:51:03 +0900120public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700121
122 private final Logger log = LoggerFactory.getLogger(getClass());
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900125 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900128 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900131 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900134 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900137 protected ClusterService clusterService;
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 LeadershipService leadershipService;
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 DeviceService deviceService;
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 MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900149 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900152 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700153
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900155 protected OpenstackNodeService osNodeService;
156
Ray Milkey8e406512018-10-24 15:56:50 -0700157 /** Fake MAC address for virtual network subnet gateway. */
158 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700159
Ray Milkey8e406512018-10-24 15:56:50 -0700160 /** ARP processing mode, broadcast | proxy (default). */
161 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900162
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700163 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164 private final InternalOpenstackNetworkListener osNetworkListener =
165 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900166 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
167 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
168
Jian Li32b03622018-11-06 17:54:24 +0900169 private final ExecutorService eventExecutor = newSingleThreadExecutor(
170 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
171
Hyunsun Moon44aac662017-02-18 02:07:01 +0900172
173 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900174 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700175
176 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800177 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900178 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
179 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900180 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900182 osNodeService.addListener(osNodeListener);
183 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700184 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900185
186 instancePortService.addListener(instancePortListener);
187
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700189 }
190
191 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800192 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700193 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900194 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900195 osNodeService.removeListener(osNodeListener);
196 instancePortService.removeListener(instancePortListener);
197 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900198 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900199 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900200
201 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700202 }
203
204 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800205 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900206 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900207
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700208 log.info("Modified");
209 }
210
Jian Li7f70bb72018-07-06 23:35:30 +0900211 private String getArpMode() {
212 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
213 return getPropertyValue(properties, ARP_MODE);
214 }
215
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700216 /**
217 * Processes ARP request packets.
218 * It checks if the target IP is owned by a known host first and then ask to
219 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
220 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900221 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700222 * @param ethPacket ethernet packet
223 */
224 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900225
226 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900227 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900228 return;
229 }
230
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700231 ARP arpPacket = (ARP) ethPacket.getPayload();
232 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
233 return;
234 }
235
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
237 if (srcInstPort == null) {
238 log.trace("Failed to find source instance port(MAC:{})",
239 ethPacket.getSourceMAC());
240 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700241 }
242
Hyunsun Moon44aac662017-02-18 02:07:01 +0900243 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900244
Jian Liac30e272018-10-18 23:08:03 +0900245 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900246 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700247 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900248 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700249 return;
250 }
251
252 Ethernet ethReply = ARP.buildArpReply(
253 targetIp.getIp4Address(),
254 replyMac,
255 ethPacket);
256
257 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
258 .setOutput(context.inPacket().receivedFrom().port())
259 .build();
260
261 packetService.emit(new DefaultOutboundPacket(
262 context.inPacket().receivedFrom().deviceId(),
263 treatment,
264 ByteBuffer.wrap(ethReply.serialize())));
265 }
266
Jian Liac30e272018-10-18 23:08:03 +0900267 /**
268 * Denotes whether the given target IP is gateway IP.
269 *
270 * @param targetIp target IP address
271 * @return true if the given targetIP is gateway IP, false otherwise.
272 */
273 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900274 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900275 .filter(Objects::nonNull)
276 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900277 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
278 }
279
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700280 /**
281 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900282 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700283 *
284 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900285 * @param osNetId openstack network id of the source instance port
286 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700287 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700289 checkNotNull(targetIp);
290
Hyunsun Moon44aac662017-02-18 02:07:01 +0900291 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
292 if (instPort != null) {
293 log.trace("Found MAC from host service for {}", targetIp);
294 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700295 } else {
296 return MacAddress.NONE;
297 }
298 }
299
Jian Lieae12362018-04-10 18:48:32 +0900300 /**
Daniel Park613ac372018-06-28 14:30:11 +0900301 * Installs flow rules which convert ARP request packet into ARP reply
302 * by adding a fake gateway MAC address as Source Hardware Address.
303 *
304 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900305 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900306 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900307 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900308 */
Jian Li5b155bf2018-11-21 18:16:26 +0900309 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
310 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900311
Jian Li7f70bb72018-07-06 23:35:30 +0900312 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900313
SONA Project6bc5c4a2018-12-14 23:49:52 +0900314 Type netType = osNetworkService.networkType(network.getId());
315
Daniel Park613ac372018-06-28 14:30:11 +0900316 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900317 if (gateway == null) {
318 return;
319 }
Daniel Park613ac372018-06-28 14:30:11 +0900320
Daniel Park8a9220f2018-11-19 18:58:35 +0900321 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900322
SONA Project6bc5c4a2018-12-14 23:49:52 +0900323 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900324 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Jian Lia2995192019-04-02 14:13:04 +0900325
Jian Li621f73c2018-12-15 01:49:22 +0900326 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900327 // do not remove fake gateway ARP rules, if there is another gateway
328 // which has the same subnet that to be removed
329 // this only occurs if we have duplicated subnets associated with
330 // different networks
331 if (!install) {
332 long numOfDupGws = osNetworkService.subnets().stream()
333 .filter(s -> !s.getId().equals(osSubnet.getId()))
334 .filter(s -> s.getGateway() != null)
335 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
336 .count();
337 if (numOfDupGws > 0) {
338 return;
339 }
340 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900341 }
342
343 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
344 .matchArpOp(ARP.OP_REQUEST)
345 .matchArpTpa(Ip4Address.valueOf(gateway));
346
Daniel Park613ac372018-06-28 14:30:11 +0900347 if (osNode == null) {
Jian Li4910c4b2019-04-01 18:06:40 +0900348 osNodeService.completeNodes(COMPUTE).forEach(n -> {
349 Device device = deviceService.getDevice(n.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900350
351 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
352
353 if (netType == VLAN) {
354 tBuilder.popVlan();
355 }
356
Jian Li4910c4b2019-04-01 18:06:40 +0900357 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
358 .extension(buildMoveArpShaToThaExtension(device), device.id())
359 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
360 .setArpOp(ARP.OP_REPLY)
361 .setArpSha(MacAddress.valueOf(gatewayMac))
362 .setArpSpa(Ip4Address.valueOf(gateway))
Jian Li1b5c5fa2019-04-24 13:51:28 +0900363 .setEthSrc(MacAddress.valueOf(gatewayMac))
Jian Li4910c4b2019-04-01 18:06:40 +0900364 .setOutput(PortNumber.IN_PORT);
365
366 osFlowRuleService.setRule(
367 appId,
368 n.intgBridge(),
369 sBuilder.build(),
370 tBuilder.build(),
371 PRIORITY_ARP_GATEWAY_RULE,
372 ARP_TABLE,
373 install
374 );
375 });
Daniel Park613ac372018-06-28 14:30:11 +0900376 } else {
Jian Li4910c4b2019-04-01 18:06:40 +0900377 Device device = deviceService.getDevice(osNode.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900378
379 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
380
381 if (netType == VLAN) {
382 tBuilder.popVlan();
383 }
384
Jian Li4910c4b2019-04-01 18:06:40 +0900385 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
386 .extension(buildMoveArpShaToThaExtension(device), device.id())
387 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
388 .setArpOp(ARP.OP_REPLY)
389 .setArpSha(MacAddress.valueOf(gatewayMac))
390 .setArpSpa(Ip4Address.valueOf(gateway))
391 .setOutput(PortNumber.IN_PORT);
392
Daniel Park613ac372018-06-28 14:30:11 +0900393 osFlowRuleService.setRule(
394 appId,
395 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900396 sBuilder.build(),
397 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900398 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900399 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900400 install
401 );
402 }
Daniel Park613ac372018-06-28 14:30:11 +0900403 }
404 }
405
406 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900407 * Installs flow rules to match ARP request packets.
408 *
409 * @param port instance port
410 * @param install installation flag
411 */
412 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900413 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900414
SONA Project6bc5c4a2018-12-14 23:49:52 +0900415 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900416 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900417 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900418 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900419 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900420 break;
421 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900422 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900423 break;
424 default:
425 break;
426 }
427 }
428
429 /**
430 * Installs flow rules to match ARP reply packets.
431 *
432 * @param port instance port
433 * @param install installation flag
434 */
435 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900436 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900437
SONA Project6bc5c4a2018-12-14 23:49:52 +0900438 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900439 case VXLAN:
440 setArpReplyRuleForVxlan(port, install);
441 break;
Jian Li2d68c192018-12-13 15:52:59 +0900442 case GRE:
443 setArpReplyRuleForGre(port, install);
444 break;
Jian Li621f73c2018-12-15 01:49:22 +0900445 case GENEVE:
446 setArpReplyRuleForGeneve(port, install);
447 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900448 case VLAN:
449 setArpReplyRuleForVlan(port, install);
450 break;
451 default:
452 break;
453 }
454 }
455
456 /**
457 * Installs flow rules to match ARP request packets only for VxLAN.
458 *
459 * @param port instance port
460 * @param install installation flag
461 */
Jian Li2d68c192018-12-13 15:52:59 +0900462 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900463
464 OpenstackNode localNode = osNodeService.node(port.deviceId());
465
Jian Li5c09e212018-10-24 18:23:58 +0900466 String segId = osNetworkService.segmentId(port.networkId());
467
Jian Li7f70bb72018-07-06 23:35:30 +0900468 TrafficSelector selector = DefaultTrafficSelector.builder()
469 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
470 .matchArpOp(ARP.OP_REQUEST)
471 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900472 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900473 .build();
474
Jian Li2d68c192018-12-13 15:52:59 +0900475 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900476 }
477
478 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900479 * Installs flow rules to match ARP request packets for VLAN.
480 *
481 * @param port instance port
482 * @param install installation flag
483 */
484 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
485 TrafficSelector selector = getArpRequestSelectorForVlan(port);
486
487 setLocalArpRequestTreatmentForVlan(selector, port, install);
488 setRemoteArpRequestTreatmentForVlan(selector, port, install);
489 }
490
491 /**
492 * Obtains the ARP request selector for VLAN.
493 *
494 * @param port instance port
495 * @return traffic selector
496 */
497 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
498 String segId = osNetworkService.segmentId(port.networkId());
499
500 return DefaultTrafficSelector.builder()
501 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
502 .matchArpOp(ARP.OP_REQUEST)
503 .matchArpTpa(port.ipAddress().getIp4Address())
504 .matchVlanId(VlanId.vlanId(segId))
505 .build();
506 }
507
508 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900509 * Installs flow rules to match ARP reply packets only for VxLAN.
510 *
511 * @param port instance port
512 * @param install installation flag
513 */
514 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
515
516 OpenstackNode localNode = osNodeService.node(port.deviceId());
517
Jian Li5b155bf2018-11-21 18:16:26 +0900518 TrafficSelector selector = getArpReplySelectorForVxlan(port);
519
520 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900521 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
522 }
523
524 /**
525 * Installs flow rules to match ARP reply packets only for GRE.
526 *
527 * @param port instance port
528 * @param install installation flag
529 */
530 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
531
532 OpenstackNode localNode = osNodeService.node(port.deviceId());
533
534 TrafficSelector selector = getArpReplySelectorForGre(port);
535
536 setLocalArpReplyTreatmentForGre(selector, port, install);
537 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900538 }
539
540 /**
Jian Li621f73c2018-12-15 01:49:22 +0900541 * Installs flow rules to match ARP reply packets only for GENEVE.
542 *
543 * @param port instance port
544 * @param install installation flag
545 */
546 private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
547
548 OpenstackNode localNode = osNodeService.node(port.deviceId());
549
550 TrafficSelector selector = getArpReplySelectorForGeneve(port);
551
552 setLocalArpReplyTreatmentForGeneve(selector, port, install);
553 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
554 }
555
556 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900557 * Installs flow rules to match ARP reply packets only for VLAN.
558 *
559 * @param port instance port
560 * @param install installation flag
561 */
562 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
563
Jian Li5b155bf2018-11-21 18:16:26 +0900564 TrafficSelector selector = getArpReplySelectorForVlan(port);
565
566 setLocalArpReplyTreatmentForVlan(selector, port, install);
567 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900568 }
569
570 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900571 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900572 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900573 }
574
575 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900576 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900577 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900578 }
579
580 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900581 private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
582 return getArpReplySelectorForVnet(port, GENEVE);
583 }
584
585 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900586 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900587 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900588 }
589
590 // a helper method
591 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900592 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900593
594 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
595
SONA Project6bc5c4a2018-12-14 23:49:52 +0900596 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900597 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
598 sBuilder.matchVlanId(VlanId.vlanId(segId));
599 }
600
601 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900602 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
603 .matchArpOp(ARP.OP_REPLY)
604 .matchArpTpa(port.ipAddress().getIp4Address())
605 .matchArpTha(port.macAddress())
606 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900607 }
Jian Li7f70bb72018-07-06 23:35:30 +0900608
Jian Li5b155bf2018-11-21 18:16:26 +0900609 // a helper method
610 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
611 InstancePort port,
612 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900613 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900614 }
615
616 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900617 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
618 InstancePort port,
619 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900620 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900621 }
622
623 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900624 private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
625 InstancePort port,
626 boolean install) {
627 setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
628 }
629
630 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900631 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
632 InstancePort port,
633 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900634 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900635 }
636
637 // a helper method
638 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
639 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900640 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900641 boolean install) {
642 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
643
SONA Project6bc5c4a2018-12-14 23:49:52 +0900644 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900645 tBuilder.popVlan();
646 }
647
648 tBuilder.setOutput(port.portNumber());
649
650 osFlowRuleService.setRule(
651 appId,
652 port.deviceId(),
653 selector,
654 tBuilder.build(),
655 PRIORITY_ARP_REPLY_RULE,
656 ARP_TABLE,
657 install
658 );
659 }
660
661 // a helper method
662 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
663 InstancePort port,
664 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900665 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900666 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900667 .setOutput(port.portNumber())
668 .build();
669
670 osFlowRuleService.setRule(
671 appId,
672 port.deviceId(),
673 selector,
674 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900675 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900676 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900677 install
678 );
Jian Li7f70bb72018-07-06 23:35:30 +0900679 }
680
681 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900682 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
683 InstancePort port,
684 OpenstackNode localNode,
685 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900686 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
687 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900688
689 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
690 osNetworkService, remoteNode);
691
Jian Li7f70bb72018-07-06 23:35:30 +0900692 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900693 .extension(buildExtension(
694 deviceService,
695 remoteNode.intgBridge(),
696 localNode.dataIp().getIp4Address()),
697 remoteNode.intgBridge())
698 .setOutput(portNum)
699 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900700
701 osFlowRuleService.setRule(
702 appId,
703 remoteNode.intgBridge(),
704 selector,
705 treatmentToRemote,
706 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900707 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900708 install
709 );
710 }
711 }
712 }
713
714 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900715 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
716 InstancePort port,
717 boolean install) {
718 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
719 }
720
721 // a helper method
722 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
723 InstancePort port,
724 boolean install) {
725 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
726 }
727
728 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900729 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
730 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900731 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900732 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900733
734 int priority;
735 if (arpOp == ARP.OP_REQUEST) {
736 priority = PRIORITY_ARP_REQUEST_RULE;
737 } else if (arpOp == ARP.OP_REPLY) {
738 priority = PRIORITY_ARP_REPLY_RULE;
739 } else {
740 // if ARP op does not match with any operation mode, we simply
741 // configure the ARP request rule priority
742 priority = PRIORITY_ARP_REQUEST_RULE;
743 }
744
Jian Li7f70bb72018-07-06 23:35:30 +0900745 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900746 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
747 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900748 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
749 .setOutput(remoteNode.vlanPortNum())
750 .build();
751
752 osFlowRuleService.setRule(
753 appId,
754 remoteNode.intgBridge(),
755 selector,
756 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900757 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900758 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900759 install);
760 }
761 }
762 }
763
764 /**
765 * Extracts properties from the component configuration context.
766 *
767 * @param context the component context
768 */
769 private void readComponentConfiguration(ComponentContext context) {
770 Dictionary<?, ?> properties = context.getProperties();
771
772 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700773 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900774 log.info("Configured. Gateway MAC is {}", gatewayMac);
775 }
776
777 /**
Jian Lieae12362018-04-10 18:48:32 +0900778 * An internal packet processor which processes ARP request, and results in
779 * packet-out ARP reply.
780 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700781 private class InternalPacketProcessor implements PacketProcessor {
782
783 @Override
784 public void process(PacketContext context) {
785 if (context.isHandled()) {
786 return;
787 }
788
789 Ethernet ethPacket = context.inPacket().parsed();
790 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
791 return;
792 }
Jian Li32b03622018-11-06 17:54:24 +0900793
794 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700795 }
796 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900797
Jian Lidaa91152019-09-08 00:35:11 +0900798 private void setBaseVnetArpRuleForBroadcastMode(OpenstackNode osNode,
799 String segId,
800 boolean isTunnel,
801 boolean install) {
802 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
803 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
804 .matchArpOp(ARP.OP_REQUEST);
805
806 if (isTunnel) {
807 sBuilder.matchTunnelId(Long.valueOf(segId));
808 } else {
809 sBuilder.matchVlanId(VlanId.vlanId(segId));
810 }
811
812 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
813 .setOutput(PortNumber.FLOOD)
814 .build();
815
816 osFlowRuleService.setRule(
817 appId,
818 osNode.intgBridge(),
819 sBuilder.build(),
820 treatment,
821 PRIORITY_ARP_FLOOD_RULE,
822 ARP_TABLE,
823 install
824 );
825 }
826
Jian Lieae12362018-04-10 18:48:32 +0900827 /**
828 * An internal network listener which listens to openstack network event,
829 * manages the gateway collection and installs flow rule that handles
830 * ARP request in data plane.
831 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900832 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
833
834 @Override
835 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900836 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900837
Jian Lieae12362018-04-10 18:48:32 +0900838 if (network == null) {
839 log.warn("Network is not specified.");
840 return false;
841 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900842 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900843 }
Jian Li5b155bf2018-11-21 18:16:26 +0900844 }
Jian Lieae12362018-04-10 18:48:32 +0900845
Jian Li5b155bf2018-11-21 18:16:26 +0900846 private boolean isRelevantHelper() {
847 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900848 }
849
850 @Override
851 public void event(OpenstackNetworkEvent event) {
852 switch (event.type()) {
853 case OPENSTACK_SUBNET_CREATED:
854 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900855 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900856 break;
857 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900858 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900859 break;
860 case OPENSTACK_NETWORK_CREATED:
861 case OPENSTACK_NETWORK_UPDATED:
Jian Lidaa91152019-09-08 00:35:11 +0900862 eventExecutor.execute(() -> processNetworkCreation(event));
863 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900864 case OPENSTACK_NETWORK_REMOVED:
Jian Lidaa91152019-09-08 00:35:11 +0900865 eventExecutor.execute(() -> processNetworkRemoval(event));
866 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900867 case OPENSTACK_PORT_CREATED:
868 case OPENSTACK_PORT_UPDATED:
869 case OPENSTACK_PORT_REMOVED:
870 default:
871 // do nothing for the other events
872 break;
873 }
874 }
Jian Li6a47fd02018-11-27 21:51:03 +0900875
876 private void processSubnetCreation(OpenstackNetworkEvent event) {
877 if (!isRelevantHelper()) {
878 return;
879 }
880
881 setFakeGatewayArpRule(event.subnet(), event.subject(),
882 true, null);
883 }
884
885 private void processSubnetRemoval(OpenstackNetworkEvent event) {
886 if (!isRelevantHelper()) {
887 return;
888 }
889
890 setFakeGatewayArpRule(event.subnet(), event.subject(),
891 false, null);
892 }
Jian Lidaa91152019-09-08 00:35:11 +0900893
894 private void processNetworkCreation(OpenstackNetworkEvent event) {
895 if (!isRelevantHelper()) {
896 return;
897 }
898
899 setVnetArpRule(event.subject(), true);
900 }
901
902 private void processNetworkRemoval(OpenstackNetworkEvent event) {
903 if (!isRelevantHelper()) {
904 return;
905 }
906
907 setVnetArpRule(event.subject(), false);
908 }
909
910 private void setVnetArpRule(Network network, boolean install) {
911 String netId = network.getId();
912 NetworkType netType = network.getNetworkType();
913
914 if (netType != NetworkType.LOCAL && netType != NetworkType.FLAT
915 && netType != NetworkType.VLAN) {
916 String segId = osNetworkService.segmentId(netId);
917 osNodeService.completeNodes(COMPUTE)
918 .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
919 node, segId, true, install));
920 }
921 if (netType == NetworkType.VLAN) {
922 String segId = osNetworkService.segmentId(netId);
923 osNodeService.completeNodes(COMPUTE)
924 .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
925 node, segId, false, install));
926 }
927 }
Jian Lieae12362018-04-10 18:48:32 +0900928 }
929
930 /**
931 * An internal openstack node listener which is used for listening openstack
932 * node activity. As long as a node is in complete state, we will install
933 * default ARP rule to handle ARP request.
934 */
935 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900936 @Override
937 public boolean isRelevant(OpenstackNodeEvent event) {
938 return event.subject().type() == COMPUTE;
939 }
940
Jian Li34220ea2018-11-14 01:30:24 +0900941 private boolean isRelevantHelper() {
942 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900943 }
944
945 @Override
946 public void event(OpenstackNodeEvent event) {
947 OpenstackNode osNode = event.subject();
948 switch (event.type()) {
949 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900950 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900951 break;
952 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900953 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900954 break;
Jian Lieae12362018-04-10 18:48:32 +0900955 default:
956 break;
957 }
958 }
959
Jian Li6a47fd02018-11-27 21:51:03 +0900960 private void processNodeCompletion(OpenstackNode osNode) {
961 if (!isRelevantHelper()) {
962 return;
963 }
964
965 setDefaultArpRule(osNode, true);
966 setAllArpRules(osNode, true);
967 }
968
969 private void processNodeIncompletion(OpenstackNode osNode) {
970 if (!isRelevantHelper()) {
971 return;
972 }
973
974 setDefaultArpRule(osNode, false);
975 setAllArpRules(osNode, false);
976 }
977
Jian Lif96685c2018-05-21 14:14:16 +0900978 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900979
980 if (getArpMode() == null) {
981 return;
982 }
983
Jian Li7f70bb72018-07-06 23:35:30 +0900984 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900985 case ARP_PROXY_MODE:
986 setDefaultArpRuleForProxyMode(osNode, install);
987 break;
988 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900989 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900990 break;
991 default:
992 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900993 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900994 break;
Jian Lieae12362018-04-10 18:48:32 +0900995 }
996 }
Jian Lif96685c2018-05-21 14:14:16 +0900997
Jian Li6a47fd02018-11-27 21:51:03 +0900998 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
999 boolean install) {
Jian Lidaa91152019-09-08 00:35:11 +09001000 setVnetArpRuleForBroadcastMode(osNode, install);
Jian Li6a47fd02018-11-27 21:51:03 +09001001
1002 // we do not add fake gateway ARP rules for FLAT network
1003 // ARP packets generated by FLAT typed VM should not be
1004 // delegated to switch to handle
1005 osNetworkService.subnets().stream().filter(subnet ->
1006 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +09001007 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +09001008 .forEach(subnet -> {
1009 String netId = subnet.getNetworkId();
1010 Network net = osNetworkService.network(netId);
1011 setFakeGatewayArpRule(subnet, net, install, osNode);
1012 });
1013 }
1014
Jian Lif96685c2018-05-21 14:14:16 +09001015 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
1016 TrafficSelector selector = DefaultTrafficSelector.builder()
1017 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1018 .build();
1019
1020 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1021 .punt()
1022 .build();
1023
1024 osFlowRuleService.setRule(
1025 appId,
1026 osNode.intgBridge(),
1027 selector,
1028 treatment,
1029 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +09001030 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001031 install
1032 );
1033 }
1034
Jian Lidaa91152019-09-08 00:35:11 +09001035 private void setVnetArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
1036 Set<String> netIds = osNetworkService.networks().stream()
1037 .map(IdEntity::getId).collect(Collectors.toSet());
Jian Lif96685c2018-05-21 14:14:16 +09001038
Jian Lidaa91152019-09-08 00:35:11 +09001039 netIds.stream()
1040 .filter(nid -> osNetworkService.networkType(nid) == VXLAN ||
1041 osNetworkService.networkType(nid) == GRE ||
1042 osNetworkService.networkType(nid) == GENEVE)
1043 .forEach(nid -> {
1044 String segId = osNetworkService.segmentId(nid);
1045 setBaseVnetArpRuleForBroadcastMode(osNode, segId, true, install);
1046 });
Jian Lif96685c2018-05-21 14:14:16 +09001047
Jian Lidaa91152019-09-08 00:35:11 +09001048 netIds.stream()
1049 .filter(nid -> osNetworkService.networkType(nid) == VLAN)
1050 .forEach(nid -> {
1051 String segId = osNetworkService.segmentId(nid);
1052 setBaseVnetArpRuleForBroadcastMode(osNode, segId, false, install);
1053 });
Jian Lif96685c2018-05-21 14:14:16 +09001054 }
Jian Li7f70bb72018-07-06 23:35:30 +09001055
Jian Lidaa91152019-09-08 00:35:11 +09001056
1057
Jian Li5b66ce02018-07-09 22:43:54 +09001058 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +09001059 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +09001060 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +09001061 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +09001062 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
1063 .forEach(p -> {
1064 setArpRequestRule(p, install);
1065 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +09001066 });
1067 }
1068 }
Jian Lieae12362018-04-10 18:48:32 +09001069 }
1070
1071 /**
1072 * An internal instance port listener which listens the port events generated
1073 * from VM. When ARP a host which located in a remote compute node, we specify
1074 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
1075 * host IP address. When ARP a host which located in a local compute node,
1076 * we specify only ARP OP mode as REQUEST.
1077 */
1078 private class InternalInstancePortListener implements InstancePortListener {
1079
1080 @Override
1081 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +09001082 return ARP_BROADCAST_MODE.equals(getArpMode());
1083 }
Jian Lieae12362018-04-10 18:48:32 +09001084
Jian Li34220ea2018-11-14 01:30:24 +09001085 private boolean isRelevantHelper(InstancePortEvent event) {
1086 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +09001087 }
1088
1089 @Override
1090 public void event(InstancePortEvent event) {
1091 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +09001092 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001093 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +09001094 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +09001095 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +09001096 break;
1097 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +09001098 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +09001099 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001100 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +09001101 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +09001102 break;
Jian Lieae12362018-04-10 18:48:32 +09001103 default:
1104 break;
1105 }
1106 }
Jian Li6a47fd02018-11-27 21:51:03 +09001107
1108 private void processInstanceMigrationStart(InstancePortEvent event) {
1109 if (!isRelevantHelper(event)) {
1110 return;
1111 }
1112
1113 setArpRequestRule(event.subject(), true);
1114 setArpReplyRule(event.subject(), true);
1115 }
1116
1117 private void processInstanceMigrationEnd(InstancePortEvent event) {
1118 if (!isRelevantHelper(event)) {
1119 return;
1120 }
1121
1122 InstancePort revisedInstPort = swapStaleLocation(event.subject());
1123 setArpRequestRule(revisedInstPort, false);
1124 }
1125
1126 private void processInstanceRemoval(InstancePortEvent event) {
1127 if (!isRelevantHelper(event)) {
1128 return;
1129 }
1130
1131 setArpRequestRule(event.subject(), false);
1132 setArpReplyRule(event.subject(), false);
1133 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001134 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001135}