blob: c3e0329d33d9e2e5950ae25355ac9552fbe02e97 [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
Jian Lid5727622019-09-11 11:15:16 +090018import com.google.common.collect.Lists;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070019import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090020import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070021import org.onlab.packet.Ethernet;
22import org.onlab.packet.Ip4Address;
23import org.onlab.packet.IpAddress;
24import org.onlab.packet.MacAddress;
Daniel Park8a9220f2018-11-19 18:58:35 +090025import org.onlab.packet.VlanId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070026import org.onlab.util.Tools;
Hyunsun Moon44aac662017-02-18 02:07:01 +090027import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090028import org.onosproject.cfg.ConfigProperty;
Jian Lieae12362018-04-10 18:48:32 +090029import org.onosproject.cluster.ClusterService;
30import org.onosproject.cluster.LeadershipService;
31import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090032import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreService;
Jian Lid5727622019-09-11 11:15:16 +090034import org.onosproject.core.GroupId;
Jian Lieae12362018-04-10 18:48:32 +090035import org.onosproject.mastership.MastershipService;
Jian Li4910c4b2019-04-01 18:06:40 +090036import org.onosproject.net.Device;
Jian Lieae12362018-04-10 18:48:32 +090037import org.onosproject.net.PortNumber;
38import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070040import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090041import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070042import org.onosproject.net.flow.TrafficTreatment;
Jian Lid5727622019-09-11 11:15:16 +090043import org.onosproject.net.group.GroupBucket;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070044import org.onosproject.net.packet.DefaultOutboundPacket;
45import org.onosproject.net.packet.PacketContext;
46import org.onosproject.net.packet.PacketProcessor;
47import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090049import org.onosproject.openstacknetworking.api.InstancePortEvent;
50import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090051import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090052import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Jian Lid5727622019-09-11 11:15:16 +090053import org.onosproject.openstacknetworking.api.OpenstackGroupRuleService;
SONA Project6bc5c4a2018-12-14 23:49:52 +090054import org.onosproject.openstacknetworking.api.OpenstackNetwork.Type;
Hyunsun Moon44aac662017-02-18 02:07:01 +090055import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
56import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
57import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090058import org.onosproject.openstacknode.api.OpenstackNode;
59import org.onosproject.openstacknode.api.OpenstackNodeEvent;
60import org.onosproject.openstacknode.api.OpenstackNodeListener;
61import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Lib3dc1ca2019-09-08 00:35:11 +090062import org.openstack4j.model.common.IdEntity;
Jian Lieae12362018-04-10 18:48:32 +090063import org.openstack4j.model.network.Network;
Jian Lib3dc1ca2019-09-08 00:35:11 +090064import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090065import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070066import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067import org.osgi.service.component.annotations.Activate;
68import org.osgi.service.component.annotations.Component;
69import org.osgi.service.component.annotations.Deactivate;
70import org.osgi.service.component.annotations.Modified;
71import org.osgi.service.component.annotations.Reference;
72import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070073import org.slf4j.Logger;
74import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090075
Hyunsun Moonb974fca2016-06-30 21:20:39 -070076import java.nio.ByteBuffer;
77import java.util.Dictionary;
Jian Lid5727622019-09-11 11:15:16 +090078import java.util.List;
Jian Lieae12362018-04-10 18:48:32 +090079import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070080import java.util.Set;
Jian Li32b03622018-11-06 17:54:24 +090081import java.util.concurrent.ExecutorService;
Jian Lib3dc1ca2019-09-08 00:35:11 +090082import java.util.stream.Collectors;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070083
84import static com.google.common.base.Preconditions.checkNotNull;
Jian Li32b03622018-11-06 17:54:24 +090085import static java.util.concurrent.Executors.newSingleThreadExecutor;
86import static org.onlab.util.Tools.groupedThreads;
Jian Lid5727622019-09-11 11:15:16 +090087import static org.onosproject.net.group.GroupDescription.Type.ALL;
Jian Lieae12362018-04-10 18:48:32 +090088import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
89import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
Jian Li5c09e212018-10-24 18:23:58 +090090import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090091import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090092import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
93import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Lid5727622019-09-11 11:15:16 +090094import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GROUP_RULE;
Jian Lieae12362018-04-10 18:48:32 +090095import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
96import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
Jian Lic2403592018-07-18 12:56:45 +090097import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +090098import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
Jian Li621f73c2018-12-15 01:49:22 +090099import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
SONA Project6bc5c4a2018-12-14 23:49:52 +0900100import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
101import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
102import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
Ray Milkey8e406512018-10-24 15:56:50 -0700103import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE;
104import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.ARP_MODE_DEFAULT;
105import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC;
106import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900107import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +0900108import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Li2d68c192018-12-13 15:52:59 +0900109import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
Jian Lieae12362018-04-10 18:48:32 +0900110import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
Jian Lid5727622019-09-11 11:15:16 +0900111import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildGroupBucket;
Jian Li4910c4b2019-04-01 18:06:40 +0900112import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpShaToThaExtension;
113import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveArpSpaToTpaExtension;
114import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildMoveEthSrcToDstExtension;
Jian Lieae12362018-04-10 18:48:32 +0900115import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700116
117/**
118 * Handles ARP packet from VMs.
119 */
Ray Milkey8e406512018-10-24 15:56:50 -0700120@Component(
121 immediate = true,
122 property = {
123 GATEWAY_MAC + "=" + GATEWAY_MAC_DEFAULT,
Jian Li6a47fd02018-11-27 21:51:03 +0900124 ARP_MODE + "=" + ARP_MODE_DEFAULT
Ray Milkey8e406512018-10-24 15:56:50 -0700125 }
126)
Jian Li6a47fd02018-11-27 21:51:03 +0900127public class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700128
129 private final Logger log = LoggerFactory.getLogger(getClass());
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900132 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900135 protected PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900138 protected OpenstackFlowRuleService osFlowRuleService;
Jian Lieae12362018-04-10 18:48:32 +0900139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lid5727622019-09-11 11:15:16 +0900141 protected OpenstackGroupRuleService osGroupRuleService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900144 protected ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900145
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700146 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900147 protected ClusterService clusterService;
Jian Lieae12362018-04-10 18:48:32 +0900148
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700149 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900150 protected LeadershipService leadershipService;
Jian Lieae12362018-04-10 18:48:32 +0900151
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700152 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900153 protected DeviceService deviceService;
Jian Lieae12362018-04-10 18:48:32 +0900154
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700155 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900156 protected MastershipService mastershipService;
Jian Lieae12362018-04-10 18:48:32 +0900157
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700158 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900159 protected InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700161 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Li6a47fd02018-11-27 21:51:03 +0900162 protected OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700163
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700164 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900165 protected OpenstackNodeService osNodeService;
166
Ray Milkey8e406512018-10-24 15:56:50 -0700167 /** Fake MAC address for virtual network subnet gateway. */
168 private String gatewayMac = GATEWAY_MAC_DEFAULT;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700169
Ray Milkey8e406512018-10-24 15:56:50 -0700170 /** ARP processing mode, broadcast | proxy (default). */
171 protected String arpMode = ARP_MODE_DEFAULT;
Jian Lieae12362018-04-10 18:48:32 +0900172
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700173 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174 private final InternalOpenstackNetworkListener osNetworkListener =
175 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900176 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
177 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
178
Jian Li32b03622018-11-06 17:54:24 +0900179 private final ExecutorService eventExecutor = newSingleThreadExecutor(
180 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
181
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182
183 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900184 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700185
186 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800187 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
189 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900190 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900191 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900192 osNodeService.addListener(osNodeListener);
193 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700194 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900195
196 instancePortService.addListener(instancePortListener);
197
Hyunsun Moon44aac662017-02-18 02:07:01 +0900198 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700199 }
200
201 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800202 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700203 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900204 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900205 osNodeService.removeListener(osNodeListener);
206 instancePortService.removeListener(instancePortListener);
207 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900208 configService.unregisterProperties(getClass(), false);
Jian Li32b03622018-11-06 17:54:24 +0900209 eventExecutor.shutdown();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210
211 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700212 }
213
214 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800215 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900216 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900217
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700218 log.info("Modified");
219 }
220
Jian Li7f70bb72018-07-06 23:35:30 +0900221 private String getArpMode() {
222 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
223 return getPropertyValue(properties, ARP_MODE);
224 }
225
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700226 /**
227 * Processes ARP request packets.
228 * It checks if the target IP is owned by a known host first and then ask to
229 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
230 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900231 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700232 * @param ethPacket ethernet packet
233 */
234 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900235
236 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900237 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900238 return;
239 }
240
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700241 ARP arpPacket = (ARP) ethPacket.getPayload();
242 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
243 return;
244 }
245
Hyunsun Moon44aac662017-02-18 02:07:01 +0900246 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
247 if (srcInstPort == null) {
248 log.trace("Failed to find source instance port(MAC:{})",
249 ethPacket.getSourceMAC());
250 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700251 }
252
Hyunsun Moon44aac662017-02-18 02:07:01 +0900253 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900254
Jian Liac30e272018-10-18 23:08:03 +0900255 MacAddress replyMac = isGatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900256 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700257 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700259 return;
260 }
261
262 Ethernet ethReply = ARP.buildArpReply(
263 targetIp.getIp4Address(),
264 replyMac,
265 ethPacket);
266
267 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
268 .setOutput(context.inPacket().receivedFrom().port())
269 .build();
270
271 packetService.emit(new DefaultOutboundPacket(
272 context.inPacket().receivedFrom().deviceId(),
273 treatment,
274 ByteBuffer.wrap(ethReply.serialize())));
275 }
276
Jian Liac30e272018-10-18 23:08:03 +0900277 /**
278 * Denotes whether the given target IP is gateway IP.
279 *
280 * @param targetIp target IP address
281 * @return true if the given targetIP is gateway IP, false otherwise.
282 */
283 private boolean isGatewayIp(IpAddress targetIp) {
Daniel Park4d7f88b2018-09-19 19:03:38 +0900284 return osNetworkService.subnets().stream()
Jian Liac30e272018-10-18 23:08:03 +0900285 .filter(Objects::nonNull)
286 .filter(subnet -> subnet.getGateway() != null)
Daniel Park4d7f88b2018-09-19 19:03:38 +0900287 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
288 }
289
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700290 /**
291 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900292 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700293 *
294 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900295 * @param osNetId openstack network id of the source instance port
296 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700297 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900298 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700299 checkNotNull(targetIp);
300
Hyunsun Moon44aac662017-02-18 02:07:01 +0900301 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
302 if (instPort != null) {
303 log.trace("Found MAC from host service for {}", targetIp);
304 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700305 } else {
306 return MacAddress.NONE;
307 }
308 }
309
Jian Lieae12362018-04-10 18:48:32 +0900310 /**
Daniel Park613ac372018-06-28 14:30:11 +0900311 * Installs flow rules which convert ARP request packet into ARP reply
312 * by adding a fake gateway MAC address as Source Hardware Address.
313 *
314 * @param osSubnet openstack subnet
Jian Li5b155bf2018-11-21 18:16:26 +0900315 * @param network openstack network
Daniel Park613ac372018-06-28 14:30:11 +0900316 * @param install flag which indicates whether to install rule or remove rule
Jian Li5b155bf2018-11-21 18:16:26 +0900317 * @param osNode openstack node
Daniel Park613ac372018-06-28 14:30:11 +0900318 */
Jian Li5b155bf2018-11-21 18:16:26 +0900319 private void setFakeGatewayArpRule(Subnet osSubnet, Network network,
320 boolean install, OpenstackNode osNode) {
Daniel Park613ac372018-06-28 14:30:11 +0900321
Jian Li7f70bb72018-07-06 23:35:30 +0900322 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li8e365bd2018-10-12 22:09:03 +0900323
SONA Project6bc5c4a2018-12-14 23:49:52 +0900324 Type netType = osNetworkService.networkType(network.getId());
325
Daniel Park613ac372018-06-28 14:30:11 +0900326 String gateway = osSubnet.getGateway();
Daniel Park6a2d95e2018-11-05 18:50:16 +0900327 if (gateway == null) {
328 return;
329 }
Daniel Park613ac372018-06-28 14:30:11 +0900330
Daniel Park8a9220f2018-11-19 18:58:35 +0900331 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
Daniel Park613ac372018-06-28 14:30:11 +0900332
SONA Project6bc5c4a2018-12-14 23:49:52 +0900333 if (netType == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900334 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
Jian Lia2995192019-04-02 14:13:04 +0900335
Jian Li621f73c2018-12-15 01:49:22 +0900336 } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
Jian Li5b155bf2018-11-21 18:16:26 +0900337 // do not remove fake gateway ARP rules, if there is another gateway
338 // which has the same subnet that to be removed
339 // this only occurs if we have duplicated subnets associated with
340 // different networks
341 if (!install) {
342 long numOfDupGws = osNetworkService.subnets().stream()
343 .filter(s -> !s.getId().equals(osSubnet.getId()))
344 .filter(s -> s.getGateway() != null)
345 .filter(s -> s.getGateway().equals(osSubnet.getGateway()))
346 .count();
347 if (numOfDupGws > 0) {
348 return;
349 }
350 }
Daniel Park8a9220f2018-11-19 18:58:35 +0900351 }
352
353 sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort())
354 .matchArpOp(ARP.OP_REQUEST)
355 .matchArpTpa(Ip4Address.valueOf(gateway));
356
Daniel Park613ac372018-06-28 14:30:11 +0900357 if (osNode == null) {
Jian Li4910c4b2019-04-01 18:06:40 +0900358 osNodeService.completeNodes(COMPUTE).forEach(n -> {
359 Device device = deviceService.getDevice(n.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900360
361 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
362
363 if (netType == VLAN) {
364 tBuilder.popVlan();
365 }
366
Jian Li4910c4b2019-04-01 18:06:40 +0900367 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
368 .extension(buildMoveArpShaToThaExtension(device), device.id())
369 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
370 .setArpOp(ARP.OP_REPLY)
371 .setArpSha(MacAddress.valueOf(gatewayMac))
372 .setArpSpa(Ip4Address.valueOf(gateway))
Jian Li1b5c5fa2019-04-24 13:51:28 +0900373 .setEthSrc(MacAddress.valueOf(gatewayMac))
Jian Li4910c4b2019-04-01 18:06:40 +0900374 .setOutput(PortNumber.IN_PORT);
375
376 osFlowRuleService.setRule(
377 appId,
378 n.intgBridge(),
379 sBuilder.build(),
380 tBuilder.build(),
381 PRIORITY_ARP_GATEWAY_RULE,
382 ARP_TABLE,
383 install
384 );
385 });
Daniel Park613ac372018-06-28 14:30:11 +0900386 } else {
Jian Li4910c4b2019-04-01 18:06:40 +0900387 Device device = deviceService.getDevice(osNode.intgBridge());
Jian Lia2995192019-04-02 14:13:04 +0900388
389 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
390
391 if (netType == VLAN) {
392 tBuilder.popVlan();
393 }
394
Jian Li4910c4b2019-04-01 18:06:40 +0900395 tBuilder.extension(buildMoveEthSrcToDstExtension(device), device.id())
396 .extension(buildMoveArpShaToThaExtension(device), device.id())
397 .extension(buildMoveArpSpaToTpaExtension(device), device.id())
398 .setArpOp(ARP.OP_REPLY)
399 .setArpSha(MacAddress.valueOf(gatewayMac))
400 .setArpSpa(Ip4Address.valueOf(gateway))
401 .setOutput(PortNumber.IN_PORT);
402
Daniel Park613ac372018-06-28 14:30:11 +0900403 osFlowRuleService.setRule(
404 appId,
405 osNode.intgBridge(),
Daniel Park8a9220f2018-11-19 18:58:35 +0900406 sBuilder.build(),
407 tBuilder.build(),
Daniel Park613ac372018-06-28 14:30:11 +0900408 PRIORITY_ARP_GATEWAY_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900409 ARP_TABLE,
Daniel Park613ac372018-06-28 14:30:11 +0900410 install
411 );
412 }
Daniel Park613ac372018-06-28 14:30:11 +0900413 }
414 }
415
416 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900417 * Installs flow rules to match ARP request packets.
418 *
419 * @param port instance port
420 * @param install installation flag
421 */
422 private void setArpRequestRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900423 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900424
SONA Project6bc5c4a2018-12-14 23:49:52 +0900425 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900426 case VXLAN:
Jian Li2d68c192018-12-13 15:52:59 +0900427 case GRE:
Jian Li621f73c2018-12-15 01:49:22 +0900428 case GENEVE:
Jian Li2d68c192018-12-13 15:52:59 +0900429 setRemoteArpRequestRuleForTunnel(port, install);
Jian Lid5727622019-09-11 11:15:16 +0900430 setLocalArpRequestRuleForVnet(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900431 break;
432 case VLAN:
Jian Li5b155bf2018-11-21 18:16:26 +0900433 setArpRequestRuleForVlan(port, install);
Jian Lid5727622019-09-11 11:15:16 +0900434 setLocalArpRequestRuleForVnet(port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900435 break;
436 default:
437 break;
438 }
439 }
440
441 /**
442 * Installs flow rules to match ARP reply packets.
443 *
444 * @param port instance port
445 * @param install installation flag
446 */
447 private void setArpReplyRule(InstancePort port, boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900448 Type netType = osNetworkService.networkType(port.networkId());
Jian Li7f70bb72018-07-06 23:35:30 +0900449
SONA Project6bc5c4a2018-12-14 23:49:52 +0900450 switch (netType) {
Jian Li7f70bb72018-07-06 23:35:30 +0900451 case VXLAN:
452 setArpReplyRuleForVxlan(port, install);
453 break;
Jian Li2d68c192018-12-13 15:52:59 +0900454 case GRE:
455 setArpReplyRuleForGre(port, install);
456 break;
Jian Li621f73c2018-12-15 01:49:22 +0900457 case GENEVE:
458 setArpReplyRuleForGeneve(port, install);
459 break;
Jian Li7f70bb72018-07-06 23:35:30 +0900460 case VLAN:
461 setArpReplyRuleForVlan(port, install);
462 break;
463 default:
464 break;
465 }
466 }
467
468 /**
Jian Lid5727622019-09-11 11:15:16 +0900469 * Installs flow rules at remote node to match ARP request packets for Tunnel.
Jian Li7f70bb72018-07-06 23:35:30 +0900470 *
471 * @param port instance port
472 * @param install installation flag
473 */
Jian Li2d68c192018-12-13 15:52:59 +0900474 private void setRemoteArpRequestRuleForTunnel(InstancePort port, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900475
476 OpenstackNode localNode = osNodeService.node(port.deviceId());
477
Jian Li5c09e212018-10-24 18:23:58 +0900478 String segId = osNetworkService.segmentId(port.networkId());
479
Jian Li7f70bb72018-07-06 23:35:30 +0900480 TrafficSelector selector = DefaultTrafficSelector.builder()
481 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
482 .matchArpOp(ARP.OP_REQUEST)
483 .matchArpTpa(port.ipAddress().getIp4Address())
Jian Li5c09e212018-10-24 18:23:58 +0900484 .matchTunnelId(Long.valueOf(segId))
Jian Li7f70bb72018-07-06 23:35:30 +0900485 .build();
486
Jian Li2d68c192018-12-13 15:52:59 +0900487 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900488 }
489
490 /**
Jian Lid5727622019-09-11 11:15:16 +0900491 * Installs flow rules at local node to matchA RP request packets for Tunnel.
492 *
493 * @param port instance port
494 * @param install installation flag
495 */
496 private void setLocalArpRequestRuleForVnet(InstancePort port, boolean install) {
497 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
498 .setOutput(port.portNumber());
499
500 List<GroupBucket> bkts = Lists.newArrayList();
501 bkts.add(buildGroupBucket(tBuilder.build(), ALL, (short) -1));
502 osGroupRuleService.setBuckets(appId, port.deviceId(),
503 port.networkId().hashCode(), bkts, install);
504 }
505
506 /**
Jian Li5b155bf2018-11-21 18:16:26 +0900507 * Installs flow rules to match ARP request packets for VLAN.
508 *
509 * @param port instance port
510 * @param install installation flag
511 */
512 private void setArpRequestRuleForVlan(InstancePort port, boolean install) {
513 TrafficSelector selector = getArpRequestSelectorForVlan(port);
514
515 setLocalArpRequestTreatmentForVlan(selector, port, install);
516 setRemoteArpRequestTreatmentForVlan(selector, port, install);
517 }
518
519 /**
520 * Obtains the ARP request selector for VLAN.
521 *
522 * @param port instance port
523 * @return traffic selector
524 */
525 private TrafficSelector getArpRequestSelectorForVlan(InstancePort port) {
526 String segId = osNetworkService.segmentId(port.networkId());
527
528 return DefaultTrafficSelector.builder()
529 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
530 .matchArpOp(ARP.OP_REQUEST)
531 .matchArpTpa(port.ipAddress().getIp4Address())
532 .matchVlanId(VlanId.vlanId(segId))
533 .build();
534 }
535
536 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900537 * Installs flow rules to match ARP reply packets only for VxLAN.
538 *
539 * @param port instance port
540 * @param install installation flag
541 */
542 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
543
544 OpenstackNode localNode = osNodeService.node(port.deviceId());
545
Jian Li5b155bf2018-11-21 18:16:26 +0900546 TrafficSelector selector = getArpReplySelectorForVxlan(port);
547
548 setLocalArpReplyTreatmentForVxlan(selector, port, install);
Jian Li2d68c192018-12-13 15:52:59 +0900549 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
550 }
551
552 /**
553 * Installs flow rules to match ARP reply packets only for GRE.
554 *
555 * @param port instance port
556 * @param install installation flag
557 */
558 private void setArpReplyRuleForGre(InstancePort port, boolean install) {
559
560 OpenstackNode localNode = osNodeService.node(port.deviceId());
561
562 TrafficSelector selector = getArpReplySelectorForGre(port);
563
564 setLocalArpReplyTreatmentForGre(selector, port, install);
565 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900566 }
567
568 /**
Jian Li621f73c2018-12-15 01:49:22 +0900569 * Installs flow rules to match ARP reply packets only for GENEVE.
570 *
571 * @param port instance port
572 * @param install installation flag
573 */
574 private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
575
576 OpenstackNode localNode = osNodeService.node(port.deviceId());
577
578 TrafficSelector selector = getArpReplySelectorForGeneve(port);
579
580 setLocalArpReplyTreatmentForGeneve(selector, port, install);
581 setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
582 }
583
584 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900585 * Installs flow rules to match ARP reply packets only for VLAN.
586 *
587 * @param port instance port
588 * @param install installation flag
589 */
590 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
591
Jian Li5b155bf2018-11-21 18:16:26 +0900592 TrafficSelector selector = getArpReplySelectorForVlan(port);
593
594 setLocalArpReplyTreatmentForVlan(selector, port, install);
595 setRemoteArpReplyTreatmentForVlan(selector, port, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900596 }
597
598 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900599 private TrafficSelector getArpReplySelectorForVxlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900600 return getArpReplySelectorForVnet(port, VXLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900601 }
602
603 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900604 private TrafficSelector getArpReplySelectorForGre(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900605 return getArpReplySelectorForVnet(port, GRE);
Jian Li2d68c192018-12-13 15:52:59 +0900606 }
607
608 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900609 private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
610 return getArpReplySelectorForVnet(port, GENEVE);
611 }
612
613 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900614 private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900615 return getArpReplySelectorForVnet(port, VLAN);
Jian Li5b155bf2018-11-21 18:16:26 +0900616 }
617
618 // a helper method
619 private TrafficSelector getArpReplySelectorForVnet(InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900620 Type type) {
Jian Li5b155bf2018-11-21 18:16:26 +0900621
622 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
623
SONA Project6bc5c4a2018-12-14 23:49:52 +0900624 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900625 String segId = osNetworkService.network(port.networkId()).getProviderSegID();
626 sBuilder.matchVlanId(VlanId.vlanId(segId));
627 }
628
629 return sBuilder
Jian Li7f70bb72018-07-06 23:35:30 +0900630 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
631 .matchArpOp(ARP.OP_REPLY)
632 .matchArpTpa(port.ipAddress().getIp4Address())
633 .matchArpTha(port.macAddress())
634 .build();
Jian Li5b155bf2018-11-21 18:16:26 +0900635 }
Jian Li7f70bb72018-07-06 23:35:30 +0900636
Jian Li5b155bf2018-11-21 18:16:26 +0900637 // a helper method
638 private void setLocalArpReplyTreatmentForVxlan(TrafficSelector selector,
639 InstancePort port,
640 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900641 setLocalArpReplyTreatmentForVnet(selector, port, VXLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900642 }
643
644 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900645 private void setLocalArpReplyTreatmentForGre(TrafficSelector selector,
646 InstancePort port,
647 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900648 setLocalArpReplyTreatmentForVnet(selector, port, GRE, install);
Jian Li2d68c192018-12-13 15:52:59 +0900649 }
650
651 // a helper method
Jian Li621f73c2018-12-15 01:49:22 +0900652 private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
653 InstancePort port,
654 boolean install) {
655 setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
656 }
657
658 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900659 private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
660 InstancePort port,
661 boolean install) {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900662 setLocalArpReplyTreatmentForVnet(selector, port, VLAN, install);
Jian Li5b155bf2018-11-21 18:16:26 +0900663 }
664
665 // a helper method
666 private void setLocalArpReplyTreatmentForVnet(TrafficSelector selector,
667 InstancePort port,
SONA Project6bc5c4a2018-12-14 23:49:52 +0900668 Type type,
Jian Li5b155bf2018-11-21 18:16:26 +0900669 boolean install) {
670 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
671
SONA Project6bc5c4a2018-12-14 23:49:52 +0900672 if (type == VLAN) {
Jian Li5b155bf2018-11-21 18:16:26 +0900673 tBuilder.popVlan();
674 }
675
676 tBuilder.setOutput(port.portNumber());
677
678 osFlowRuleService.setRule(
679 appId,
680 port.deviceId(),
681 selector,
682 tBuilder.build(),
683 PRIORITY_ARP_REPLY_RULE,
684 ARP_TABLE,
685 install
686 );
687 }
688
689 // a helper method
690 private void setLocalArpRequestTreatmentForVlan(TrafficSelector selector,
691 InstancePort port,
692 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900693 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jian Li5b155bf2018-11-21 18:16:26 +0900694 .popVlan()
Jian Li7f70bb72018-07-06 23:35:30 +0900695 .setOutput(port.portNumber())
696 .build();
697
698 osFlowRuleService.setRule(
699 appId,
700 port.deviceId(),
701 selector,
702 treatment,
Jian Li5b155bf2018-11-21 18:16:26 +0900703 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900704 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900705 install
706 );
Jian Li7f70bb72018-07-06 23:35:30 +0900707 }
708
709 // a helper method
Jian Li2d68c192018-12-13 15:52:59 +0900710 private void setRemoteArpTreatmentForTunnel(TrafficSelector selector,
711 InstancePort port,
712 OpenstackNode localNode,
713 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900714 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
715 if (!remoteNode.intgBridge().equals(port.deviceId())) {
Jian Li2d68c192018-12-13 15:52:59 +0900716
717 PortNumber portNum = tunnelPortNumByNetId(port.networkId(),
718 osNetworkService, remoteNode);
719
Jian Li7f70bb72018-07-06 23:35:30 +0900720 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
Jian Li2d68c192018-12-13 15:52:59 +0900721 .extension(buildExtension(
722 deviceService,
723 remoteNode.intgBridge(),
724 localNode.dataIp().getIp4Address()),
725 remoteNode.intgBridge())
726 .setOutput(portNum)
727 .build();
Jian Li7f70bb72018-07-06 23:35:30 +0900728
729 osFlowRuleService.setRule(
730 appId,
731 remoteNode.intgBridge(),
732 selector,
733 treatmentToRemote,
734 PRIORITY_ARP_REQUEST_RULE,
Jian Li5c09e212018-10-24 18:23:58 +0900735 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900736 install
737 );
738 }
739 }
740 }
741
742 // a helper method
Jian Li5b155bf2018-11-21 18:16:26 +0900743 private void setRemoteArpRequestTreatmentForVlan(TrafficSelector selector,
744 InstancePort port,
745 boolean install) {
746 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REQUEST, install);
747 }
748
749 // a helper method
750 private void setRemoteArpReplyTreatmentForVlan(TrafficSelector selector,
751 InstancePort port,
752 boolean install) {
753 setRemoteArpTreatmentForVlan(selector, port, ARP.OP_REPLY, install);
754 }
755
756 // a helper method
Jian Li7f70bb72018-07-06 23:35:30 +0900757 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
758 InstancePort port,
Jian Li5b155bf2018-11-21 18:16:26 +0900759 short arpOp,
Jian Li7f70bb72018-07-06 23:35:30 +0900760 boolean install) {
Jian Li5b155bf2018-11-21 18:16:26 +0900761
762 int priority;
763 if (arpOp == ARP.OP_REQUEST) {
764 priority = PRIORITY_ARP_REQUEST_RULE;
765 } else if (arpOp == ARP.OP_REPLY) {
766 priority = PRIORITY_ARP_REPLY_RULE;
767 } else {
768 // if ARP op does not match with any operation mode, we simply
769 // configure the ARP request rule priority
770 priority = PRIORITY_ARP_REQUEST_RULE;
771 }
772
Jian Li7f70bb72018-07-06 23:35:30 +0900773 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
Jian Li5ecfd1a2018-12-10 11:41:03 +0900774 if (!remoteNode.intgBridge().equals(port.deviceId()) &&
775 remoteNode.vlanIntf() != null) {
Jian Li7f70bb72018-07-06 23:35:30 +0900776 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
777 .setOutput(remoteNode.vlanPortNum())
778 .build();
779
780 osFlowRuleService.setRule(
781 appId,
782 remoteNode.intgBridge(),
783 selector,
784 treatmentToRemote,
Jian Li5b155bf2018-11-21 18:16:26 +0900785 priority,
Jian Li5c09e212018-10-24 18:23:58 +0900786 ARP_TABLE,
Jian Li7f70bb72018-07-06 23:35:30 +0900787 install);
788 }
789 }
790 }
791
Jian Lid5727622019-09-11 11:15:16 +0900792 // a helper method
793 private void setBaseVnetArpRuleForBroadcastMode(OpenstackNode osNode,
794 String segId, String netId,
795 boolean isTunnel,
796 boolean install) {
797
798 // add group rule
799 int groupId = netId.hashCode();
800 osGroupRuleService.setRule(appId, osNode.intgBridge(), groupId,
801 ALL, Lists.newArrayList(), install);
802
803 // add flow rule
804 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
805 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
806 .matchArpOp(ARP.OP_REQUEST);
807
808 if (isTunnel) {
809 sBuilder.matchTunnelId(Long.parseLong(segId));
810 } else {
811 sBuilder.matchVlanId(VlanId.vlanId(segId));
812 }
813
814 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
815 .group(GroupId.valueOf(netId.hashCode()))
816 .build();
817
818 osFlowRuleService.setRule(
819 appId,
820 osNode.intgBridge(),
821 sBuilder.build(),
822 treatment,
823 PRIORITY_ARP_GROUP_RULE,
824 ARP_TABLE,
825 install
826 );
827 }
828
Jian Li7f70bb72018-07-06 23:35:30 +0900829 /**
830 * Extracts properties from the component configuration context.
831 *
832 * @param context the component context
833 */
834 private void readComponentConfiguration(ComponentContext context) {
835 Dictionary<?, ?> properties = context.getProperties();
836
837 String updatedMac = Tools.get(properties, GATEWAY_MAC);
Ray Milkey8e406512018-10-24 15:56:50 -0700838 gatewayMac = updatedMac != null ? updatedMac : GATEWAY_MAC_DEFAULT;
Jian Li7f70bb72018-07-06 23:35:30 +0900839 log.info("Configured. Gateway MAC is {}", gatewayMac);
840 }
841
842 /**
Jian Lieae12362018-04-10 18:48:32 +0900843 * An internal packet processor which processes ARP request, and results in
844 * packet-out ARP reply.
845 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700846 private class InternalPacketProcessor implements PacketProcessor {
847
848 @Override
849 public void process(PacketContext context) {
850 if (context.isHandled()) {
851 return;
852 }
853
854 Ethernet ethPacket = context.inPacket().parsed();
855 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
856 return;
857 }
Jian Li32b03622018-11-06 17:54:24 +0900858
859 eventExecutor.execute(() -> processPacketIn(context, ethPacket));
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700860 }
861 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900862
Jian Lieae12362018-04-10 18:48:32 +0900863 /**
864 * An internal network listener which listens to openstack network event,
865 * manages the gateway collection and installs flow rule that handles
866 * ARP request in data plane.
867 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900868 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
869
870 @Override
871 public boolean isRelevant(OpenstackNetworkEvent event) {
Jian Li5b155bf2018-11-21 18:16:26 +0900872 Network network = event.subject();
Jian Libb4f5412018-04-12 09:48:50 +0900873
Jian Lieae12362018-04-10 18:48:32 +0900874 if (network == null) {
875 log.warn("Network is not specified.");
876 return false;
877 } else {
SONA Project6bc5c4a2018-12-14 23:49:52 +0900878 return network.getProviderSegID() != null;
Jian Lieae12362018-04-10 18:48:32 +0900879 }
Jian Li5b155bf2018-11-21 18:16:26 +0900880 }
Jian Lieae12362018-04-10 18:48:32 +0900881
Jian Li5b155bf2018-11-21 18:16:26 +0900882 private boolean isRelevantHelper() {
883 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900884 }
885
886 @Override
887 public void event(OpenstackNetworkEvent event) {
888 switch (event.type()) {
889 case OPENSTACK_SUBNET_CREATED:
890 case OPENSTACK_SUBNET_UPDATED:
Jian Li6a47fd02018-11-27 21:51:03 +0900891 eventExecutor.execute(() -> processSubnetCreation(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900892 break;
893 case OPENSTACK_SUBNET_REMOVED:
Jian Li6a47fd02018-11-27 21:51:03 +0900894 eventExecutor.execute(() -> processSubnetRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900895 break;
896 case OPENSTACK_NETWORK_CREATED:
897 case OPENSTACK_NETWORK_UPDATED:
Jian Lib3dc1ca2019-09-08 00:35:11 +0900898 eventExecutor.execute(() -> processNetworkCreation(event));
899 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900900 case OPENSTACK_NETWORK_REMOVED:
Jian Lib3dc1ca2019-09-08 00:35:11 +0900901 eventExecutor.execute(() -> processNetworkRemoval(event));
902 break;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900903 case OPENSTACK_PORT_CREATED:
904 case OPENSTACK_PORT_UPDATED:
905 case OPENSTACK_PORT_REMOVED:
906 default:
907 // do nothing for the other events
908 break;
909 }
910 }
Jian Li6a47fd02018-11-27 21:51:03 +0900911
912 private void processSubnetCreation(OpenstackNetworkEvent event) {
913 if (!isRelevantHelper()) {
914 return;
915 }
916
917 setFakeGatewayArpRule(event.subnet(), event.subject(),
918 true, null);
919 }
920
921 private void processSubnetRemoval(OpenstackNetworkEvent event) {
922 if (!isRelevantHelper()) {
923 return;
924 }
925
926 setFakeGatewayArpRule(event.subnet(), event.subject(),
927 false, null);
928 }
Jian Lib3dc1ca2019-09-08 00:35:11 +0900929
930 private void processNetworkCreation(OpenstackNetworkEvent event) {
931 if (!isRelevantHelper()) {
932 return;
933 }
934
935 setVnetArpRule(event.subject(), true);
936 }
937
938 private void processNetworkRemoval(OpenstackNetworkEvent event) {
939 if (!isRelevantHelper()) {
940 return;
941 }
942
943 setVnetArpRule(event.subject(), false);
944 }
945
946 private void setVnetArpRule(Network network, boolean install) {
Jian Li8ac677c2019-09-16 22:41:34 +0900947
948 if (ARP_PROXY_MODE.equals(getArpMode())) {
949 return;
950 }
951
Jian Lib3dc1ca2019-09-08 00:35:11 +0900952 String netId = network.getId();
953 NetworkType netType = network.getNetworkType();
954
955 if (netType != NetworkType.LOCAL && netType != NetworkType.FLAT
956 && netType != NetworkType.VLAN) {
957 String segId = osNetworkService.segmentId(netId);
958 osNodeService.completeNodes(COMPUTE)
Jian Lid5727622019-09-11 11:15:16 +0900959 .forEach(node -> {
960 setBaseVnetArpRuleForBroadcastMode(node, segId,
961 netId, true, install);
962 });
Jian Lib3dc1ca2019-09-08 00:35:11 +0900963 }
964 if (netType == NetworkType.VLAN) {
965 String segId = osNetworkService.segmentId(netId);
966 osNodeService.completeNodes(COMPUTE)
Jian Lid5727622019-09-11 11:15:16 +0900967 .forEach(node -> {
968 setBaseVnetArpRuleForBroadcastMode(
969 node, segId, netId, false, install);
970 });
Jian Lib3dc1ca2019-09-08 00:35:11 +0900971 }
972 }
Jian Lieae12362018-04-10 18:48:32 +0900973 }
974
975 /**
976 * An internal openstack node listener which is used for listening openstack
977 * node activity. As long as a node is in complete state, we will install
978 * default ARP rule to handle ARP request.
979 */
980 private class InternalNodeEventListener implements OpenstackNodeListener {
Jian Lifb64d882018-11-27 10:57:40 +0900981 @Override
982 public boolean isRelevant(OpenstackNodeEvent event) {
983 return event.subject().type() == COMPUTE;
984 }
985
Jian Li34220ea2018-11-14 01:30:24 +0900986 private boolean isRelevantHelper() {
987 return Objects.equals(localNodeId, leadershipService.getLeader(appId.name()));
Jian Lieae12362018-04-10 18:48:32 +0900988 }
989
990 @Override
991 public void event(OpenstackNodeEvent event) {
992 OpenstackNode osNode = event.subject();
993 switch (event.type()) {
994 case OPENSTACK_NODE_COMPLETE:
Jian Li6a47fd02018-11-27 21:51:03 +0900995 eventExecutor.execute(() -> processNodeCompletion(osNode));
Jian Lieae12362018-04-10 18:48:32 +0900996 break;
997 case OPENSTACK_NODE_INCOMPLETE:
Jian Lieae12362018-04-10 18:48:32 +0900998 default:
999 break;
1000 }
1001 }
1002
Jian Li6a47fd02018-11-27 21:51:03 +09001003 private void processNodeCompletion(OpenstackNode osNode) {
1004 if (!isRelevantHelper()) {
1005 return;
1006 }
1007
1008 setDefaultArpRule(osNode, true);
1009 setAllArpRules(osNode, true);
1010 }
1011
1012 private void processNodeIncompletion(OpenstackNode osNode) {
1013 if (!isRelevantHelper()) {
1014 return;
1015 }
1016
1017 setDefaultArpRule(osNode, false);
1018 setAllArpRules(osNode, false);
1019 }
1020
Jian Lif96685c2018-05-21 14:14:16 +09001021 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +09001022
1023 if (getArpMode() == null) {
1024 return;
1025 }
1026
Jian Li7f70bb72018-07-06 23:35:30 +09001027 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +09001028 case ARP_PROXY_MODE:
1029 setDefaultArpRuleForProxyMode(osNode, install);
1030 break;
1031 case ARP_BROADCAST_MODE:
Jian Li6a47fd02018-11-27 21:51:03 +09001032 processDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lif96685c2018-05-21 14:14:16 +09001033 break;
1034 default:
1035 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +09001036 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +09001037 break;
Jian Lieae12362018-04-10 18:48:32 +09001038 }
1039 }
Jian Lif96685c2018-05-21 14:14:16 +09001040
Jian Li6a47fd02018-11-27 21:51:03 +09001041 private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
1042 boolean install) {
Jian Lib3dc1ca2019-09-08 00:35:11 +09001043 setVnetArpRuleForBroadcastMode(osNode, install);
Jian Li6a47fd02018-11-27 21:51:03 +09001044
1045 // we do not add fake gateway ARP rules for FLAT network
1046 // ARP packets generated by FLAT typed VM should not be
1047 // delegated to switch to handle
1048 osNetworkService.subnets().stream().filter(subnet ->
1049 osNetworkService.network(subnet.getNetworkId()) != null &&
SONA Project6bc5c4a2018-12-14 23:49:52 +09001050 osNetworkService.networkType(subnet.getNetworkId()) != FLAT)
Jian Li6a47fd02018-11-27 21:51:03 +09001051 .forEach(subnet -> {
1052 String netId = subnet.getNetworkId();
1053 Network net = osNetworkService.network(netId);
1054 setFakeGatewayArpRule(subnet, net, install, osNode);
1055 });
1056 }
1057
Jian Lif96685c2018-05-21 14:14:16 +09001058 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
1059 TrafficSelector selector = DefaultTrafficSelector.builder()
1060 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
1061 .build();
1062
1063 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
1064 .punt()
1065 .build();
1066
1067 osFlowRuleService.setRule(
1068 appId,
1069 osNode.intgBridge(),
1070 selector,
1071 treatment,
1072 PRIORITY_ARP_CONTROL_RULE,
Jian Li5c09e212018-10-24 18:23:58 +09001073 ARP_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +09001074 install
1075 );
1076 }
1077
Jian Lib3dc1ca2019-09-08 00:35:11 +09001078 private void setVnetArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
1079 Set<String> netIds = osNetworkService.networks().stream()
1080 .map(IdEntity::getId).collect(Collectors.toSet());
Jian Lif96685c2018-05-21 14:14:16 +09001081
Jian Lib3dc1ca2019-09-08 00:35:11 +09001082 netIds.stream()
1083 .filter(nid -> osNetworkService.networkType(nid) == VXLAN ||
1084 osNetworkService.networkType(nid) == GRE ||
1085 osNetworkService.networkType(nid) == GENEVE)
1086 .forEach(nid -> {
1087 String segId = osNetworkService.segmentId(nid);
Jian Lid5727622019-09-11 11:15:16 +09001088 setBaseVnetArpRuleForBroadcastMode(osNode, segId, nid, true, install);
Jian Lib3dc1ca2019-09-08 00:35:11 +09001089 });
Jian Lif96685c2018-05-21 14:14:16 +09001090
Jian Lib3dc1ca2019-09-08 00:35:11 +09001091 netIds.stream()
1092 .filter(nid -> osNetworkService.networkType(nid) == VLAN)
1093 .forEach(nid -> {
1094 String segId = osNetworkService.segmentId(nid);
Jian Lid5727622019-09-11 11:15:16 +09001095 setBaseVnetArpRuleForBroadcastMode(osNode, segId, nid, false, install);
Jian Lib3dc1ca2019-09-08 00:35:11 +09001096 });
Jian Lif96685c2018-05-21 14:14:16 +09001097 }
Jian Li7f70bb72018-07-06 23:35:30 +09001098
Jian Li5b66ce02018-07-09 22:43:54 +09001099 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +09001100 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +09001101 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +09001102 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +09001103 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
1104 .forEach(p -> {
1105 setArpRequestRule(p, install);
1106 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +09001107 });
Jian Lid5727622019-09-11 11:15:16 +09001108 } else {
1109 // we do nothing for proxy mode
Jian Li7f70bb72018-07-06 23:35:30 +09001110 }
1111 }
Jian Lieae12362018-04-10 18:48:32 +09001112 }
1113
1114 /**
1115 * An internal instance port listener which listens the port events generated
1116 * from VM. When ARP a host which located in a remote compute node, we specify
1117 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
1118 * host IP address. When ARP a host which located in a local compute node,
1119 * we specify only ARP OP mode as REQUEST.
1120 */
1121 private class InternalInstancePortListener implements InstancePortListener {
1122
1123 @Override
1124 public boolean isRelevant(InstancePortEvent event) {
Jian Li34220ea2018-11-14 01:30:24 +09001125 return ARP_BROADCAST_MODE.equals(getArpMode());
1126 }
Jian Lieae12362018-04-10 18:48:32 +09001127
Jian Li34220ea2018-11-14 01:30:24 +09001128 private boolean isRelevantHelper(InstancePortEvent event) {
1129 return mastershipService.isLocalMaster(event.subject().deviceId());
Jian Lieae12362018-04-10 18:48:32 +09001130 }
1131
1132 @Override
1133 public void event(InstancePortEvent event) {
1134 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +09001135 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +09001136 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Li34220ea2018-11-14 01:30:24 +09001137 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
Jian Li6a47fd02018-11-27 21:51:03 +09001138 eventExecutor.execute(() -> processInstanceMigrationStart(event));
Jian Lieae12362018-04-10 18:48:32 +09001139 break;
1140 case OPENSTACK_INSTANCE_PORT_VANISHED:
Jian Li6a47fd02018-11-27 21:51:03 +09001141 eventExecutor.execute(() -> processInstanceRemoval(event));
Jian Lieae12362018-04-10 18:48:32 +09001142 break;
Jian Li24ec59f2018-05-23 19:01:25 +09001143 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Li6a47fd02018-11-27 21:51:03 +09001144 eventExecutor.execute(() -> processInstanceMigrationEnd(event));
Jian Li24ec59f2018-05-23 19:01:25 +09001145 break;
Jian Lieae12362018-04-10 18:48:32 +09001146 default:
1147 break;
1148 }
1149 }
Jian Li6a47fd02018-11-27 21:51:03 +09001150
1151 private void processInstanceMigrationStart(InstancePortEvent event) {
1152 if (!isRelevantHelper(event)) {
1153 return;
1154 }
1155
1156 setArpRequestRule(event.subject(), true);
1157 setArpReplyRule(event.subject(), true);
1158 }
1159
1160 private void processInstanceMigrationEnd(InstancePortEvent event) {
1161 if (!isRelevantHelper(event)) {
1162 return;
1163 }
1164
1165 InstancePort revisedInstPort = swapStaleLocation(event.subject());
1166 setArpRequestRule(revisedInstPort, false);
1167 }
1168
1169 private void processInstanceRemoval(InstancePortEvent event) {
1170 if (!isRelevantHelper(event)) {
1171 return;
1172 }
1173
1174 setArpRequestRule(event.subject(), false);
1175 setArpReplyRule(event.subject(), false);
1176 }
Hyunsun Moon44aac662017-02-18 02:07:01 +09001177 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -07001178}