blob: 4fcd6bd5a9a944c5e686e30ff4b5eda8b4699d43 [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
18import com.google.common.base.Strings;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import com.google.common.collect.Sets;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070020import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090021import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070022import org.onlab.packet.Ethernet;
23import org.onlab.packet.Ip4Address;
24import org.onlab.packet.IpAddress;
25import org.onlab.packet.MacAddress;
26import 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 Lieae12362018-04-10 18:48:32 +090034import org.onosproject.mastership.MastershipService;
35import org.onosproject.net.PortNumber;
36import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090037import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070038import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090039import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070040import org.onosproject.net.flow.TrafficTreatment;
41import org.onosproject.net.packet.DefaultOutboundPacket;
42import org.onosproject.net.packet.PacketContext;
43import org.onosproject.net.packet.PacketProcessor;
44import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090046import org.onosproject.openstacknetworking.api.InstancePortEvent;
47import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090048import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090049import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
51import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
52import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090053import org.onosproject.openstacknode.api.OpenstackNode;
54import org.onosproject.openstacknode.api.OpenstackNodeEvent;
55import org.onosproject.openstacknode.api.OpenstackNodeListener;
56import org.onosproject.openstacknode.api.OpenstackNodeService;
57import org.openstack4j.model.network.Network;
58import org.openstack4j.model.network.NetworkType;
Hyunsun Moon44aac662017-02-18 02:07:01 +090059import org.openstack4j.model.network.Subnet;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070060import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Modified;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070067import org.slf4j.Logger;
68import org.slf4j.LoggerFactory;
Hyunsun Moon44aac662017-02-18 02:07:01 +090069
Hyunsun Moonb974fca2016-06-30 21:20:39 -070070import java.nio.ByteBuffer;
71import java.util.Dictionary;
Jian Lieae12362018-04-10 18:48:32 +090072import java.util.Objects;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070073import java.util.Set;
74
75import static com.google.common.base.Preconditions.checkNotNull;
Jian Lieae12362018-04-10 18:48:32 +090076import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
77import static org.onosproject.openstacknetworking.api.Constants.ARP_PROXY_MODE;
78import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_ARP_MODE_STR;
Hyunsun Moon44aac662017-02-18 02:07:01 +090079import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
Jian Lieae12362018-04-10 18:48:32 +090080import static org.onosproject.openstacknetworking.api.Constants.DHCP_ARP_TABLE;
Hyunsun Moon44aac662017-02-18 02:07:01 +090081import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Lieae12362018-04-10 18:48:32 +090082import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_CONTROL_RULE;
83import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
84import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
85import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
86import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_SUBNET_RULE;
Jian Lic2403592018-07-18 12:56:45 +090087import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Jian Li7f70bb72018-07-06 23:35:30 +090088import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
Jian Liec5c32b2018-07-13 14:28:58 +090089import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
Jian Lieae12362018-04-10 18:48:32 +090090import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
91import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070092
93/**
94 * Handles ARP packet from VMs.
95 */
96@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090097public final class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -070098
99 private final Logger log = LoggerFactory.getLogger(getClass());
100
101 private static final String GATEWAY_MAC = "gatewayMac";
Jian Lieae12362018-04-10 18:48:32 +0900102 private static final String ARP_MODE = "arpMode";
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800105 CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800108 PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700109
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900111 OpenstackFlowRuleService osFlowRuleService;
112
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700113 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800114 ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900115
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900117 ClusterService clusterService;
118
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700119 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900120 LeadershipService leadershipService;
121
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700122 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900123 DeviceService deviceService;
124
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700125 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900126 MastershipService mastershipService;
127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800129 InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800132 OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jian Lieae12362018-04-10 18:48:32 +0900135 protected OpenstackNodeService osNodeService;
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 //@Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
138 // label = "Fake MAC address for virtual network subnet gateway")
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700139 private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 //@Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
142 // label = "ARP processing mode, broadcast | proxy (default)")
Jian Lieae12362018-04-10 18:48:32 +0900143 protected String arpMode = DEFAULT_ARP_MODE_STR;
144
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700145 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900146 private final InternalOpenstackNetworkListener osNetworkListener =
147 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900148 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
149 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
150
Hyunsun Moon44aac662017-02-18 02:07:01 +0900151
152 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900153 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700154
155 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800156 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900157 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
158 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900159 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900160 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900161 osNodeService.addListener(osNodeListener);
162 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700163 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900164
165 instancePortService.addListener(instancePortListener);
166
Hyunsun Moon44aac662017-02-18 02:07:01 +0900167 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700168 }
169
170 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800171 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700172 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900173 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900174 osNodeService.removeListener(osNodeListener);
175 instancePortService.removeListener(instancePortListener);
176 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900177 configService.unregisterProperties(getClass(), false);
178
179 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700180 }
181
182 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800183 void modified(ComponentContext context) {
Jian Li7f70bb72018-07-06 23:35:30 +0900184 readComponentConfiguration(context);
Jian Lieae12362018-04-10 18:48:32 +0900185
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700186 log.info("Modified");
187 }
188
Jian Li7f70bb72018-07-06 23:35:30 +0900189 private String getArpMode() {
190 Set<ConfigProperty> properties = configService.getProperties(this.getClass().getName());
191 return getPropertyValue(properties, ARP_MODE);
192 }
193
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700194 /**
195 * Processes ARP request packets.
196 * It checks if the target IP is owned by a known host first and then ask to
197 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
198 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900199 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700200 * @param ethPacket ethernet packet
201 */
202 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900203
204 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
Jian Li7f70bb72018-07-06 23:35:30 +0900205 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900206 return;
207 }
208
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700209 ARP arpPacket = (ARP) ethPacket.getPayload();
210 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
211 return;
212 }
213
Hyunsun Moon44aac662017-02-18 02:07:01 +0900214 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
215 if (srcInstPort == null) {
216 log.trace("Failed to find source instance port(MAC:{})",
217 ethPacket.getSourceMAC());
218 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700219 }
220
Hyunsun Moon44aac662017-02-18 02:07:01 +0900221 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
Daniel Park4d7f88b2018-09-19 19:03:38 +0900222
223 MacAddress replyMac = gatewayIp(targetIp) ? MacAddress.valueOf(gatewayMac) :
Hyunsun Moon44aac662017-02-18 02:07:01 +0900224 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700225 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700227 return;
228 }
229
230 Ethernet ethReply = ARP.buildArpReply(
231 targetIp.getIp4Address(),
232 replyMac,
233 ethPacket);
234
235 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
236 .setOutput(context.inPacket().receivedFrom().port())
237 .build();
238
239 packetService.emit(new DefaultOutboundPacket(
240 context.inPacket().receivedFrom().deviceId(),
241 treatment,
242 ByteBuffer.wrap(ethReply.serialize())));
243 }
244
Daniel Park4d7f88b2018-09-19 19:03:38 +0900245 private boolean gatewayIp(IpAddress targetIp) {
246 return osNetworkService.subnets().stream()
247 .anyMatch(subnet -> subnet.getGateway().equals(targetIp.toString()));
248 }
249
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700250 /**
251 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900252 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700253 *
254 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255 * @param osNetId openstack network id of the source instance port
256 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700257 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900258 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700259 checkNotNull(targetIp);
260
Hyunsun Moon44aac662017-02-18 02:07:01 +0900261 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
262 if (instPort != null) {
263 log.trace("Found MAC from host service for {}", targetIp);
264 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700265 } else {
266 return MacAddress.NONE;
267 }
268 }
269
Jian Lieae12362018-04-10 18:48:32 +0900270 /**
Daniel Park613ac372018-06-28 14:30:11 +0900271 * Installs flow rules which convert ARP request packet into ARP reply
272 * by adding a fake gateway MAC address as Source Hardware Address.
273 *
274 * @param osSubnet openstack subnet
275 * @param install flag which indicates whether to install rule or remove rule
276 */
277 private void setFakeGatewayArpRule(Subnet osSubnet, boolean install, OpenstackNode osNode) {
278
Jian Li7f70bb72018-07-06 23:35:30 +0900279 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Daniel Park613ac372018-06-28 14:30:11 +0900280 String gateway = osSubnet.getGateway();
281
282 TrafficSelector selector = DefaultTrafficSelector.builder()
283 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
284 .matchArpOp(ARP.OP_REQUEST)
285 .matchArpTpa(Ip4Address.valueOf(gateway))
286 .build();
287
288 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
289 .setArpOp(ARP.OP_REPLY)
290 .setArpSha(MacAddress.valueOf(gatewayMac))
291 .setArpSpa(Ip4Address.valueOf(gateway))
292 .setOutput(PortNumber.IN_PORT)
293 .build();
294
295 if (osNode == null) {
296 osNodeService.completeNodes(COMPUTE).forEach(n ->
297 osFlowRuleService.setRule(
298 appId,
299 n.intgBridge(),
300 selector,
301 treatment,
302 PRIORITY_ARP_GATEWAY_RULE,
303 DHCP_ARP_TABLE,
304 install
305 )
306 );
307 } else {
308 osFlowRuleService.setRule(
309 appId,
310 osNode.intgBridge(),
311 selector,
312 treatment,
313 PRIORITY_ARP_GATEWAY_RULE,
314 DHCP_ARP_TABLE,
315 install
316 );
317 }
318
319 }
320 }
321
322 /**
Jian Li7f70bb72018-07-06 23:35:30 +0900323 * Installs flow rules to match ARP request packets.
324 *
325 * @param port instance port
326 * @param install installation flag
327 */
328 private void setArpRequestRule(InstancePort port, boolean install) {
329 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
330
331 switch (type) {
332 case VXLAN:
333 setRemoteArpRequestRuleForVxlan(port, install);
334 break;
335 case VLAN:
336 // since VLAN ARP packet can be broadcasted to all hosts that connected with L2 network,
337 // there is no need to add any flow rules to handle ARP request
338 break;
339 default:
340 break;
341 }
342 }
343
344 /**
345 * Installs flow rules to match ARP reply packets.
346 *
347 * @param port instance port
348 * @param install installation flag
349 */
350 private void setArpReplyRule(InstancePort port, boolean install) {
351 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
352
353 switch (type) {
354 case VXLAN:
355 setArpReplyRuleForVxlan(port, install);
356 break;
357 case VLAN:
358 setArpReplyRuleForVlan(port, install);
359 break;
360 default:
361 break;
362 }
363 }
364
365 /**
366 * Installs flow rules to match ARP request packets only for VxLAN.
367 *
368 * @param port instance port
369 * @param install installation flag
370 */
371 private void setRemoteArpRequestRuleForVxlan(InstancePort port, boolean install) {
372
373 OpenstackNode localNode = osNodeService.node(port.deviceId());
374
375 TrafficSelector selector = DefaultTrafficSelector.builder()
376 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
377 .matchArpOp(ARP.OP_REQUEST)
378 .matchArpTpa(port.ipAddress().getIp4Address())
379 .build();
380
381 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
382 }
383
384 /**
385 * Installs flow rules to match ARP reply packets only for VxLAN.
386 *
387 * @param port instance port
388 * @param install installation flag
389 */
390 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
391
392 OpenstackNode localNode = osNodeService.node(port.deviceId());
393
394 TrafficSelector selector = setArpReplyRuleForVnet(port, install);
395 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
396 }
397
398 /**
399 * Installs flow rules to match ARP reply packets only for VLAN.
400 *
401 * @param port instance port
402 * @param install installation flag
403 */
404 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
405
406 TrafficSelector selector = setArpReplyRuleForVnet(port, install);
407 setRemoteArpTreatmentForVlan(selector, port, install);
408 }
409
410 // a helper method
411 private TrafficSelector setArpReplyRuleForVnet(InstancePort port, boolean install) {
412 TrafficSelector selector = DefaultTrafficSelector.builder()
413 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
414 .matchArpOp(ARP.OP_REPLY)
415 .matchArpTpa(port.ipAddress().getIp4Address())
416 .matchArpTha(port.macAddress())
417 .build();
418
419 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
420 .setOutput(port.portNumber())
421 .build();
422
423 osFlowRuleService.setRule(
424 appId,
425 port.deviceId(),
426 selector,
427 treatment,
428 PRIORITY_ARP_REPLY_RULE,
429 DHCP_ARP_TABLE,
430 install
431 );
432
433 return selector;
434 }
435
436 // a helper method
437 private void setRemoteArpTreatmentForVxlan(TrafficSelector selector,
438 InstancePort port,
439 OpenstackNode localNode,
440 boolean install) {
441 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
442 if (!remoteNode.intgBridge().equals(port.deviceId())) {
443 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
444 .extension(buildExtension(
445 deviceService,
446 remoteNode.intgBridge(),
447 localNode.dataIp().getIp4Address()),
448 remoteNode.intgBridge())
449 .setOutput(remoteNode.tunnelPortNum())
450 .build();
451
452 osFlowRuleService.setRule(
453 appId,
454 remoteNode.intgBridge(),
455 selector,
456 treatmentToRemote,
457 PRIORITY_ARP_REQUEST_RULE,
458 DHCP_ARP_TABLE,
459 install
460 );
461 }
462 }
463 }
464
465 // a helper method
466 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
467 InstancePort port,
468 boolean install) {
469 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
470 if (!remoteNode.intgBridge().equals(port.deviceId()) && remoteNode.vlanIntf() != null) {
471 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
472 .setOutput(remoteNode.vlanPortNum())
473 .build();
474
475 osFlowRuleService.setRule(
476 appId,
477 remoteNode.intgBridge(),
478 selector,
479 treatmentToRemote,
480 PRIORITY_ARP_REQUEST_RULE,
481 DHCP_ARP_TABLE,
482 install);
483 }
484 }
485 }
486
487 /**
488 * Extracts properties from the component configuration context.
489 *
490 * @param context the component context
491 */
492 private void readComponentConfiguration(ComponentContext context) {
493 Dictionary<?, ?> properties = context.getProperties();
494
495 String updatedMac = Tools.get(properties, GATEWAY_MAC);
496 gatewayMac = updatedMac != null ? updatedMac : DEFAULT_GATEWAY_MAC_STR;
497 log.info("Configured. Gateway MAC is {}", gatewayMac);
498 }
499
500 /**
Jian Lieae12362018-04-10 18:48:32 +0900501 * An internal packet processor which processes ARP request, and results in
502 * packet-out ARP reply.
503 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700504 private class InternalPacketProcessor implements PacketProcessor {
505
506 @Override
507 public void process(PacketContext context) {
508 if (context.isHandled()) {
509 return;
510 }
511
512 Ethernet ethPacket = context.inPacket().parsed();
513 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
514 return;
515 }
516 processPacketIn(context, ethPacket);
517 }
518 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900519
Jian Lieae12362018-04-10 18:48:32 +0900520 /**
521 * An internal network listener which listens to openstack network event,
522 * manages the gateway collection and installs flow rule that handles
523 * ARP request in data plane.
524 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900525 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
526
527 @Override
528 public boolean isRelevant(OpenstackNetworkEvent event) {
529 Subnet osSubnet = event.subnet();
530 if (osSubnet == null) {
531 return false;
532 }
Jian Lieae12362018-04-10 18:48:32 +0900533
Jian Libb4f5412018-04-12 09:48:50 +0900534 Network network = osNetworkService.network(osSubnet.getNetworkId());
535
Jian Lieae12362018-04-10 18:48:32 +0900536 if (network == null) {
537 log.warn("Network is not specified.");
538 return false;
539 } else {
540 if (network.getNetworkType().equals(NetworkType.FLAT)) {
541 return false;
542 }
543 }
544
545 // do not allow to proceed without leadership
546 NodeId leader = leadershipService.getLeader(appId.name());
547 if (!Objects.equals(localNodeId, leader)) {
548 return false;
549 }
550
Hyunsun Moon44aac662017-02-18 02:07:01 +0900551 return !Strings.isNullOrEmpty(osSubnet.getGateway());
552 }
553
554 @Override
555 public void event(OpenstackNetworkEvent event) {
556 switch (event.type()) {
557 case OPENSTACK_SUBNET_CREATED:
558 case OPENSTACK_SUBNET_UPDATED:
Daniel Park613ac372018-06-28 14:30:11 +0900559 setFakeGatewayArpRule(event.subnet(), true, null);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900560 break;
561 case OPENSTACK_SUBNET_REMOVED:
Daniel Park613ac372018-06-28 14:30:11 +0900562 setFakeGatewayArpRule(event.subnet(), false, null);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900563 break;
564 case OPENSTACK_NETWORK_CREATED:
565 case OPENSTACK_NETWORK_UPDATED:
566 case OPENSTACK_NETWORK_REMOVED:
567 case OPENSTACK_PORT_CREATED:
568 case OPENSTACK_PORT_UPDATED:
569 case OPENSTACK_PORT_REMOVED:
570 default:
571 // do nothing for the other events
572 break;
573 }
574 }
Jian Lieae12362018-04-10 18:48:32 +0900575 }
576
577 /**
578 * An internal openstack node listener which is used for listening openstack
579 * node activity. As long as a node is in complete state, we will install
580 * default ARP rule to handle ARP request.
581 */
582 private class InternalNodeEventListener implements OpenstackNodeListener {
583
584 @Override
585 public boolean isRelevant(OpenstackNodeEvent event) {
Jian Lif7934d52018-07-10 16:27:02 +0900586
Jian Lieae12362018-04-10 18:48:32 +0900587 // do not allow to proceed without leadership
588 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900589 return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
Jian Lieae12362018-04-10 18:48:32 +0900590 }
591
592 @Override
593 public void event(OpenstackNodeEvent event) {
594 OpenstackNode osNode = event.subject();
595 switch (event.type()) {
596 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900597 setDefaultArpRule(osNode, true);
Jian Li5b66ce02018-07-09 22:43:54 +0900598 setAllArpRules(osNode, true);
Jian Lieae12362018-04-10 18:48:32 +0900599 break;
600 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900601 setDefaultArpRule(osNode, false);
Jian Li5b66ce02018-07-09 22:43:54 +0900602 setAllArpRules(osNode, false);
Jian Lieae12362018-04-10 18:48:32 +0900603 break;
Jian Lieae12362018-04-10 18:48:32 +0900604 default:
605 break;
606 }
607 }
608
Jian Lif96685c2018-05-21 14:14:16 +0900609 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
Jian Libcc42282018-09-13 20:59:34 +0900610
611 if (getArpMode() == null) {
612 return;
613 }
614
Jian Li7f70bb72018-07-06 23:35:30 +0900615 switch (getArpMode()) {
Jian Lif96685c2018-05-21 14:14:16 +0900616 case ARP_PROXY_MODE:
617 setDefaultArpRuleForProxyMode(osNode, install);
618 break;
619 case ARP_BROADCAST_MODE:
620 setDefaultArpRuleForBroadcastMode(osNode, install);
Jian Lie2e03a52018-07-05 23:35:02 +0900621
622 // we do not add fake gateway ARP rules for FLAT network
623 // ARP packets generated by FLAT typed VM should not be
624 // delegated to switch to handle
625 osNetworkService.subnets().stream().filter(subnet ->
626 osNetworkService.network(subnet.getNetworkId()) != null &&
627 osNetworkService.network(subnet.getNetworkId())
Jian Li7f70bb72018-07-06 23:35:30 +0900628 .getNetworkType() != NetworkType.FLAT)
Jian Lie2e03a52018-07-05 23:35:02 +0900629 .forEach(subnet ->
630 setFakeGatewayArpRule(subnet, install, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900631 break;
632 default:
633 log.warn("Invalid ARP mode {}. Please use either " +
Jian Li7f70bb72018-07-06 23:35:30 +0900634 "broadcast or proxy mode.", getArpMode());
Jian Lif96685c2018-05-21 14:14:16 +0900635 break;
Jian Lieae12362018-04-10 18:48:32 +0900636 }
637 }
Jian Lif96685c2018-05-21 14:14:16 +0900638
639 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
640 TrafficSelector selector = DefaultTrafficSelector.builder()
641 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
642 .build();
643
644 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
645 .punt()
646 .build();
647
648 osFlowRuleService.setRule(
649 appId,
650 osNode.intgBridge(),
651 selector,
652 treatment,
653 PRIORITY_ARP_CONTROL_RULE,
654 DHCP_ARP_TABLE,
655 install
656 );
657 }
658
659 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
660 TrafficSelector selector = DefaultTrafficSelector.builder()
661 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
662 .matchArpOp(ARP.OP_REQUEST)
663 .build();
664
665 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
666 .setOutput(PortNumber.FLOOD)
667 .build();
668
669 osFlowRuleService.setRule(
670 appId,
671 osNode.intgBridge(),
672 selector,
673 treatment,
674 PRIORITY_ARP_SUBNET_RULE,
675 DHCP_ARP_TABLE,
676 install
677 );
678 }
Jian Li7f70bb72018-07-06 23:35:30 +0900679
Jian Li5b66ce02018-07-09 22:43:54 +0900680 private void setAllArpRules(OpenstackNode osNode, boolean install) {
Jian Li7f70bb72018-07-06 23:35:30 +0900681 if (ARP_BROADCAST_MODE.equals(getArpMode())) {
Jian Li5b66ce02018-07-09 22:43:54 +0900682 instancePortService.instancePorts().stream()
Jian Lic2403592018-07-18 12:56:45 +0900683 .filter(p -> p.state() == ACTIVE)
Jian Li5b66ce02018-07-09 22:43:54 +0900684 .filter(p -> p.deviceId().equals(osNode.intgBridge()))
685 .forEach(p -> {
686 setArpRequestRule(p, install);
687 setArpReplyRule(p, install);
Jian Li7f70bb72018-07-06 23:35:30 +0900688 });
689 }
690 }
Jian Lieae12362018-04-10 18:48:32 +0900691 }
692
693 /**
694 * An internal instance port listener which listens the port events generated
695 * from VM. When ARP a host which located in a remote compute node, we specify
696 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
697 * host IP address. When ARP a host which located in a local compute node,
698 * we specify only ARP OP mode as REQUEST.
699 */
700 private class InternalInstancePortListener implements InstancePortListener {
701
702 @Override
703 public boolean isRelevant(InstancePortEvent event) {
704
Jian Li7f70bb72018-07-06 23:35:30 +0900705 if (ARP_PROXY_MODE.equals(getArpMode())) {
Jian Lieae12362018-04-10 18:48:32 +0900706 return false;
707 }
708
709 InstancePort instPort = event.subject();
710 return mastershipService.isLocalMaster(instPort.deviceId());
711 }
712
713 @Override
714 public void event(InstancePortEvent event) {
715 switch (event.type()) {
Jian Lieae12362018-04-10 18:48:32 +0900716 case OPENSTACK_INSTANCE_PORT_DETECTED:
Jian Liec5c32b2018-07-13 14:28:58 +0900717 case OPENSTACK_INSTANCE_PORT_UPDATED:
Jian Lieae12362018-04-10 18:48:32 +0900718 setArpRequestRule(event.subject(), true);
719 setArpReplyRule(event.subject(), true);
720 break;
721 case OPENSTACK_INSTANCE_PORT_VANISHED:
722 setArpRequestRule(event.subject(), false);
723 setArpReplyRule(event.subject(), false);
724 break;
Jian Liec5c32b2018-07-13 14:28:58 +0900725 case OPENSTACK_INSTANCE_MIGRATION_STARTED:
726 setArpRequestRule(event.subject(), true);
727 setArpReplyRule(event.subject(), true);
728 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900729 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
Jian Liec5c32b2018-07-13 14:28:58 +0900730 InstancePort revisedInstPort = swapStaleLocation(event.subject());
731 setArpRequestRule(revisedInstPort, false);
Jian Li24ec59f2018-05-23 19:01:25 +0900732 break;
Jian Lieae12362018-04-10 18:48:32 +0900733 default:
734 break;
735 }
736 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900737 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700738}