blob: 0e09b03e59185999f92bd9c5c626a6c2a9516f20 [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;
Jian Li621f73c2018-12-15 01:49:22 +090089import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090090import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
91import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
92import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -070093import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
94import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
95import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
96import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +090097import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +0900100import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
101import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700102
103/**
104 * Handles ARP packet from VMs.
105 */
Ray Milkey8e406512018-10-24 15:56:50 -0700106@Component(
107 immediate = true,
108 property = {
109 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900110 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700111 }
112)
Jian Li6a47fd02018-11-27 21:51:03 +0900113public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700114
115 private final Logger log = LoggerFactory.getLogger(getClass());
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900118 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900121 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900124 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900127 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900130 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900133 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900136 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900139 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900142 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900145 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700146
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700147 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900148 protected OpenstackNodeService osNodeService;
149
Ray Milkey8e406512018-10-24 15:56:50 -0700150 /** Fake MAC address for virtual network subnet gateway. */
151 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700152
Ray Milkey8e406512018-10-24 15:56:50 -0700153 /** ARP processing mode, broadcast | proxy (default). */
154 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900155
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700156 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 private final InternalOpenstackNetworkListener osNetworkListener =
158 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900159 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
160 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
161
Jian Li32b03622018-11-06 17:54:24 +0900162 private final ExecutorService eventExecutor = newSingleThreadExecutor(
163 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
164
Hyunsun Moon44aac662017-02-18 02:07:01 +0900165
166 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900167 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700168
169 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800170 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900171 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
172 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900173 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900175 osNodeService.addListener(osNodeListener);
176 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700177 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900178
179 instancePortService.addListener(instancePortListener);
180
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700182 }
183
184 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800185 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700186 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900188 osNodeService.removeListener(osNodeListener);
189 instancePortService.removeListener(instancePortListener);
190 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900192 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193
194 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700195 }
196
197 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800198 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900199 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900200
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700201 log.info("Modified");
202 }
203
Jian Li7f70bb72018-07-06 23:35:30 +0900204 private String getArpMode() {
205 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
206 return getPropertyValue(properties, ARP_MODE);
207 }
208
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700209 /**
210 * Processes ARP request packets.
211 * It checks if the target IP is owned by a known host first and then ask to
212 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
213 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700215 * @param ethPacket ethernet packet
216 */
217 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900218
219 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900220 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900221 return;
222 }
223
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700224 ARP arpPacket = (ARP) ethPacket.getPayload();
225 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
226 return;
227 }
228
Hyunsun Moon44aac662017-02-18 02:07:01 +0900229 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
230 if (srcInstPort == null) {
231 log.trace("Failed to find source instance port(MAC:{})",
232 ethPacket.getSourceMAC());
233 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700234 }
235
Hyunsun Moon44aac662017-02-18 02:07:01 +0900236 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900237
Jian Liac30e272018-10-18 23:08:03 +0900238 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900239 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700240 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900241 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700242 return;
243 }
244
245 Ethernet ethReply = ARP.buildArpReply(
246 targetIp.getIp4Address(),
247 replyMac,
248 ethPacket);
249
250 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
251 .setOutput(context.inPacket().receivedFrom().port())
252 .build();
253
254 packetService.emit(new DefaultOutboundPacket(
255 context.inPacket().receivedFrom().deviceId(),
256 treatment,
257 ByteBuffer.wrap(ethReply.serialize())));
258 }
259
Jian Liac30e272018-10-18 23:08:03 +0900260 /**
261 * Denotes whether the given target IP is gateway IP.
262 *
263 * @param targetIp target IP address
264 * @return true if the given targetIP is gateway IP, false otherwise.
265 */
266 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900267 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900268 .filter(Objects::nonNull)
269 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900270 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
271 }
272
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700273 /**
274 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900275 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700276 *
277 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900278 * @param osNetId openstack network id of the source instance port
279 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700280 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700282 checkNotNull(targetIp);
283
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
285 if (instPort != null) {
286 log.trace("Found MAC from host service for {}", targetIp);
287 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700288 } else {
289 return MacAddress.NONE;
290 }
291 }
292
Jian Lieae12362018-04-10 18:48:32 +0900293 /**
Daniel Park613ac372018-06-28 14:30:11 +0900294 * Installs flow rules which convert ARP request packet into ARP reply
295 * by adding a fake gateway MAC address as Source Hardware Address.
296 *
297 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900298 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900299 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900300 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900301 */
Jian Li5b155bf2018-11-21 18:16:26 +0900302 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
303 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900304
Jian Li7f70bb72018-07-06 23:35:30 +0900305 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900306
SONA Project6bc5c4a2018-12-14 23:49:52 +0900307 Type netType = osNetworkService.networkType(network.getId());
308
Daniel Park613ac372018-06-28 14:30:11 +0900309 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900310 if (gateway == null) {
311 return;
312 }
Daniel Park613ac372018-06-28 14:30:11 +0900313
Daniel Park8a9220f2018-11-19 18:58:35 +0900314 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
315 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900316
SONA Project6bc5c4a2018-12-14 23:49:52 +0900317 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900318 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Daniel Park8a9220f2018-11-19 18:58:35 +0900319 tBuilder.popVlan();
Jian Li621f73c2018-12-15 01:49:22 +0900320 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900321 // do not remove fake gateway ARP rules, if there is another gateway
322 // which has the same subnet that to be removed
323 // this only occurs if we have duplicated subnets associated with
324 // different networks
325 if (!install) {
326 long numOfDupGws = osNetworkService.subnets().stream()
327 .filter(s -> !s.getId().equals(osSubnet.getId()))
328 .filter(s -> s.getGateway() != null)
329 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
330 .count();
331 if (numOfDupGws > 0) {
332 return;
333 }
334 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900335 }
336
337 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
338 .matchArpOp(ARP.OP_REQUEST)
339 .matchArpTpa(Ip4Address.valueOf(gateway));
340
341 tBuilder.setArpOp(ARP.OP_REPLY)
Daniel Park613ac372018-06-28 14:30:11 +0900342 .setArpSha(MacAddress.valueOf(gatewayMac))
343 .setArpSpa(Ip4Address.valueOf(gateway))
Daniel Park8a9220f2018-11-19 18:58:35 +0900344 .setOutput(PortNumber.IN_PORT);
Daniel Park613ac372018-06-28 14:30:11 +0900345
346 if (osNode == null) {
347 osNodeService.completeNodes(COMPUTE).forEach(n ->
348 osFlowRuleService.setRule(
349 appId,
350 n.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900351 sBuilder.build(),
352 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900353 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900354 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900355 install
356 )
357 );
358 } else {
359 osFlowRuleService.setRule(
360 appId,
361 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900362 sBuilder.build(),
363 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900364 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900365 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900366 install
367 );
368 }
369
370 }
371 }
372
373 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900374 * Installs flow rules to match ARP request packets.
375 *
376 * @param port instance port
377 * @param install installation flag
378 */
379 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900380 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900381
SONA Project6bc5c4a2018-12-14 23:49:52 +0900382 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900383 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900384 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900385 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900386 setRemoteArpRequestRuleForTunnel(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900387 break;
388 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900389 setArpRequestRuleForVlan(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900390 break;
391 default:
392 break;
393 }
394 }
395
396 /**
397 * Installs flow rules to match ARP reply packets.
398 *
399 * @param port instance port
400 * @param install installation flag
401 */
402 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900403 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900404
SONA Project6bc5c4a2018-12-14 23:49:52 +0900405 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900406 case VXLAN:
407 setArpReplyRuleForVxlan(port, install);
408 break;
Jian Li2d68c192018-12-13 15:52:59 +0900409 case GRE:
410 setArpReplyRuleForGre(port, install);
411 break;
Jian Li621f73c2018-12-15 01:49:22 +0900412 case GENEVE:
413 setArpReplyRuleForGeneve(port, install);
414 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900415 case VLAN:
416 setArpReplyRuleForVlan(port, install);
417 break;
418 default:
419 break;
420 }
421 }
422
423 /**
424 * Installs flow rules to match ARP request packets only for VxLAN.
425 *
426 * @param port instance port
427 * @param install installation flag
428 */
Jian Li2d68c192018-12-13 15:52:59 +0900429 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900430
431 OpenstackNode localNode = osNodeService.node(port.deviceId());
432
Jian Li5c09e212018-10-24 18:23:58 +0900433 String segId = osNetworkService.segmentId(port.networkId());
434
Jian Li7f70bb72018-07-06 23:35:30 +0900435 TrafficSelector selector = DefaultTrafficSelector.builder()
436 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
437 .matchArpOp(ARP.OP_REQUEST)
438 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900439 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900440 .build();
441
Jian Li2d68c192018-12-13 15:52:59 +0900442 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900443 }
444
445 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900446 * Installs flow rules to match ARP request packets for VLAN.
447 *
448 * @param port instance port
449 * @param install installation flag
450 */
451 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
452 TrafficSelector selector = getArpRequestSelectorForVlan(port);
453
454 setLocalArpRequestTreatmentForVlan(selector, port, install);
455 setRemoteArpRequestTreatmentForVlan(selector, port, install);
456 }
457
458 /**
459 * Obtains the ARP request selector for VLAN.
460 *
461 * @param port instance port
462 * @return traffic selector
463 */
464 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
465 String segId = osNetworkService.segmentId(port.networkId());
466
467 return DefaultTrafficSelector.builder()
468 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
469 .matchArpOp(ARP.OP_REQUEST)
470 .matchArpTpa(port.ipAddress().getIp4Address())
471 .matchVlanId(VlanId.vlanId(segId))
472 .build();
473 }
474
475 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900476 * Installs flow rules to match ARP reply packets only for VxLAN.
477 *
478 * @param port instance port
479 * @param install installation flag
480 */
481 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
482
483 OpenstackNode localNode = osNodeService.node(port.deviceId());
484
Jian Li5b155bf2018-11-21 18:16:26 +0900485 TrafficSelector selector = getArpReplySelectorForVxlan(port);
486
487 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900488 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
489 }
490
491 /**
492 * Installs flow rules to match ARP reply packets only for GRE.
493 *
494 * @param port instance port
495 * @param install installation flag
496 */
497 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
498
499 OpenstackNode localNode = osNodeService.node(port.deviceId());
500
501 TrafficSelector selector = getArpReplySelectorForGre(port);
502
503 setLocalArpReplyTreatmentForGre(selector, port, install);
504 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900505 }
506
507 /**
Jian Li621f73c2018-12-15 01:49:22 +0900508 * Installs flow rules to match ARP reply packets only for GENEVE.
509 *
510 * @param port instance port
511 * @param install installation flag
512 */
513 private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
514
515 OpenstackNode localNode = osNodeService.node(port.deviceId());
516
517 TrafficSelector selector = getArpReplySelectorForGeneve(port);
518
519 setLocalArpReplyTreatmentForGeneve(selector, port, install);
520 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
521 }
522
523 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900524 * Installs flow rules to match ARP reply packets only for VLAN.
525 *
526 * @param port instance port
527 * @param install installation flag
528 */
529 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
530
Jian Li5b155bf2018-11-21 18:16:26 +0900531 TrafficSelector selector = getArpReplySelectorForVlan(port);
532
533 setLocalArpReplyTreatmentForVlan(selector, port, install);
534 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900535 }
536
537 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900538 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900539 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900540 }
541
542 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900543 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900544 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900545 }
546
547 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900548 private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
549 return getArpReplySelectorForVnet(port, GENEVE);
550 }
551
552 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900553 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900554 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900555 }
556
557 // a helper method
558 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900559 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900560
561 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
562
SONA Project6bc5c4a2018-12-14 23:49:52 +0900563 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900564 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
565 sBuilder.matchVlanId(VlanId.vlanId(segId));
566 }
567
568 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900569 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
570 .matchArpOp(ARP.OP_REPLY)
571 .matchArpTpa(port.ipAddress().getIp4Address())
572 .matchArpTha(port.macAddress())
573 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900574 }
Jian Li7f70bb72018-07-06 23:35:30 +0900575
Jian Li5b155bf2018-11-21 18:16:26 +0900576 // a helper method
577 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
578 InstancePort port,
579 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900580 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900581 }
582
583 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900584 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
585 InstancePort port,
586 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900587 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900588 }
589
590 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900591 private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
592 InstancePort port,
593 boolean install) {
594 setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
595 }
596
597 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900598 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
599 InstancePort port,
600 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900601 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900602 }
603
604 // a helper method
605 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
606 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900607 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900608 boolean install) {
609 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
610
SONA Project6bc5c4a2018-12-14 23:49:52 +0900611 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900612 tBuilder.popVlan();
613 }
614
615 tBuilder.setOutput(port.portNumber());
616
617 osFlowRuleService.setRule(
618 appId,
619 port.deviceId(),
620 selector,
621 tBuilder.build(),
622 PRIORITY_ARP_REPLY_RULE,
623 ARP_TABLE,
624 install
625 );
626 }
627
628 // a helper method
629 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
630 InstancePort port,
631 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900632 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900633 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900634 .setOutput(port.portNumber())
635 .build();
636
637 osFlowRuleService.setRule(
638 appId,
639 port.deviceId(),
640 selector,
641 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900642 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900643 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900644 install
645 );
Jian Li7f70bb72018-07-06 23:35:30 +0900646 }
647
648 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900649 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
650 InstancePort port,
651 OpenstackNode localNode,
652 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900653 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
654 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900655
656 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
657 osNetworkService, remoteNode);
658
Jian Li7f70bb72018-07-06 23:35:30 +0900659 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900660 .extension(buildExtension(
661 deviceService,
662 remoteNode.intgBridge(),
663 localNode.dataIp().getIp4Address()),
664 remoteNode.intgBridge())
665 .setOutput(portNum)
666 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900667
668 osFlowRuleService.setRule(
669 appId,
670 remoteNode.intgBridge(),
671 selector,
672 treatmentToRemote,
673 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900674 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900675 install
676 );
677 }
678 }
679 }
680
681 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900682 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
683 InstancePort port,
684 boolean install) {
685 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
686 }
687
688 // a helper method
689 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
690 InstancePort port,
691 boolean install) {
692 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
693 }
694
695 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900696 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
697 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900698 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900699 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900700
701 int priority;
702 if (arpOp == ARP.OP_REQUEST) {
703 priority = PRIORITY_ARP_REQUEST_RULE;
704 } else if (arpOp == ARP.OP_REPLY) {
705 priority = PRIORITY_ARP_REPLY_RULE;
706 } else {
707 // if ARP op does not match with any operation mode, we simply
708 // configure the ARP request rule priority
709 priority = PRIORITY_ARP_REQUEST_RULE;
710 }
711
Jian Li7f70bb72018-07-06 23:35:30 +0900712 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900713 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
714 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900715 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
716 .setOutput(remoteNode.vlanPortNum())
717 .build();
718
719 osFlowRuleService.setRule(
720 appId,
721 remoteNode.intgBridge(),
722 selector,
723 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900724 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900725 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900726 install);
727 }
728 }
729 }
730
731 /**
732 * Extracts properties from the component configuration context.
733 *
734 * @param context the component context
735 */
736 private void readComponentConfiguration(ComponentContext context) {
737 Dictionary<?, ?> properties = context.getProperties();
738
739 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700740 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900741 log.info("Configured. Gateway MAC is {}", gatewayMac);
742 }
743
744 /**
Jian Lieae12362018-04-10 18:48:32 +0900745 * An internal packet processor which processes ARP request, and results in
746 * packet-out ARP reply.
747 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700748 private class InternalPacketProcessor implements PacketProcessor {
749
750 @Override
751 public void process(PacketContext context) {
752 if (context.isHandled()) {
753 return;
754 }
755
756 Ethernet ethPacket = context.inPacket().parsed();
757 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
758 return;
759 }
Jian Li32b03622018-11-06 17:54:24 +0900760
761 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700762 }
763 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900764
Jian Lieae12362018-04-10 18:48:32 +0900765 /**
766 * An internal network listener which listens to openstack network event,
767 * manages the gateway collection and installs flow rule that handles
768 * ARP request in data plane.
769 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900770 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
771
772 @Override
773 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900774 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900775
Jian Lieae12362018-04-10 18:48:32 +0900776 if (network == null) {
777 log.warn("Network is not specified.");
778 return false;
779 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900780 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900781 }
Jian Li5b155bf2018-11-21 18:16:26 +0900782 }
Jian Lieae12362018-04-10 18:48:32 +0900783
Jian Li5b155bf2018-11-21 18:16:26 +0900784 private boolean isRelevantHelper() {
785 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900786 }
787
788 @Override
789 public void event(OpenstackNetworkEvent event) {
790 switch (event.type()) {
791 case OPENSTACK_SUBNET_CREATED:
792 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900793 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900794 break;
795 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900796 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900797 break;
798 case OPENSTACK_NETWORK_CREATED:
799 case OPENSTACK_NETWORK_UPDATED:
800 case OPENSTACK_NETWORK_REMOVED:
801 case OPENSTACK_PORT_CREATED:
802 case OPENSTACK_PORT_UPDATED:
803 case OPENSTACK_PORT_REMOVED:
804 default:
805 // do nothing for the other events
806 break;
807 }
808 }
Jian Li6a47fd02018-11-27 21:51:03 +0900809
810 private void processSubnetCreation(OpenstackNetworkEvent event) {
811 if (!isRelevantHelper()) {
812 return;
813 }
814
815 setFakeGatewayArpRule(event.subnet(), event.subject(),
816 true, null);
817 }
818
819 private void processSubnetRemoval(OpenstackNetworkEvent event) {
820 if (!isRelevantHelper()) {
821 return;
822 }
823
824 setFakeGatewayArpRule(event.subnet(), event.subject(),
825 false, null);
826 }
Jian Lieae12362018-04-10 18:48:32 +0900827 }
828
829 /**
830 * An internal openstack node listener which is used for listening openstack
831 * node activity. As long as a node is in complete state, we will install
832 * default ARP rule to handle ARP request.
833 */
834 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900835 @Override
836 public boolean isRelevant(OpenstackNodeEvent event) {
837 return event.subject().type() == COMPUTE;
838 }
839
Jian Li34220ea2018-11-14 01:30:24 +0900840 private boolean isRelevantHelper() {
841 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900842 }
843
844 @Override
845 public void event(OpenstackNodeEvent event) {
846 OpenstackNode osNode = event.subject();
847 switch (event.type()) {
848 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900849 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900850 break;
851 case OPENSTACK_NODE_INCOMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900852 eventExecutor.execute(() -> processNodeIncompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900853 break;
Jian Lieae12362018-04-10 18:48:32 +0900854 default:
855 break;
856 }
857 }
858
Jian Li6a47fd02018-11-27 21:51:03 +0900859 private void processNodeCompletion(OpenstackNode osNode) {
860 if (!isRelevantHelper()) {
861 return;
862 }
863
864 setDefaultArpRule(osNode, true);
865 setAllArpRules(osNode, true);
866 }
867
868 private void processNodeIncompletion(OpenstackNode osNode) {
869 if (!isRelevantHelper()) {
870 return;
871 }
872
873 setDefaultArpRule(osNode, false);
874 setAllArpRules(osNode, false);
875 }
876
Jian Lif96685c2018-05-21 14:14:16 +0900877 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900878
879 if (getArpMode() == null) {
880 return;
881 }
882
Jian Li7f70bb72018-07-06 23:35:30 +0900883 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900884 case ARP_PROXY_MODE:
885 setDefaultArpRuleForProxyMode(osNode, install);
886 break;
887 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +0900888 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +0900889 break;
890 default:
891 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900892 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900893 break;
Jian Lieae12362018-04-10 18:48:32 +0900894 }
895 }
Jian Lif96685c2018-05-21 14:14:16 +0900896
Jian Li6a47fd02018-11-27 21:51:03 +0900897 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
898 boolean install) {
899 setDefaultArpRuleForBroadcastMode(osNode, install);
900
901 // we do not add fake gateway ARP rules for FLAT network
902 // ARP packets generated by FLAT typed VM should not be
903 // delegated to switch to handle
904 osNetworkService.subnets().stream().filter(subnet ->
905 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +0900906 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +0900907 .forEach(subnet -> {
908 String netId = subnet.getNetworkId();
909 Network net = osNetworkService.network(netId);
910 setFakeGatewayArpRule(subnet, net, install, osNode);
911 });
912 }
913
Jian Lif96685c2018-05-21 14:14:16 +0900914 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
915 TrafficSelector selector = DefaultTrafficSelector.builder()
916 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
917 .build();
918
919 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
920 .punt()
921 .build();
922
923 osFlowRuleService.setRule(
924 appId,
925 osNode.intgBridge(),
926 selector,
927 treatment,
928 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900929 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900930 install
931 );
932 }
933
934 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
935 TrafficSelector selector = DefaultTrafficSelector.builder()
936 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
937 .matchArpOp(ARP.OP_REQUEST)
938 .build();
939
940 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
941 .setOutput(PortNumber.FLOOD)
942 .build();
943
944 osFlowRuleService.setRule(
945 appId,
946 osNode.intgBridge(),
947 selector,
948 treatment,
Jian Li5c09e212018-10-24 18:23:58 +0900949 PRIORITY_ARP_FLOOD_RULE,
950 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900951 install
952 );
953 }
Jian Li7f70bb72018-07-06 23:35:30 +0900954
Jian Li5b66ce02018-07-09 22:43:54 +0900955 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900956 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900957 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900958 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900959 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
960 .forEach(p -> {
961 setArpRequestRule(p, install);
962 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900963 });
964 }
965 }
Jian Lieae12362018-04-10 18:48:32 +0900966 }
967
968 /**
969 * An internal instance port listener which listens the port events generated
970 * from VM. When ARP a host which located in a remote compute node, we specify
971 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
972 * host IP address. When ARP a host which located in a local compute node,
973 * we specify only ARP OP mode as REQUEST.
974 */
975 private class InternalInstancePortListener implements InstancePortListener {
976
977 @Override
978 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +0900979 return ARP_BROADCAST_MODE.equals(getArpMode());
980 }
Jian Lieae12362018-04-10 18:48:32 +0900981
Jian Li34220ea2018-11-14 01:30:24 +0900982 private boolean isRelevantHelper(InstancePortEvent event) {
983 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +0900984 }
985
986 @Override
987 public void event(InstancePortEvent event) {
988 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +0900989 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900990 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +0900991 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +0900992 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +0900993 break;
994 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +0900995 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +0900996 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900997 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +0900998 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +0900999 break;
Jian Lieae12362018-04-10 18:48:32 +09001000 default:
1001 break;
1002 }
1003 }
Jian Li6a47fd02018-11-27 21:51:03 +09001004
1005 private void processInstanceMigrationStart(InstancePortEvent event) {
1006 if (!isRelevantHelper(event)) {
1007 return;
1008 }
1009
1010 setArpRequestRule(event.subject(), true);
1011 setArpReplyRule(event.subject(), true);
1012 }
1013
1014 private void processInstanceMigrationEnd(InstancePortEvent event) {
1015 if (!isRelevantHelper(event)) {
1016 return;
1017 }
1018
1019 InstancePort revisedInstPort = swapStaleLocation(event.subject());
1020 setArpRequestRule(revisedInstPort, false);
1021 }
1022
1023 private void processInstanceRemoval(InstancePortEvent event) {
1024 if (!isRelevantHelper(event)) {
1025 return;
1026 }
1027
1028 setArpRequestRule(event.subject(), false);
1029 setArpReplyRule(event.subject(), false);
1030 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001031 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001032}