blob: 74bf68191ffca2cbf9c0b8bf56005b89d47e5e56 [file] [log] [blame]
Daniel Park81a61a12016-02-26 08:24:44 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Daniel Park81a61a12016-02-26 08:24:44 +09003 *
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;
Daniel Park81a61a12016-02-26 08:24:44 +090017
Jian Li60312252018-05-10 18:40:32 +090018import com.google.common.base.Strings;
Jian Li1064e4f2018-05-29 16:16:53 +090019import com.google.common.collect.ImmutableSet;
Jian Li60312252018-05-10 18:40:32 +090020import com.google.common.collect.Maps;
Jian Li1064e4f2018-05-29 16:16:53 +090021import com.google.common.collect.Sets;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070022import org.apache.felix.scr.annotations.Activate;
23import org.apache.felix.scr.annotations.Component;
24import org.apache.felix.scr.annotations.Deactivate;
Jian Li60312252018-05-10 18:40:32 +090025import org.apache.felix.scr.annotations.Modified;
26import org.apache.felix.scr.annotations.Property;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070027import org.apache.felix.scr.annotations.Reference;
28import org.apache.felix.scr.annotations.ReferenceCardinality;
Daniel Park81a61a12016-02-26 08:24:44 +090029import org.onlab.packet.ARP;
Jian Li60312252018-05-10 18:40:32 +090030import org.onlab.packet.EthType;
Daniel Park81a61a12016-02-26 08:24:44 +090031import org.onlab.packet.Ethernet;
Daniel Park81a61a12016-02-26 08:24:44 +090032import org.onlab.packet.Ip4Address;
33import org.onlab.packet.IpAddress;
34import org.onlab.packet.MacAddress;
Jian Li60312252018-05-10 18:40:32 +090035import org.onosproject.cfg.ComponentConfigService;
Jian Li7f70bb72018-07-06 23:35:30 +090036import org.onosproject.cfg.ConfigProperty;
Jian Li60312252018-05-10 18:40:32 +090037import org.onosproject.cluster.ClusterService;
38import org.onosproject.cluster.LeadershipService;
39import org.onosproject.cluster.NodeId;
40import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
Jian Li14a79f22018-06-05 03:44:22 +090042import org.onosproject.net.ConnectPoint;
Hyunsun Moon0d457362017-06-27 17:19:41 +090043import org.onosproject.net.DeviceId;
daniel parkb5817102018-02-15 00:18:51 +090044import org.onosproject.net.PortNumber;
Jian Li60312252018-05-10 18:40:32 +090045import org.onosproject.net.flow.DefaultTrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090046import org.onosproject.net.flow.DefaultTrafficTreatment;
Jian Li60312252018-05-10 18:40:32 +090047import org.onosproject.net.flow.TrafficSelector;
Daniel Park81a61a12016-02-26 08:24:44 +090048import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.packet.DefaultOutboundPacket;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070050import org.onosproject.net.packet.InboundPacket;
Daniel Park81a61a12016-02-26 08:24:44 +090051import org.onosproject.net.packet.PacketContext;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070052import org.onosproject.net.packet.PacketProcessor;
Daniel Park81a61a12016-02-26 08:24:44 +090053import org.onosproject.net.packet.PacketService;
Hyunsun Moon05400872017-02-07 17:11:25 +090054import org.onosproject.openstacknetworking.api.Constants;
Jian Li60312252018-05-10 18:40:32 +090055import org.onosproject.openstacknetworking.api.InstancePort;
Jian Li24ec59f2018-05-23 19:01:25 +090056import org.onosproject.openstacknetworking.api.InstancePortEvent;
57import org.onosproject.openstacknetworking.api.InstancePortListener;
Jian Li1064e4f2018-05-29 16:16:53 +090058import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li60312252018-05-10 18:40:32 +090059import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
daniel park32b42202018-03-14 16:53:44 +090060import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Jian Lie1a39032018-06-19 21:49:36 +090061import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
62import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
Jian Li1064e4f2018-05-29 16:16:53 +090063import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Li60312252018-05-10 18:40:32 +090064import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
65import org.onosproject.openstacknetworking.api.OpenstackRouterListener;
daniel parkeeb8e042018-02-21 14:06:58 +090066import org.onosproject.openstacknetworking.api.OpenstackRouterService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090067import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lif96685c2018-05-21 14:14:16 +090068import org.onosproject.openstacknode.api.OpenstackNodeEvent;
69import org.onosproject.openstacknode.api.OpenstackNodeListener;
Hyunsun Moon0d457362017-06-27 17:19:41 +090070import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li60312252018-05-10 18:40:32 +090071import org.openstack4j.model.network.ExternalGateway;
Jian Li4df657b2018-05-29 16:39:00 +090072import org.openstack4j.model.network.IP;
daniel parkeeb8e042018-02-21 14:06:58 +090073import org.openstack4j.model.network.NetFloatingIP;
Jian Li60312252018-05-10 18:40:32 +090074import org.openstack4j.model.network.Port;
75import org.openstack4j.model.network.Router;
Jian Li60312252018-05-10 18:40:32 +090076import org.osgi.service.component.ComponentContext;
Daniel Park81a61a12016-02-26 08:24:44 +090077import org.slf4j.Logger;
78
79import java.nio.ByteBuffer;
Jian Li60312252018-05-10 18:40:32 +090080import java.util.Map;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import java.util.Objects;
Hyunsun Moon0d457362017-06-27 17:19:41 +090082import java.util.Set;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070083import java.util.concurrent.ExecutorService;
Hyunsun Moon0d457362017-06-27 17:19:41 +090084import java.util.stream.Collectors;
Daniel Park81a61a12016-02-26 08:24:44 +090085
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -070086import static java.util.concurrent.Executors.newSingleThreadExecutor;
87import static org.onlab.util.Tools.groupedThreads;
Jian Li60312252018-05-10 18:40:32 +090088import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
89import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
90import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_ARP_MODE_STR;
91import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
92import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
93import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lif96685c2018-05-21 14:14:16 +090094import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
Jian Li60312252018-05-10 18:40:32 +090095import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
Jian Li24ec59f2018-05-23 19:01:25 +090096import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
97import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByComputeDevId;
Jian Lia171a432018-06-11 11:52:11 +090098import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getGwByInstancePort;
Jian Li7f70bb72018-07-06 23:35:30 +090099import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Li24ec59f2018-05-23 19:01:25 +0900100import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.isAssociatedWithVM;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900101import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Daniel Park81a61a12016-02-26 08:24:44 +0900102import static org.slf4j.LoggerFactory.getLogger;
103
104/**
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105 * Handle ARP requests from gateway nodes.
Daniel Park81a61a12016-02-26 08:24:44 +0900106 */
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700107@Component(immediate = true)
Daniel Park81a61a12016-02-26 08:24:44 +0900108public class OpenstackRoutingArpHandler {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900109
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700110 private final Logger log = getLogger(getClass());
Daniel Park81a61a12016-02-26 08:24:44 +0900111
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112 private static final String DEVICE_OWNER_ROUTER_GW = "network:router_gateway";
113 private static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
Jian Li60312252018-05-10 18:40:32 +0900114 private static final String ARP_MODE = "arpMode";
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected PacketService packetService;
Daniel Park81a61a12016-02-26 08:24:44 +0900121
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel park32b42202018-03-14 16:53:44 +0900123 protected OpenstackNetworkAdminService osNetworkAdminService;
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700124
Hyunsun Moon44aac662017-02-18 02:07:01 +0900125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parkeeb8e042018-02-21 14:06:58 +0900126 protected OpenstackRouterService osRouterService;
127
daniel parkeeb8e042018-02-21 14:06:58 +0900128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
daniel parke49eb382017-04-05 16:48:28 +0900129 protected OpenstackNodeService osNodeService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130
Jian Li60312252018-05-10 18:40:32 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li1064e4f2018-05-29 16:16:53 +0900132 protected InstancePortService instancePortService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li60312252018-05-10 18:40:32 +0900135 protected ClusterService clusterService;
136
137 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 protected LeadershipService leadershipService;
139
140 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
141 protected OpenstackFlowRuleService osFlowRuleService;
142
143 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Li1064e4f2018-05-29 16:16:53 +0900144 protected OpenstackNetworkService osNetworkService;
145
146 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lif3a28b02018-06-11 21:29:13 +0900147 protected ComponentConfigService configService;
Jian Li60312252018-05-10 18:40:32 +0900148
Jian Li60312252018-05-10 18:40:32 +0900149 @Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
Daniel Park6041f102018-07-06 18:49:45 +0900150 label = "ARP processing mode, broadcast | proxy (default)")
Jian Li60312252018-05-10 18:40:32 +0900151 protected String arpMode = DEFAULT_ARP_MODE_STR;
152
153 protected String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
154
155 private final OpenstackRouterListener osRouterListener = new InternalRouterEventListener();
Jian Lif96685c2018-05-21 14:14:16 +0900156 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
Jian Li24ec59f2018-05-23 19:01:25 +0900157 private final InstancePortListener instPortListener = new InternalInstancePortListener();
Jian Li60312252018-05-10 18:40:32 +0900158
Jian Lie1a39032018-06-19 21:49:36 +0900159 private final OpenstackNetworkListener osNetworkListener = new InternalOpenstackNetworkListener();
160
Jian Li60312252018-05-10 18:40:32 +0900161 private ApplicationId appId;
162 private NodeId localNodeId;
Jian Lie1a39032018-06-19 21:49:36 +0900163 private final Map<String, MacAddress> floatingIpMacMap = Maps.newConcurrentMap();
164 private final Map<String, DeviceId> migrationPool = Maps.newConcurrentMap();
165 private final Map<MacAddress, InstancePort> terminatedInstPorts = Maps.newConcurrentMap();
166 private final Map<MacAddress, InstancePort> tobeRemovedInstPorts = Maps.newConcurrentMap();
167 private final Map<String, NetFloatingIP> pendingInstPortIds = Maps.newConcurrentMap();
Jian Li60312252018-05-10 18:40:32 +0900168
Hyunsun Moon44aac662017-02-18 02:07:01 +0900169 private final ExecutorService eventExecutor = newSingleThreadExecutor(
170 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700171
Hyunsun Moon0d457362017-06-27 17:19:41 +0900172 private final PacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700173
174 @Activate
175 protected void activate() {
Jian Li60312252018-05-10 18:40:32 +0900176 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
177 configService.registerProperties(getClass());
178 localNodeId = clusterService.getLocalNode().id();
Jian Lif3a28b02018-06-11 21:29:13 +0900179 osRouterService.addListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900180 osNodeService.addListener(osNodeListener);
Jian Lie1a39032018-06-19 21:49:36 +0900181 osNetworkService.addListener(osNetworkListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900182 instancePortService.addListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900183 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700184 packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
185 log.info("Started");
Daniel Park81a61a12016-02-26 08:24:44 +0900186 }
187
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700188 @Deactivate
189 protected void deactivate() {
190 packetService.removeProcessor(packetProcessor);
Jian Lie1a39032018-06-19 21:49:36 +0900191 instancePortService.removeListener(instPortListener);
Jian Li60312252018-05-10 18:40:32 +0900192 osRouterService.removeListener(osRouterListener);
Jian Lif96685c2018-05-21 14:14:16 +0900193 osNodeService.removeListener(osNodeListener);
Jian Li24ec59f2018-05-23 19:01:25 +0900194 instancePortService.removeListener(instPortListener);
Jian Lie1a39032018-06-19 21:49:36 +0900195 osNetworkService.removeListener(osNetworkListener);
Jian Li60312252018-05-10 18:40:32 +0900196 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900197 eventExecutor.shutdown();
Jian Li60312252018-05-10 18:40:32 +0900198 configService.unregisterProperties(getClass(), false);
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700199 log.info("Stopped");
Daniel Park81a61a12016-02-26 08:24:44 +0900200 }
201
Jian Li60312252018-05-10 18:40:32 +0900202 // TODO: need to find a way to unify aprMode and gatewayMac variables with
203 // that in SwitchingArpHandler
204 @Modified
205 void modified(ComponentContext context) {
Jian Li60312252018-05-10 18:40:32 +0900206
207 log.info("Modified");
208 }
209
Jian Li7f70bb72018-07-06 23:35:30 +0900210 private String getArpMode() {
211 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
212 return getPropertyValue(properties, ARP_MODE);
213 }
214
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700215 private void processArpPacket(PacketContext context, Ethernet ethernet) {
Daniel Park81a61a12016-02-26 08:24:44 +0900216 ARP arp = (ARP) ethernet.getPayload();
Jian Li60312252018-05-10 18:40:32 +0900217
Jian Li7f70bb72018-07-06 23:35:30 +0900218 if (arp.getOpCode() == ARP.OP_REQUEST && ARP_PROXY_MODE.equals(getArpMode())) {
daniel parkb5817102018-02-15 00:18:51 +0900219 if (log.isTraceEnabled()) {
220 log.trace("ARP request received from {} for {}",
221 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
222 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
223 }
224
225 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900226
227 MacAddress targetMac = null;
228
229 NetFloatingIP floatingIP = osRouterService.floatingIps().stream()
230 .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
231 .findAny().orElse(null);
232
daniel park576969a2018-03-09 07:07:41 +0900233 //In case target ip is for associated floating ip, sets target mac to vm's.
daniel parkeeb8e042018-02-21 14:06:58 +0900234 if (floatingIP != null && floatingIP.getPortId() != null) {
Jian Li60312252018-05-10 18:40:32 +0900235 targetMac = MacAddress.valueOf(osNetworkAdminService.port(
236 floatingIP.getPortId()).getMacAddress());
daniel parkeeb8e042018-02-21 14:06:58 +0900237 }
238
239 if (isExternalGatewaySourceIp(targetIp.getIp4Address())) {
240 targetMac = Constants.DEFAULT_GATEWAY_MAC;
241 }
242
243 if (targetMac == null) {
daniel parkb5817102018-02-15 00:18:51 +0900244 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
245 return;
246 }
247
Jian Lia171a432018-06-11 11:52:11 +0900248 InstancePort instPort = instancePortService.instancePort(targetMac);
249
250 OpenstackNode gw = getGwByInstancePort(osNodeService.completeNodes(GATEWAY), instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900251
252 if (gw == null) {
253 return;
254 }
255
256 // if the ARP packet_in received from non-relevant GWs, we simply ignore it
257 if (!Objects.equals(gw.intgBridge(), context.inPacket().receivedFrom().deviceId())) {
258 return;
259 }
260
daniel parkb5817102018-02-15 00:18:51 +0900261 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
262 targetMac, ethernet);
263
264 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
daniel park576969a2018-03-09 07:07:41 +0900265 .setOutput(context.inPacket().receivedFrom().port()).build();
daniel parkb5817102018-02-15 00:18:51 +0900266
267 packetService.emit(new DefaultOutboundPacket(
268 context.inPacket().receivedFrom().deviceId(),
269 treatment,
270 ByteBuffer.wrap(ethReply.serialize())));
271
272 context.block();
Jian Li60312252018-05-10 18:40:32 +0900273 }
274
275 if (arp.getOpCode() == ARP.OP_REPLY) {
Jian Li14a79f22018-06-05 03:44:22 +0900276 ConnectPoint cp = context.inPacket().receivedFrom();
277 PortNumber receivedPortNum = cp.port();
278 IpAddress spa = Ip4Address.valueOf(arp.getSenderProtocolAddress());
279 MacAddress sha = MacAddress.valueOf(arp.getSenderHardwareAddress());
280
281 log.debug("ARP reply ip: {}, mac: {}", spa, sha);
282
daniel parkb5817102018-02-15 00:18:51 +0900283 try {
Jian Li14a79f22018-06-05 03:44:22 +0900284
Jian Lid4066ea2018-06-07 01:44:45 +0900285 Set<String> extRouterIps = osNetworkService.externalPeerRouters().
286 stream().map(r -> r.externalPeerRouterIp().toString()).collect(Collectors.toSet());
Jian Li14a79f22018-06-05 03:44:22 +0900287
Jian Lid4066ea2018-06-07 01:44:45 +0900288 // if SPA is NOT contained in existing external router IP set, we ignore it
289 if (!extRouterIps.contains(spa.toString())) {
Jian Li14a79f22018-06-05 03:44:22 +0900290 return;
291 }
292
293 OpenstackNode node = osNodeService.node(cp.deviceId());
294
295 if (node == null) {
296 return;
297 }
298
299 // we only handles the ARP-Reply message received by gateway node
300 if (node.type() != GATEWAY) {
301 return;
302 }
303
304 if (receivedPortNum.equals(node.uplinkPortNum())) {
305 osNetworkAdminService.updateExternalPeerRouterMac(spa, sha);
daniel parkb5817102018-02-15 00:18:51 +0900306 }
307 } catch (Exception e) {
Jian Li14a79f22018-06-05 03:44:22 +0900308 log.error("Exception occurred because of {}", e);
daniel parkb5817102018-02-15 00:18:51 +0900309 }
Daniel Park81a61a12016-02-26 08:24:44 +0900310 }
Daniel Park81a61a12016-02-26 08:24:44 +0900311 }
312
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700313 private class InternalPacketProcessor implements PacketProcessor {
314
315 @Override
316 public void process(PacketContext context) {
317 if (context.isHandled()) {
318 return;
Hyunsun Moon0d457362017-06-27 17:19:41 +0900319 }
320
321 Set<DeviceId> gateways = osNodeService.completeNodes(GATEWAY)
322 .stream().map(OpenstackNode::intgBridge)
323 .collect(Collectors.toSet());
324
325 if (!gateways.contains(context.inPacket().receivedFrom().deviceId())) {
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700326 // return if the packet is not from gateway nodes
327 return;
328 }
329
330 InboundPacket pkt = context.inPacket();
331 Ethernet ethernet = pkt.parsed();
332 if (ethernet != null &&
333 ethernet.getEtherType() == Ethernet.TYPE_ARP) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900334 eventExecutor.execute(() -> processArpPacket(context, ethernet));
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700335 }
336 }
337 }
338
daniel parkeeb8e042018-02-21 14:06:58 +0900339 private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
daniel park32b42202018-03-14 16:53:44 +0900340 return osNetworkAdminService.ports().stream()
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
daniel parkeeb8e042018-02-21 14:06:58 +0900342 DEVICE_OWNER_ROUTER_GW))
Hyunsun Moon44aac662017-02-18 02:07:01 +0900343 .flatMap(osPort -> osPort.getFixedIps().stream())
344 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
Kyuhwi Choi92d9ea42016-06-13 17:28:00 +0900345 }
Jian Li60312252018-05-10 18:40:32 +0900346
Jian Li60312252018-05-10 18:40:32 +0900347 private void initFloatingIpMacMap() {
348 osRouterService.floatingIps().forEach(f -> {
349 if (f.getPortId() != null && f.getFloatingIpAddress() != null) {
350 Port port = osNetworkAdminService.port(f.getPortId());
351 if (port != null && port.getMacAddress() != null) {
Jian Lif3a28b02018-06-11 21:29:13 +0900352 floatingIpMacMap.put(f.getFloatingIpAddress(),
353 MacAddress.valueOf(port.getMacAddress()));
Jian Li60312252018-05-10 18:40:32 +0900354 }
355 }
356 });
357 }
358
Jian Lie1a39032018-06-19 21:49:36 +0900359 private void initPendingInstPorts() {
360 osRouterService.floatingIps().forEach(f -> {
361 if (f.getPortId() != null) {
362 Port port = osNetworkAdminService.port(f.getPortId());
363 if (port != null) {
364 if (!Strings.isNullOrEmpty(port.getDeviceId()) &&
365 instancePortService.instancePort(f.getPortId()) == null) {
366 pendingInstPortIds.put(f.getPortId(), f);
367 }
368 }
369 }
370 });
371 }
372
Jian Li60312252018-05-10 18:40:32 +0900373 /**
374 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li1064e4f2018-05-29 16:16:53 +0900375 *
376 * @param gateway gateway node
377 * @param install flow rule installation flag
378 */
379 private void setFloatingIpArpRuleForGateway(OpenstackNode gateway, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900380 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900381
382 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
383 Set<OpenstackNode> finalGws = Sets.newConcurrentHashSet();
384 finalGws.addAll(ImmutableSet.copyOf(completedGws));
385
386 if (install) {
387 if (completedGws.contains(gateway)) {
388 if (completedGws.size() > 1) {
389 finalGws.remove(gateway);
390 osRouterService.floatingIps().forEach(fip -> {
391 if (fip.getPortId() != null) {
392 setFloatingIpArpRule(fip, finalGws, false);
393 finalGws.add(gateway);
394 }
395 });
396 }
397 osRouterService.floatingIps().forEach(fip -> {
398 if (fip.getPortId() != null) {
399 setFloatingIpArpRule(fip, finalGws, true);
400 }
401 });
402 } else {
403 log.warn("Detected node should be included in completed gateway set");
404 }
405 } else {
406 if (!completedGws.contains(gateway)) {
407 finalGws.add(gateway);
408 osRouterService.floatingIps().forEach(fip -> {
409 if (fip.getPortId() != null) {
410 setFloatingIpArpRule(fip, finalGws, false);
411 }
412 });
413 finalGws.remove(gateway);
414 if (completedGws.size() >= 1) {
415 osRouterService.floatingIps().forEach(fip -> {
416 if (fip.getPortId() != null) {
417 setFloatingIpArpRule(fip, finalGws, true);
418 }
419 });
420 }
421 } else {
422 log.warn("Detected node should NOT be included in completed gateway set");
423 }
424 }
425 }
426 }
427
428 /**
Jian Li24ec59f2018-05-23 19:01:25 +0900429 * Installs/uninstalls ARP flow rules to the corresponding gateway by
430 * looking for compute node's device ID.
431 *
432 * @param fip floating IP
433 * @param port instance port
434 * @param gateways a collection of gateways
435 * @param install install flag
436 */
437 private void setFloatingIpArpRuleWithPortEvent(NetFloatingIP fip,
438 InstancePort port,
439 Set<OpenstackNode> gateways,
440 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900441 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li24ec59f2018-05-23 19:01:25 +0900442
443 OpenstackNode gw = getGwByInstancePort(gateways, port);
444
445 if (gw == null) {
446 return;
447 }
448
449 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
450
451 setArpRule(fip, MacAddress.valueOf(macString), gw, install);
452 }
453 }
454
455 /**
Jian Li1064e4f2018-05-29 16:16:53 +0900456 * Installs static ARP rules used in ARP BROAD_CAST mode.
Jian Li60312252018-05-10 18:40:32 +0900457 * Note that, those rules will be only matched ARP_REQUEST packets,
458 * used for telling gateway node the mapped MAC address of requested IP,
459 * without the helps from controller.
460 *
461 * @param fip floating IP address
Jian Li1064e4f2018-05-29 16:16:53 +0900462 * @param gateways a set of gateway nodes
Jian Li60312252018-05-10 18:40:32 +0900463 * @param install flow rule installation flag
464 */
Jian Li1064e4f2018-05-29 16:16:53 +0900465 private synchronized void setFloatingIpArpRule(NetFloatingIP fip,
466 Set<OpenstackNode> gateways,
467 boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900468 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900469
470 if (fip == null) {
471 log.warn("Failed to set ARP broadcast rule for floating IP");
472 return;
473 }
474
Jian Lif3a28b02018-06-11 21:29:13 +0900475 MacAddress targetMac;
476 InstancePort instPort;
Jian Li60312252018-05-10 18:40:32 +0900477
478 if (install) {
479 if (fip.getPortId() != null) {
Jian Lif3a28b02018-06-11 21:29:13 +0900480 String macString = osNetworkAdminService.port(fip.getPortId()).getMacAddress();
481 targetMac = MacAddress.valueOf(macString);
482 floatingIpMacMap.put(fip.getFloatingIpAddress(), targetMac);
Jian Li60312252018-05-10 18:40:32 +0900483 } else {
484 log.trace("Unknown target ARP request for {}, ignore it",
485 fip.getFloatingIpAddress());
486 return;
487 }
488 } else {
Jian Lif3a28b02018-06-11 21:29:13 +0900489 targetMac = floatingIpMacMap.get(fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900490 }
491
Jian Lif3a28b02018-06-11 21:29:13 +0900492 instPort = instancePortService.instancePort(targetMac);
493
494 // in VM purge case, we will have null instance port
495 if (instPort == null) {
Jian Lie1a39032018-06-19 21:49:36 +0900496 instPort = tobeRemovedInstPorts.get(targetMac);
497 tobeRemovedInstPorts.remove(targetMac);
498 }
499
500 if (instPort == null) {
501 instPort = terminatedInstPorts.get(targetMac);
Jian Lif3a28b02018-06-11 21:29:13 +0900502 }
Jian Li60312252018-05-10 18:40:32 +0900503
Jian Lia171a432018-06-11 11:52:11 +0900504 OpenstackNode gw = getGwByInstancePort(gateways, instPort);
Jian Li1064e4f2018-05-29 16:16:53 +0900505
506 if (gw == null) {
507 return;
508 }
509
Jian Li24ec59f2018-05-23 19:01:25 +0900510 setArpRule(fip, targetMac, gw, install);
511 }
512 }
Jian Li60312252018-05-10 18:40:32 +0900513
Jian Li24ec59f2018-05-23 19:01:25 +0900514 private void setArpRule(NetFloatingIP fip, MacAddress targetMac,
515 OpenstackNode gateway, boolean install) {
516 TrafficSelector selector = DefaultTrafficSelector.builder()
517 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
518 .matchArpOp(ARP.OP_REQUEST)
519 .matchArpTpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
520 .build();
Jian Li60312252018-05-10 18:40:32 +0900521
Jian Li24ec59f2018-05-23 19:01:25 +0900522 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
523 .setArpOp(ARP.OP_REPLY)
524 .setArpSha(targetMac)
525 .setArpSpa(Ip4Address.valueOf(fip.getFloatingIpAddress()))
526 .setOutput(PortNumber.IN_PORT)
527 .build();
Jian Li60312252018-05-10 18:40:32 +0900528
Jian Li24ec59f2018-05-23 19:01:25 +0900529 osFlowRuleService.setRule(
530 appId,
531 gateway.intgBridge(),
532 selector,
533 treatment,
534 PRIORITY_ARP_GATEWAY_RULE,
535 GW_COMMON_TABLE,
536 install
537 );
538
539 if (install) {
540 log.info("Install ARP Rule for Floating IP {}",
541 fip.getFloatingIpAddress());
542 } else {
543 log.info("Uninstall ARP Rule for Floating IP {}",
544 fip.getFloatingIpAddress());
Jian Li60312252018-05-10 18:40:32 +0900545 }
546 }
547
548 /**
549 * An internal router event listener, intended to install/uninstall
550 * ARP rules for forwarding packets created from floating IPs.
551 */
552 private class InternalRouterEventListener implements OpenstackRouterListener {
553
554 @Override
555 public boolean isRelevant(OpenstackRouterEvent event) {
556 // do not allow to proceed without leadership
557 NodeId leader = leadershipService.getLeader(appId.name());
558 return Objects.equals(localNodeId, leader);
559 }
560
561 @Override
562 public void event(OpenstackRouterEvent event) {
Jian Li1064e4f2018-05-29 16:16:53 +0900563
564 Set<OpenstackNode> completedGws = osNodeService.completeNodes(GATEWAY);
565
Jian Li60312252018-05-10 18:40:32 +0900566 switch (event.type()) {
567 case OPENSTACK_ROUTER_CREATED:
568 eventExecutor.execute(() ->
569 // add a router with external gateway
570 setFakeGatewayArpRule(event.subject(), true)
571 );
572 break;
573 case OPENSTACK_ROUTER_REMOVED:
574 eventExecutor.execute(() ->
575 // remove a router with external gateway
576 setFakeGatewayArpRule(event.subject(), false)
577 );
578 break;
579 case OPENSTACK_ROUTER_GATEWAY_ADDED:
580 eventExecutor.execute(() ->
581 // add a gateway manually after adding a router
582 setFakeGatewayArpRule(event.externalGateway(), true)
583 );
584 break;
585 case OPENSTACK_ROUTER_GATEWAY_REMOVED:
586 eventExecutor.execute(() ->
587 // remove a gateway from an existing router
588 setFakeGatewayArpRule(event.externalGateway(), false)
589 );
590 break;
591 case OPENSTACK_FLOATING_IP_ASSOCIATED:
Jian Lie1a39032018-06-19 21:49:36 +0900592
593 if (instancePortService.instancePort(event.portId()) == null) {
594 log.info("Try to associate the fip {} with a terminated VM",
595 event.floatingIp().getFloatingIpAddress());
596 pendingInstPortIds.put(event.portId(), event.floatingIp());
597 return;
598 }
599
Jian Li60312252018-05-10 18:40:32 +0900600 eventExecutor.execute(() ->
601 // associate a floating IP with an existing VM
Jian Li1064e4f2018-05-29 16:16:53 +0900602 setFloatingIpArpRule(event.floatingIp(), completedGws, true)
Jian Li60312252018-05-10 18:40:32 +0900603 );
604 break;
605 case OPENSTACK_FLOATING_IP_DISASSOCIATED:
Jian Lie1a39032018-06-19 21:49:36 +0900606
607 MacAddress mac = floatingIpMacMap.get(event.floatingIp().getFloatingIpAddress());
608
609 if (mac != null && !tobeRemovedInstPorts.containsKey(mac) &&
610 terminatedInstPorts.containsKey(mac)) {
611 tobeRemovedInstPorts.put(mac, terminatedInstPorts.get(mac));
612 }
613
614 if (instancePortService.instancePort(event.portId()) == null) {
615
616 if (pendingInstPortIds.containsKey(event.portId())) {
617 log.info("Try to disassociate the fip {} with a terminated VM",
618 event.floatingIp().getFloatingIpAddress());
619 pendingInstPortIds.remove(event.portId());
620 return;
621 }
622 }
623
Jian Li60312252018-05-10 18:40:32 +0900624 eventExecutor.execute(() ->
625 // disassociate a floating IP with the existing VM
Jian Li1064e4f2018-05-29 16:16:53 +0900626 setFloatingIpArpRule(event.floatingIp(), completedGws, false)
Jian Li60312252018-05-10 18:40:32 +0900627 );
628 break;
629 case OPENSTACK_FLOATING_IP_CREATED:
630 eventExecutor.execute(() -> {
631 NetFloatingIP osFip = event.floatingIp();
632
633 // during floating IP creation, if the floating IP is
634 // associated with any port of VM, then we will set
635 // floating IP related ARP rules to gateway node
636 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900637 setFloatingIpArpRule(osFip, completedGws, true);
Jian Li60312252018-05-10 18:40:32 +0900638 }
639 });
640 break;
641 case OPENSTACK_FLOATING_IP_REMOVED:
642 eventExecutor.execute(() -> {
643 NetFloatingIP osFip = event.floatingIp();
644
645 // during floating IP deletion, if the floating IP is
646 // still associated with any port of VM, then we will
647 // remove floating IP related ARP rules from gateway node
648 if (!Strings.isNullOrEmpty(osFip.getPortId())) {
Jian Li1064e4f2018-05-29 16:16:53 +0900649 setFloatingIpArpRule(event.floatingIp(), completedGws, false);
Jian Li60312252018-05-10 18:40:32 +0900650 }
651 });
652 break;
653 default:
654 // do nothing for the other events
655 break;
656 }
657 }
658
Jian Li4df657b2018-05-29 16:39:00 +0900659 private Set<IP> getExternalGatewaySnatIps(ExternalGateway extGw) {
660 return osNetworkAdminService.ports().stream()
661 .filter(port ->
662 Objects.equals(port.getNetworkId(), extGw.getNetworkId()))
663 .filter(port ->
664 Objects.equals(port.getDeviceOwner(), DEVICE_OWNER_ROUTER_GW))
665 .flatMap(port -> port.getFixedIps().stream())
666 .collect(Collectors.toSet());
667 }
668
Jian Li60312252018-05-10 18:40:32 +0900669 private void setFakeGatewayArpRule(ExternalGateway extGw, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900670 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li60312252018-05-10 18:40:32 +0900671
672 if (extGw == null) {
673 return;
674 }
675
Jian Li4df657b2018-05-29 16:39:00 +0900676 Set<IP> ips = getExternalGatewaySnatIps(extGw);
Jian Li60312252018-05-10 18:40:32 +0900677
Jian Li4df657b2018-05-29 16:39:00 +0900678 ips.forEach(ip -> {
679 TrafficSelector selector = DefaultTrafficSelector.builder()
680 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
681 .matchArpOp(ARP.OP_REQUEST)
682 .matchArpTpa(Ip4Address.valueOf(ip.getIpAddress()))
683 .build();
Jian Li60312252018-05-10 18:40:32 +0900684
Jian Li4df657b2018-05-29 16:39:00 +0900685 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
686 .setArpOp(ARP.OP_REPLY)
687 .setArpSha(MacAddress.valueOf(gatewayMac))
688 .setArpSpa(Ip4Address.valueOf(ip.getIpAddress()))
689 .setOutput(PortNumber.IN_PORT)
690 .build();
Jian Li60312252018-05-10 18:40:32 +0900691
Jian Li4df657b2018-05-29 16:39:00 +0900692 osNodeService.completeNodes(GATEWAY).forEach(n ->
693 osFlowRuleService.setRule(
694 appId,
695 n.intgBridge(),
696 selector,
697 treatment,
698 PRIORITY_ARP_GATEWAY_RULE,
699 GW_COMMON_TABLE,
700 install
701 )
702 );
Jian Li60312252018-05-10 18:40:32 +0900703
Jian Li4df657b2018-05-29 16:39:00 +0900704 if (install) {
705 log.info("Install ARP Rule for Gateway Snat {}", ip.getIpAddress());
706 } else {
707 log.info("Uninstall ARP Rule for Gateway Snat {}", ip.getIpAddress());
708 }
709 });
Jian Li60312252018-05-10 18:40:32 +0900710 }
711 }
712
713 private void setFakeGatewayArpRule(Router router, boolean install) {
714 setFakeGatewayArpRule(router.getExternalGatewayInfo(), install);
715 }
716 }
717
Jian Lie1a39032018-06-19 21:49:36 +0900718 private class InternalInstancePortListener implements InstancePortListener {
Jian Li60312252018-05-10 18:40:32 +0900719
720 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900721 public boolean isRelevant(InstancePortEvent event) {
722 // do not allow to proceed without leadership
723 NodeId leader = leadershipService.getLeader(appId.name());
724 return Objects.equals(localNodeId, leader);
Jian Li60312252018-05-10 18:40:32 +0900725 }
726
727 @Override
Jian Lie1a39032018-06-19 21:49:36 +0900728 public void event(InstancePortEvent event) {
729 InstancePort instPort = event.subject();
730
731 Set<NetFloatingIP> ips = osRouterService.floatingIps();
732 NetFloatingIP fip = associatedFloatingIp(instPort, ips);
733 Set<OpenstackNode> gateways = osNodeService.completeNodes(GATEWAY);
734
Jian Li60312252018-05-10 18:40:32 +0900735 switch (event.type()) {
Jian Lie1a39032018-06-19 21:49:36 +0900736 case OPENSTACK_INSTANCE_PORT_DETECTED:
737 terminatedInstPorts.remove(instPort.macAddress());
738
739 if (pendingInstPortIds.containsKey(instPort.portId())) {
740 Set<OpenstackNode> completedGws =
741 osNodeService.completeNodes(GATEWAY);
742 setFloatingIpArpRule(pendingInstPortIds.get(instPort.portId()),
743 completedGws, true);
744 pendingInstPortIds.remove(instPort.portId());
745 }
746
Jian Li60312252018-05-10 18:40:32 +0900747 break;
Jian Lie1a39032018-06-19 21:49:36 +0900748
749 case OPENSTACK_INSTANCE_PORT_VANISHED:
750 terminatedInstPorts.put(instPort.macAddress(), instPort);
751 break;
752
753 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
754
755 if (gateways.size() == 1) {
756 return;
757 }
758
759 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
760 migrationPool.put(fip.getFloatingIpAddress(), event.subject().deviceId());
761
762 eventExecutor.execute(() -> {
763 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
764 gateways, true);
765 });
766 }
767
768 break;
769 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
770
771 if (gateways.size() == 1) {
772 return;
773 }
774
775 if (fip != null && isAssociatedWithVM(osNetworkService, fip)) {
776 DeviceId newDeviceId = migrationPool.get(fip.getFloatingIpAddress());
777 DeviceId oldDeviceId = event.subject().deviceId();
778 migrationPool.remove(fip.getFloatingIpAddress());
779
780 OpenstackNode oldGw = getGwByComputeDevId(gateways, oldDeviceId);
781 OpenstackNode newGw = getGwByComputeDevId(gateways, newDeviceId);
782
783 if (oldGw != null && oldGw.equals(newGw)) {
784 return;
785 }
786
787 eventExecutor.execute(() ->
788 setFloatingIpArpRuleWithPortEvent(fip, event.subject(),
789 gateways, false));
790 }
791 break;
Jian Li60312252018-05-10 18:40:32 +0900792 default:
793 break;
794 }
795 }
Jian Lie1a39032018-06-19 21:49:36 +0900796 }
Jian Li60312252018-05-10 18:40:32 +0900797
Jian Lie1a39032018-06-19 21:49:36 +0900798 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
799
800 @Override
801 public boolean isRelevant(OpenstackNetworkEvent event) {
802 // do not allow to proceed without leadership
803 NodeId leader = leadershipService.getLeader(appId.name());
804 return Objects.equals(localNodeId, leader);
Jian Li60312252018-05-10 18:40:32 +0900805 }
806
Jian Lie1a39032018-06-19 21:49:36 +0900807 @Override
808 public void event(OpenstackNetworkEvent event) {
809 switch (event.type()) {
810 case OPENSTACK_PORT_REMOVED:
811 Port osPort = event.port();
812 MacAddress mac = MacAddress.valueOf(osPort.getMacAddress());
813 if (terminatedInstPorts.containsKey(mac)) {
814 tobeRemovedInstPorts.put(mac, terminatedInstPorts.get(mac));
815 terminatedInstPorts.remove(mac);
816 }
817 break;
818 default:
819 break;
820 }
Jian Li60312252018-05-10 18:40:32 +0900821 }
822 }
Jian Lif96685c2018-05-21 14:14:16 +0900823
824 private class InternalNodeEventListener implements OpenstackNodeListener {
825
826 @Override
827 public boolean isRelevant(OpenstackNodeEvent event) {
828 // do not allow to proceed without leadership
829 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900830 return Objects.equals(localNodeId, leader) && event.subject().type() == GATEWAY;
Jian Lif96685c2018-05-21 14:14:16 +0900831 }
832
833 @Override
834 public void event(OpenstackNodeEvent event) {
835 OpenstackNode osNode = event.subject();
836 switch (event.type()) {
837 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900838 setDefaultArpRule(osNode, true);
839 setFloatingIpArpRuleForGateway(osNode, true);
Jian Li1064e4f2018-05-29 16:16:53 +0900840
Jian Lif3a28b02018-06-11 21:29:13 +0900841 // initialize FloatingIp to Mac map
842 initFloatingIpMacMap();
843
Jian Lie1a39032018-06-19 21:49:36 +0900844 // initialize pendingInstPorts
845 initPendingInstPorts();
846
Jian Lif96685c2018-05-21 14:14:16 +0900847 break;
848 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900849 setDefaultArpRule(osNode, false);
850 setFloatingIpArpRuleForGateway(osNode, false);
Jian Lif96685c2018-05-21 14:14:16 +0900851 break;
852 default:
853 break;
854 }
855 }
856
857 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900858 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900859 case ARP_PROXY_MODE:
860 setDefaultArpRuleForProxyMode(osNode, install);
861 break;
862 case ARP_BROADCAST_MODE:
863 setDefaultArpRuleForBroadcastMode(osNode, install);
864 break;
865 default:
866 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900867 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900868 break;
869 }
870 }
871
872 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
873 TrafficSelector selector = DefaultTrafficSelector.builder()
874 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
875 .build();
876
877 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
878 .punt()
879 .build();
880
881 osFlowRuleService.setRule(
882 appId,
883 osNode.intgBridge(),
884 selector,
885 treatment,
886 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900887 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900888 install
889 );
890 }
891
892 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
893 // we only match ARP_REPLY in gateway node, because controller
894 // somehow need to process ARP_REPLY which is issued from
895 // external router...
896 TrafficSelector selector = DefaultTrafficSelector.builder()
897 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
898 .matchArpOp(ARP.OP_REPLY)
899 .build();
900
901 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
902 .punt()
903 .build();
904
905 osFlowRuleService.setRule(
906 appId,
907 osNode.intgBridge(),
908 selector,
909 treatment,
910 PRIORITY_ARP_CONTROL_RULE,
Jian Li8abf2fe2018-06-12 18:42:30 +0900911 GW_COMMON_TABLE,
Jian Lif96685c2018-05-21 14:14:16 +0900912 install
913 );
914 }
915 }
Daniel Park81a61a12016-02-26 08:24:44 +0900916}