blob: 3ac0c0dcc16dc4dad063de33ce1ea668a0007800 [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;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090036import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070037import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070039import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.packet.DefaultOutboundPacket;
41import org.onosproject.net.packet.PacketContext;
42import org.onosproject.net.packet.PacketProcessor;
43import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090044import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090045import org.onosproject.openstacknetworking.api.InstancePortEvent;
46import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090047import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090048import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090049import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
51import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
52import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090053import org.onosproject.openstacknode.api.OpenstackNode;
54import org.onosproject.openstacknode.api.OpenstackNodeEvent;
55import org.onosproject.openstacknode.api.OpenstackNodeListener;
56import org.onosproject.openstacknode.api.OpenstackNodeService;
57import org.openstack4j.model.network.Network;
Hyunsun Moon44aac662017-02-18 02:07:01 +090058import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070059import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060import org.osgi.service.component.annotations.Activate;
61import org.osgi.service.component.annotations.Component;
62import org.osgi.service.component.annotations.Deactivate;
63import org.osgi.service.component.annotations.Modified;
64import org.osgi.service.component.annotations.Reference;
65import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070066import org.slf4j.Logger;
67import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090068
Hyunsun Moonb974fca2016-06-30 21:20:39 -070069import java.nio.ByteBuffer;
70import java.util.Dictionary;
Jian Lieae12362018-04-10 18:48:32 +090071import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070072import java.util.Set;
Jian Li32b03622018-11-06 17:54:24 +090073import java.util.concurrent.ExecutorService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070074
75import static com.google.common.base.Preconditions.checkNotNull;
Jian Li32b03622018-11-06 17:54:24 +090076import static java.util.concurrent.Executors.newSingleThreadExecutor;
77import static org.onlab.util.Tools.groupedThreads;
Jian Lieae12362018-04-10 18:48:32 +090078import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
79import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li5c09e212018-10-24 18:23:58 +090080import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090082import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li5c09e212018-10-24 18:23:58 +090083import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_FLOOD_RULE;
Jian Lieae12362018-04-10 18:48:32 +090084import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
85import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
86import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
Jian Lic2403592018-07-18 12:56:45 +090087import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090088import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
89import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
90import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
91import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -070092import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
93import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
94import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
95import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +090096import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090097import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +090099import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
100import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700101
102/**
103 * Handles ARP packet from VMs.
104 */
Ray Milkey8e406512018-10-24 15:56:50 -0700105@Component(
106 immediate = true,
107 property = {
108 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900109 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700110 }
111)
Jian Li6a47fd02018-11-27 21:51:03 +0900112public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700113
114 private final Logger log = LoggerFactory.getLogger(getClass());
115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900117 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900120 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900123 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900126 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900129 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900132 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900135 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900138 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900141 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900142
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900144 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900147 protected OpenstackNodeService osNodeService;
148
Ray Milkey8e406512018-10-24 15:56:50 -0700149 /** Fake MAC address for virtual network subnet gateway. */
150 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700151
Ray Milkey8e406512018-10-24 15:56:50 -0700152 /** ARP processing mode, broadcast | proxy (default). */
153 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900154
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700155 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 private final InternalOpenstackNetworkListener osNetworkListener =
157 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900158 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
159 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
160
Jian Li32b03622018-11-06 17:54:24 +0900161 private final ExecutorService eventExecutor = newSingleThreadExecutor(
162 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
163
Hyunsun Moon44aac662017-02-18 02:07:01 +0900164
165 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900166 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700167
168 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800169 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900170 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
171 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900172 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900174 osNodeService.addListener(osNodeListener);
175 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700176 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900177
178 instancePortService.addListener(instancePortListener);
179
Hyunsun Moon44aac662017-02-18 02:07:01 +0900180 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700181 }
182
183 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800184 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700185 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900187 osNodeService.removeListener(osNodeListener);
188 instancePortService.removeListener(instancePortListener);
189 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900190 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900191 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192
193 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700194 }
195
196 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800197 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900198 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900199
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700200 log.info("Modified");
201 }
202
Jian Li7f70bb72018-07-06 23:35:30 +0900203 private String getArpMode() {
204 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
205 return getPropertyValue(properties, ARP_MODE);
206 }
207
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700208 /**
209 * Processes ARP request packets.
210 * It checks if the target IP is owned by a known host first and then ask to
211 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
212 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900213 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700214 * @param ethPacket ethernet packet
215 */
216 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900217
218 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900219 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900220 return;
221 }
222
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700223 ARP arpPacket = (ARP) ethPacket.getPayload();
224 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
225 return;
226 }
227
Hyunsun Moon44aac662017-02-18 02:07:01 +0900228 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
229 if (srcInstPort == null) {
230 log.trace("Failed to find source instance port(MAC:{})",
231 ethPacket.getSourceMAC());
232 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700233 }
234
Hyunsun Moon44aac662017-02-18 02:07:01 +0900235 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900236
Jian Liac30e272018-10-18 23:08:03 +0900237 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900238 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700239 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900240 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700241 return;
242 }
243
244 Ethernet ethReply = ARP.buildArpReply(
245 targetIp.getIp4Address(),
246 replyMac,
247 ethPacket);
248
249 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
250 .setOutput(context.inPacket().receivedFrom().port())
251 .build();
252
253 packetService.emit(new DefaultOutboundPacket(
254 context.inPacket().receivedFrom().deviceId(),
255 treatment,
256 ByteBuffer.wrap(ethReply.serialize())));
257 }
258
Jian Liac30e272018-10-18 23:08:03 +0900259 /**
260 * Denotes whether the given target IP is gateway IP.
261 *
262 * @param targetIp target IP address
263 * @return true if the given targetIP is gateway IP, false otherwise.
264 */
265 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900266 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900267 .filter(Objects::nonNull)
268 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900269 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
270 }
271
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700272 /**
273 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900274 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700275 *
276 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900277 * @param osNetId openstack network id of the source instance port
278 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700279 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700281 checkNotNull(targetIp);
282
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
284 if (instPort != null) {
285 log.trace("Found MAC from host service for {}", targetIp);
286 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700287 } else {
288 return MacAddress.NONE;
289 }
290 }
291
Jian Lieae12362018-04-10 18:48:32 +0900292 /**
Daniel Park613ac372018-06-28 14:30:11 +0900293 * Installs flow rules which convert ARP request packet into ARP reply
294 * by adding a fake gateway MAC address as Source Hardware Address.
295 *
296 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900297 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900298 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900299 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900300 */
Jian Li5b155bf2018-11-21 18:16:26 +0900301 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
302 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900303
Jian Li7f70bb72018-07-06 23:35:30 +0900304 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900305
SONA Project6bc5c4a2018-12-14 23:49:52 +0900306 Type netType = osNetworkService.networkType(network.getId());
307
Daniel Park613ac372018-06-28 14:30:11 +0900308 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900309 if (gateway == null) {
310 return;
311 }
Daniel Park613ac372018-06-28 14:30:11 +0900312
Daniel Park8a9220f2018-11-19 18:58:35 +0900313 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
314 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900315
SONA Project6bc5c4a2018-12-14 23:49:52 +0900316 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900317 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Daniel Park8a9220f2018-11-19 18:58:35 +0900318 tBuilder.popVlan();
SONA Project6bc5c4a2018-12-14 23:49:52 +0900319 } else if (netType == VXLAN || netType == GRE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900320 // do not remove fake gateway ARP rules, if there is another gateway
321 // which has the same subnet that to be removed
322 // this only occurs if we have duplicated subnets associated with
323 // different networks
324 if (!install) {
325 long numOfDupGws = osNetworkService.subnets().stream()
326 .filter(s -> !s.getId().equals(osSubnet.getId()))
327 .filter(s -> s.getGateway() != null)
328 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
329 .count();
330 if (numOfDupGws > 0) {
331 return;
332 }
333 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900334 }
335
336 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
337 .matchArpOp(ARP.OP_REQUEST)
338 .matchArpTpa(Ip4Address.valueOf(gateway));
339
340 tBuilder.setArpOp(ARP.OP_REPLY)
Daniel Park613ac372018-06-28 14:30:11 +0900341 .setArpSha(MacAddress.valueOf(gatewayMac))
342 .setArpSpa(Ip4Address.valueOf(gateway))
Daniel Park8a9220f2018-11-19 18:58:35 +0900343 .setOutput(PortNumber.IN_PORT);
Daniel Park613ac372018-06-28 14:30:11 +0900344
345 if (osNode == null) {
346 osNodeService.completeNodes(COMPUTE).forEach(n ->
347 osFlowRuleService.setRule(
348 appId,
349 n.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900350 sBuilder.build(),
351 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900352 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900353 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900354 install
355 )
356 );
357 } else {
358 osFlowRuleService.setRule(
359 appId,
360 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900361 sBuilder.build(),
362 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900363 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900364 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900365 install
366 );
367 }
368
369 }
370 }
371
372 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900373 * Installs flow rules to match ARP request packets.
374 *
375 * @param port instance port
376 * @param install installation flag
377 */
378 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900379 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900380
SONA Project6bc5c4a2018-12-14 23:49:52 +0900381 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900382 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900383 case GRE:
384 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900385 break;
386 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900387 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900388 break;
389 default:
390 break;
391 }
392 }
393
394 /**
395 * Installs flow rules to match ARP reply packets.
396 *
397 * @param port instance port
398 * @param install installation flag
399 */
400 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900401 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900402
SONA Project6bc5c4a2018-12-14 23:49:52 +0900403 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900404 case VXLAN:
405 setArpReplyRuleForVxlan(port, install);
406 break;
Jian Li2d68c192018-12-13 15:52:59 +0900407 case GRE:
408 setArpReplyRuleForGre(port, install);
409 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900410 case VLAN:
411 setArpReplyRuleForVlan(port, install);
412 break;
413 default:
414 break;
415 }
416 }
417
418 /**
419 * Installs flow rules to match ARP request packets only for VxLAN.
420 *
421 * @param port instance port
422 * @param install installation flag
423 */
Jian Li2d68c192018-12-13 15:52:59 +0900424 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900425
426 OpenstackNode localNode = osNodeService.node(port.deviceId());
427
Jian Li5c09e212018-10-24 18:23:58 +0900428 String segId = osNetworkService.segmentId(port.networkId());
429
Jian Li7f70bb72018-07-06 23:35:30 +0900430 TrafficSelector selector = DefaultTrafficSelector.builder()
431 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
432 .matchArpOp(ARP.OP_REQUEST)
433 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900434 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900435 .build();
436
Jian Li2d68c192018-12-13 15:52:59 +0900437 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900438 }
439
440 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900441 * Installs flow rules to match ARP request packets for VLAN.
442 *
443 * @param port instance port
444 * @param install installation flag
445 */
446 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
447 TrafficSelector selector = getArpRequestSelectorForVlan(port);
448
449 setLocalArpRequestTreatmentForVlan(selector, port, install);
450 setRemoteArpRequestTreatmentForVlan(selector, port, install);
451 }
452
453 /**
454 * Obtains the ARP request selector for VLAN.
455 *
456 * @param port instance port
457 * @return traffic selector
458 */
459 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
460 String segId = osNetworkService.segmentId(port.networkId());
461
462 return DefaultTrafficSelector.builder()
463 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
464 .matchArpOp(ARP.OP_REQUEST)
465 .matchArpTpa(port.ipAddress().getIp4Address())
466 .matchVlanId(VlanId.vlanId(segId))
467 .build();
468 }
469
470 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900471 * Installs flow rules to match ARP reply packets only for VxLAN.
472 *
473 * @param port instance port
474 * @param install installation flag
475 */
476 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
477
478 OpenstackNode localNode = osNodeService.node(port.deviceId());
479
Jian Li5b155bf2018-11-21 18:16:26 +0900480 TrafficSelector selector = getArpReplySelectorForVxlan(port);
481
482 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900483 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
484 }
485
486 /**
487 * Installs flow rules to match ARP reply packets only for GRE.
488 *
489 * @param port instance port
490 * @param install installation flag
491 */
492 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
493
494 OpenstackNode localNode = osNodeService.node(port.deviceId());
495
496 TrafficSelector selector = getArpReplySelectorForGre(port);
497
498 setLocalArpReplyTreatmentForGre(selector, port, install);
499 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900500 }
501
502 /**
503 * Installs flow rules to match ARP reply packets only for VLAN.
504 *
505 * @param port instance port
506 * @param install installation flag
507 */
508 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
509
Jian Li5b155bf2018-11-21 18:16:26 +0900510 TrafficSelector selector = getArpReplySelectorForVlan(port);
511
512 setLocalArpReplyTreatmentForVlan(selector, port, install);
513 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900514 }
515
516 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900517 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900518 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900519 }
520
521 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900522 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900523 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900524 }
525
526 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900527 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900528 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900529 }
530
531 // a helper method
532 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900533 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900534
535 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
536
SONA Project6bc5c4a2018-12-14 23:49:52 +0900537 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900538 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
539 sBuilder.matchVlanId(VlanId.vlanId(segId));
540 }
541
542 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900543 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
544 .matchArpOp(ARP.OP_REPLY)
545 .matchArpTpa(port.ipAddress().getIp4Address())
546 .matchArpTha(port.macAddress())
547 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900548 }
Jian Li7f70bb72018-07-06 23:35:30 +0900549
Jian Li5b155bf2018-11-21 18:16:26 +0900550 // a helper method
551 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
552 InstancePort port,
553 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900554 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900555 }
556
557 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900558 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
559 InstancePort port,
560 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900561 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900562 }
563
564 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900565 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
566 InstancePort port,
567 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900568 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900569 }
570
571 // a helper method
572 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
573 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900574 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900575 boolean install) {
576 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
577
SONA Project6bc5c4a2018-12-14 23:49:52 +0900578 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900579 tBuilder.popVlan();
580 }
581
582 tBuilder.setOutput(port.portNumber());
583
584 osFlowRuleService.setRule(
585 appId,
586 port.deviceId(),
587 selector,
588 tBuilder.build(),
589 PRIORITY_ARP_REPLY_RULE,
590 ARP_TABLE,
591 install
592 );
593 }
594
595 // a helper method
596 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
597 InstancePort port,
598 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900599 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900600 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900601 .setOutput(port.portNumber())
602 .build();
603
604 osFlowRuleService.setRule(
605 appId,
606 port.deviceId(),
607 selector,
608 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900609 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900610 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900611 install
612 );
Jian Li7f70bb72018-07-06 23:35:30 +0900613 }
614
615 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900616 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
617 InstancePort port,
618 OpenstackNode localNode,
619 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900620 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
621 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900622
623 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
624 osNetworkService, remoteNode);
625
Jian Li7f70bb72018-07-06 23:35:30 +0900626 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900627 .extension(buildExtension(
628 deviceService,
629 remoteNode.intgBridge(),
630 localNode.dataIp().getIp4Address()),
631 remoteNode.intgBridge())
632 .setOutput(portNum)
633 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900634
635 osFlowRuleService.setRule(
636 appId,
637 remoteNode.intgBridge(),
638 selector,
639 treatmentToRemote,
640 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900641 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900642 install
643 );
644 }
645 }
646 }
647
648 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900649 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
650 InstancePort port,
651 boolean install) {
652 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
653 }
654
655 // a helper method
656 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
657 InstancePort port,
658 boolean install) {
659 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
660 }
661
662 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900663 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
664 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900665 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900666 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900667
668 int priority;
669 if (arpOp == ARP.OP_REQUEST) {
670 priority = PRIORITY_ARP_REQUEST_RULE;
671 } else if (arpOp == ARP.OP_REPLY) {
672 priority = PRIORITY_ARP_REPLY_RULE;
673 } else {
674 // if ARP op does not match with any operation mode, we simply
675 // configure the ARP request rule priority
676 priority = PRIORITY_ARP_REQUEST_RULE;
677 }
678
Jian Li7f70bb72018-07-06 23:35:30 +0900679 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900680 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
681 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900682 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
683 .setOutput(remoteNode.vlanPortNum())
684 .build();
685
686 osFlowRuleService.setRule(
687 appId,
688 remoteNode.intgBridge(),
689 selector,
690 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900691 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900692 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900693 install);
694 }
695 }
696 }
697
698 /**
699 * Extracts properties from the component configuration context.
700 *
701 * @param context the component context
702 */
703 private void readComponentConfiguration(ComponentContext context) {
704 Dictionary<?, ?> properties = context.getProperties();
705
706 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700707 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900708 log.info("Configured. Gateway MAC is {}", gatewayMac);
709 }
710
711 /**
Jian Lieae12362018-04-10 18:48:32 +0900712 * An internal packet processor which processes ARP request, and results in
713 * packet-out ARP reply.
714 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700715 private class InternalPacketProcessor implements PacketProcessor {
716
717 @Override
718 public void process(PacketContext context) {
719 if (context.isHandled()) {
720 return;
721 }
722
723 Ethernet ethPacket = context.inPacket().parsed();
724 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
725 return;
726 }
Jian Li32b03622018-11-06 17:54:24 +0900727
728 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700729 }
730 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900731
Jian Lieae12362018-04-10 18:48:32 +0900732 /**
733 * An internal network listener which listens to openstack network event,
734 * manages the gateway collection and installs flow rule that handles
735 * ARP request in data plane.
736 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900737 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
738
739 @Override
740 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900741 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900742
Jian Lieae12362018-04-10 18:48:32 +0900743 if (network == null) {
744 log.warn("Network is not specified.");
745 return false;
746 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900747 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900748 }
Jian Li5b155bf2018-11-21 18:16:26 +0900749 }
Jian Lieae12362018-04-10 18:48:32 +0900750
Jian Li5b155bf2018-11-21 18:16:26 +0900751 private boolean isRelevantHelper() {
752 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900753 }
754
755 @Override
756 public void event(OpenstackNetworkEvent event) {
757 switch (event.type()) {
758 case OPENSTACK_SUBNET_CREATED:
759 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900760 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900761 break;
762 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900763 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900764 break;
765 case OPENSTACK_NETWORK_CREATED:
766 case OPENSTACK_NETWORK_UPDATED:
767 case OPENSTACK_NETWORK_REMOVED:
768 case OPENSTACK_PORT_CREATED:
769 case OPENSTACK_PORT_UPDATED:
770 case OPENSTACK_PORT_REMOVED:
771 default:
772 // do nothing for the other events
773 break;
774 }
775 }
Jian Li6a47fd02018-11-27 21:51:03 +0900776
777 private void processSubnetCreation(OpenstackNetworkEvent event) {
778 if (!isRelevantHelper()) {
779 return;
780 }
781
782 setFakeGatewayArpRule(event.subnet(), event.subject(),
783 true, null);
784 }
785
786 private void processSubnetRemoval(OpenstackNetworkEvent event) {
787 if (!isRelevantHelper()) {
788 return;
789 }
790
791 setFakeGatewayArpRule(event.subnet(), event.subject(),
792 false, null);
793 }
Jian Lieae12362018-04-10 18:48:32 +0900794 }
795
796 /**
797 * An internal openstack node listener which is used for listening openstack
798 * node activity. As long as a node is in complete state, we will install
799 * default ARP rule to handle ARP request.
800 */
801 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900802 @Override
803 public boolean isRelevant(OpenstackNodeEvent event) {
804 return event.subject().type() == COMPUTE;
805 }
806
Jian Li34220ea2018-11-14 01:30:24 +0900807 private boolean isRelevantHelper() {
808 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900809 }
810
811 @Override
812 public void event(OpenstackNodeEvent event) {
813 OpenstackNode osNode = event.subject();
814 switch (event.type()) {
815 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900816 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900817 break;
818 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900819 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900820 break;
Jian Lieae12362018-04-10 18:48:32 +0900821 default:
822 break;
823 }
824 }
825
Jian Li6a47fd02018-11-27 21:51:03 +0900826 private void processNodeCompletion(OpenstackNode osNode) {
827 if (!isRelevantHelper()) {
828 return;
829 }
830
831 setDefaultArpRule(osNode, true);
832 setAllArpRules(osNode, true);
833 }
834
835 private void processNodeIncompletion(OpenstackNode osNode) {
836 if (!isRelevantHelper()) {
837 return;
838 }
839
840 setDefaultArpRule(osNode, false);
841 setAllArpRules(osNode, false);
842 }
843
Jian Lif96685c2018-05-21 14:14:16 +0900844 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900845
846 if (getArpMode() == null) {
847 return;
848 }
849
Jian Li7f70bb72018-07-06 23:35:30 +0900850 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900851 case ARP_PROXY_MODE:
852 setDefaultArpRuleForProxyMode(osNode, install);
853 break;
854 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900855 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900856 break;
857 default:
858 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900859 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900860 break;
Jian Lieae12362018-04-10 18:48:32 +0900861 }
862 }
Jian Lif96685c2018-05-21 14:14:16 +0900863
Jian Li6a47fd02018-11-27 21:51:03 +0900864 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
865 boolean install) {
866 setDefaultArpRuleForBroadcastMode(osNode, install);
867
868 // we do not add fake gateway ARP rules for FLAT network
869 // ARP packets generated by FLAT typed VM should not be
870 // delegated to switch to handle
871 osNetworkService.subnets().stream().filter(subnet ->
872 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +0900873 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +0900874 .forEach(subnet -> {
875 String netId = subnet.getNetworkId();
876 Network net = osNetworkService.network(netId);
877 setFakeGatewayArpRule(subnet, net, install, osNode);
878 });
879 }
880
Jian Lif96685c2018-05-21 14:14:16 +0900881 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
882 TrafficSelector selector = DefaultTrafficSelector.builder()
883 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
884 .build();
885
886 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
887 .punt()
888 .build();
889
890 osFlowRuleService.setRule(
891 appId,
892 osNode.intgBridge(),
893 selector,
894 treatment,
895 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900896 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900897 install
898 );
899 }
900
901 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
902 TrafficSelector selector = DefaultTrafficSelector.builder()
903 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
904 .matchArpOp(ARP.OP_REQUEST)
905 .build();
906
907 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
908 .setOutput(PortNumber.FLOOD)
909 .build();
910
911 osFlowRuleService.setRule(
912 appId,
913 osNode.intgBridge(),
914 selector,
915 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900916 PRIORITY_ARP_FLOOD_RULE,
917 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900918 install
919 );
920 }
Jian Li7f70bb72018-07-06 23:35:30 +0900921
Jian Li5b66ce02018-07-09 22:43:54 +0900922 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900923 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900924 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900925 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900926 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
927 .forEach(p -> {
928 setArpRequestRule(p, install);
929 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900930 });
931 }
932 }
Jian Lieae12362018-04-10 18:48:32 +0900933 }
934
935 /**
936 * An internal instance port listener which listens the port events generated
937 * from VM. When ARP a host which located in a remote compute node, we specify
938 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
939 * host IP address. When ARP a host which located in a local compute node,
940 * we specify only ARP OP mode as REQUEST.
941 */
942 private class InternalInstancePortListener implements InstancePortListener {
943
944 @Override
945 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900946 return ARP_BROADCAST_MODE.equals(getArpMode());
947 }
Jian Lieae12362018-04-10 18:48:32 +0900948
Jian Li34220ea2018-11-14 01:30:24 +0900949 private boolean isRelevantHelper(InstancePortEvent event) {
950 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +0900951 }
952
953 @Override
954 public void event(InstancePortEvent event) {
955 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +0900956 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900957 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +0900958 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +0900959 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +0900960 break;
961 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +0900962 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +0900963 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900964 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +0900965 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900966 break;
Jian Lieae12362018-04-10 18:48:32 +0900967 default:
968 break;
969 }
970 }
Jian Li6a47fd02018-11-27 21:51:03 +0900971
972 private void processInstanceMigrationStart(InstancePortEvent event) {
973 if (!isRelevantHelper(event)) {
974 return;
975 }
976
977 setArpRequestRule(event.subject(), true);
978 setArpReplyRule(event.subject(), true);
979 }
980
981 private void processInstanceMigrationEnd(InstancePortEvent event) {
982 if (!isRelevantHelper(event)) {
983 return;
984 }
985
986 InstancePort revisedInstPort = swapStaleLocation(event.subject());
987 setArpRequestRule(revisedInstPort, false);
988 }
989
990 private void processInstanceRemoval(InstancePortEvent event) {
991 if (!isRelevantHelper(event)) {
992 return;
993 }
994
995 setArpRequestRule(event.subject(), false);
996 setArpReplyRule(event.subject(), false);
997 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900998 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700999}