blob: 03af72e737413a15ca0d6f29a306238db705b620 [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;
19import com.google.common.collect.Sets;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Modified;
24import org.apache.felix.scr.annotations.Property;
25import org.apache.felix.scr.annotations.Reference;
26import org.apache.felix.scr.annotations.ReferenceCardinality;
27import org.onlab.packet.ARP;
Hyunsun Moon44aac662017-02-18 02:07:01 +090028import org.onlab.packet.EthType;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070029import org.onlab.packet.Ethernet;
30import org.onlab.packet.Ip4Address;
31import org.onlab.packet.IpAddress;
32import org.onlab.packet.MacAddress;
33import org.onlab.util.Tools;
Hyunsun Moon44aac662017-02-18 02:07:01 +090034import org.onosproject.cfg.ComponentConfigService;
Jian Lieae12362018-04-10 18:48:32 +090035import org.onosproject.cluster.ClusterService;
36import org.onosproject.cluster.LeadershipService;
37import org.onosproject.cluster.NodeId;
Hyunsun Moon44aac662017-02-18 02:07:01 +090038import org.onosproject.core.ApplicationId;
39import org.onosproject.core.CoreService;
Jian Lieae12362018-04-10 18:48:32 +090040import org.onosproject.mastership.MastershipService;
41import org.onosproject.net.PortNumber;
42import org.onosproject.net.device.DeviceService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090043import org.onosproject.net.flow.DefaultTrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070044import org.onosproject.net.flow.DefaultTrafficTreatment;
Hyunsun Moon44aac662017-02-18 02:07:01 +090045import org.onosproject.net.flow.TrafficSelector;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070046import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.packet.DefaultOutboundPacket;
48import org.onosproject.net.packet.PacketContext;
49import org.onosproject.net.packet.PacketProcessor;
50import org.onosproject.net.packet.PacketService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090051import org.onosproject.openstacknetworking.api.InstancePort;
Jian Lieae12362018-04-10 18:48:32 +090052import org.onosproject.openstacknetworking.api.InstancePortEvent;
53import org.onosproject.openstacknetworking.api.InstancePortListener;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Lieae12362018-04-10 18:48:32 +090055import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090056import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
57import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
58import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Jian Lieae12362018-04-10 18:48:32 +090059import org.onosproject.openstacknode.api.OpenstackNode;
60import org.onosproject.openstacknode.api.OpenstackNodeEvent;
61import org.onosproject.openstacknode.api.OpenstackNodeListener;
62import org.onosproject.openstacknode.api.OpenstackNodeService;
63import org.openstack4j.model.network.Network;
64import 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;
67import 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;
87import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
88import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070089
90/**
91 * Handles ARP packet from VMs.
92 */
93@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090094public final class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -070095
96 private final Logger log = LoggerFactory.getLogger(getClass());
97
98 private static final String GATEWAY_MAC = "gatewayMac";
Jian Lieae12362018-04-10 18:48:32 +090099 private static final String ARP_MODE = "arpMode";
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700100
101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800102 CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800105 PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lieae12362018-04-10 18:48:32 +0900108 OpenstackFlowRuleService osFlowRuleService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800111 ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lieae12362018-04-10 18:48:32 +0900114 ClusterService clusterService;
115
116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 LeadershipService leadershipService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 DeviceService deviceService;
121
122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 MastershipService mastershipService;
124
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800126 InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900127
128 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800129 OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700130
Jian Lieae12362018-04-10 18:48:32 +0900131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected OpenstackNodeService osNodeService;
133
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700134 @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700135 label = "Fake MAC address for virtual network subnet gateway")
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700136 private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700137
Jian Lieae12362018-04-10 18:48:32 +0900138 @Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
Jian Li1478f292018-05-28 17:10:59 +0900139 label = "ARP processing mode, broadcast (default) | proxy ")
Jian Lieae12362018-04-10 18:48:32 +0900140 protected String arpMode = DEFAULT_ARP_MODE_STR;
141
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700142 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900143 private final InternalOpenstackNetworkListener osNetworkListener =
144 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900145 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
146 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
147
Hyunsun Moon44aac662017-02-18 02:07:01 +0900148 private final Set<IpAddress> gateways = Sets.newConcurrentHashSet();
149
150 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900151 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700152
153 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800154 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900155 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
156 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900157 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900158 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900159 osNodeService.addListener(osNodeListener);
160 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700161 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900162
163 instancePortService.addListener(instancePortListener);
164
165 osNetworkService.networks().forEach(n -> {
166 if (n.getNetworkType() != NetworkType.FLAT) {
167 osNetworkService.subnets().forEach(s -> {
168 if (s.getNetworkId().equals(n.getId())) {
169 addSubnetGateway(s);
170 }
171 });
172 }
173 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900174
175 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700176 }
177
178 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800179 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700180 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900181 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900182 osNodeService.removeListener(osNodeListener);
183 instancePortService.removeListener(instancePortListener);
184 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900185 configService.unregisterProperties(getClass(), false);
186
187 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700188 }
189
190 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800191 void modified(ComponentContext context) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700192 Dictionary<?, ?> properties = context.getProperties();
193 String updatedMac;
194
195 updatedMac = Tools.get(properties, GATEWAY_MAC);
196 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(gatewayMac)) {
197 gatewayMac = updatedMac;
198 }
199
Jian Lieae12362018-04-10 18:48:32 +0900200 String updateArpMode;
201
202 updateArpMode = Tools.get(properties, ARP_MODE);
203 if (!Strings.isNullOrEmpty(updateArpMode) && !updateArpMode.equals(arpMode)) {
204 arpMode = updateArpMode;
205 }
206
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700207 log.info("Modified");
208 }
209
Hyunsun Moon44aac662017-02-18 02:07:01 +0900210 private void addSubnetGateway(Subnet osSubnet) {
211 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
212 return;
213 }
214 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
215 gateways.add(gatewayIp);
216 log.debug("Added ARP proxy entry IP:{}", gatewayIp);
217 }
218
219 private void removeSubnetGateway(Subnet osSubnet) {
220 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
221 return;
222 }
223 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
224 gateways.remove(gatewayIp);
225 log.debug("Removed ARP proxy entry IP:{}", gatewayIp);
226 }
227
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700228 /**
229 * Processes ARP request packets.
230 * It checks if the target IP is owned by a known host first and then ask to
231 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
232 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900233 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700234 * @param ethPacket ethernet packet
235 */
236 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900237
238 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
239 if (arpMode.equals(ARP_BROADCAST_MODE)) {
240 return;
241 }
242
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700243 ARP arpPacket = (ARP) ethPacket.getPayload();
244 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
245 return;
246 }
247
Hyunsun Moon44aac662017-02-18 02:07:01 +0900248 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
249 if (srcInstPort == null) {
250 log.trace("Failed to find source instance port(MAC:{})",
251 ethPacket.getSourceMAC());
252 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700253 }
254
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
256 MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
257 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700258 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900259 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700260 return;
261 }
262
263 Ethernet ethReply = ARP.buildArpReply(
264 targetIp.getIp4Address(),
265 replyMac,
266 ethPacket);
267
268 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
269 .setOutput(context.inPacket().receivedFrom().port())
270 .build();
271
272 packetService.emit(new DefaultOutboundPacket(
273 context.inPacket().receivedFrom().deviceId(),
274 treatment,
275 ByteBuffer.wrap(ethReply.serialize())));
276 }
277
278 /**
279 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700281 *
282 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 * @param osNetId openstack network id of the source instance port
284 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700285 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900286 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700287 checkNotNull(targetIp);
288
Hyunsun Moon44aac662017-02-18 02:07:01 +0900289 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
290 if (instPort != null) {
291 log.trace("Found MAC from host service for {}", targetIp);
292 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700293 } else {
294 return MacAddress.NONE;
295 }
296 }
297
Jian Lieae12362018-04-10 18:48:32 +0900298 /**
Daniel Park613ac372018-06-28 14:30:11 +0900299 * Installs flow rules which convert ARP request packet into ARP reply
300 * by adding a fake gateway MAC address as Source Hardware Address.
301 *
302 * @param osSubnet openstack subnet
303 * @param install flag which indicates whether to install rule or remove rule
304 */
305 private void setFakeGatewayArpRule(Subnet osSubnet, boolean install, OpenstackNode osNode) {
306
307 if (arpMode.equals(ARP_BROADCAST_MODE)) {
308 String gateway = osSubnet.getGateway();
309
310 TrafficSelector selector = DefaultTrafficSelector.builder()
311 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
312 .matchArpOp(ARP.OP_REQUEST)
313 .matchArpTpa(Ip4Address.valueOf(gateway))
314 .build();
315
316 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
317 .setArpOp(ARP.OP_REPLY)
318 .setArpSha(MacAddress.valueOf(gatewayMac))
319 .setArpSpa(Ip4Address.valueOf(gateway))
320 .setOutput(PortNumber.IN_PORT)
321 .build();
322
323 if (osNode == null) {
324 osNodeService.completeNodes(COMPUTE).forEach(n ->
325 osFlowRuleService.setRule(
326 appId,
327 n.intgBridge(),
328 selector,
329 treatment,
330 PRIORITY_ARP_GATEWAY_RULE,
331 DHCP_ARP_TABLE,
332 install
333 )
334 );
335 } else {
336 osFlowRuleService.setRule(
337 appId,
338 osNode.intgBridge(),
339 selector,
340 treatment,
341 PRIORITY_ARP_GATEWAY_RULE,
342 DHCP_ARP_TABLE,
343 install
344 );
345 }
346
347 }
348 }
349
350 /**
Jian Lieae12362018-04-10 18:48:32 +0900351 * An internal packet processor which processes ARP request, and results in
352 * packet-out ARP reply.
353 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700354 private class InternalPacketProcessor implements PacketProcessor {
355
356 @Override
357 public void process(PacketContext context) {
358 if (context.isHandled()) {
359 return;
360 }
361
362 Ethernet ethPacket = context.inPacket().parsed();
363 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
364 return;
365 }
366 processPacketIn(context, ethPacket);
367 }
368 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900369
Jian Lieae12362018-04-10 18:48:32 +0900370 /**
371 * An internal network listener which listens to openstack network event,
372 * manages the gateway collection and installs flow rule that handles
373 * ARP request in data plane.
374 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900375 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
376
377 @Override
378 public boolean isRelevant(OpenstackNetworkEvent event) {
379 Subnet osSubnet = event.subnet();
380 if (osSubnet == null) {
381 return false;
382 }
Jian Lieae12362018-04-10 18:48:32 +0900383
Jian Libb4f5412018-04-12 09:48:50 +0900384 Network network = osNetworkService.network(osSubnet.getNetworkId());
385
Jian Lieae12362018-04-10 18:48:32 +0900386 if (network == null) {
387 log.warn("Network is not specified.");
388 return false;
389 } else {
390 if (network.getNetworkType().equals(NetworkType.FLAT)) {
391 return false;
392 }
393 }
394
395 // do not allow to proceed without leadership
396 NodeId leader = leadershipService.getLeader(appId.name());
397 if (!Objects.equals(localNodeId, leader)) {
398 return false;
399 }
400
Hyunsun Moon44aac662017-02-18 02:07:01 +0900401 return !Strings.isNullOrEmpty(osSubnet.getGateway());
402 }
403
404 @Override
405 public void event(OpenstackNetworkEvent event) {
406 switch (event.type()) {
407 case OPENSTACK_SUBNET_CREATED:
408 case OPENSTACK_SUBNET_UPDATED:
409 addSubnetGateway(event.subnet());
Daniel Park613ac372018-06-28 14:30:11 +0900410 setFakeGatewayArpRule(event.subnet(), true, null);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900411 break;
412 case OPENSTACK_SUBNET_REMOVED:
413 removeSubnetGateway(event.subnet());
Daniel Park613ac372018-06-28 14:30:11 +0900414 setFakeGatewayArpRule(event.subnet(), false, null);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900415 break;
416 case OPENSTACK_NETWORK_CREATED:
417 case OPENSTACK_NETWORK_UPDATED:
418 case OPENSTACK_NETWORK_REMOVED:
419 case OPENSTACK_PORT_CREATED:
420 case OPENSTACK_PORT_UPDATED:
421 case OPENSTACK_PORT_REMOVED:
422 default:
423 // do nothing for the other events
424 break;
425 }
426 }
Jian Lieae12362018-04-10 18:48:32 +0900427 }
428
429 /**
430 * An internal openstack node listener which is used for listening openstack
431 * node activity. As long as a node is in complete state, we will install
432 * default ARP rule to handle ARP request.
433 */
434 private class InternalNodeEventListener implements OpenstackNodeListener {
435
436 @Override
437 public boolean isRelevant(OpenstackNodeEvent event) {
438 // do not allow to proceed without leadership
439 NodeId leader = leadershipService.getLeader(appId.name());
Jian Li51b844c2018-05-31 10:59:03 +0900440 return Objects.equals(localNodeId, leader) && event.subject().type() == COMPUTE;
Jian Lieae12362018-04-10 18:48:32 +0900441 }
442
443 @Override
444 public void event(OpenstackNodeEvent event) {
445 OpenstackNode osNode = event.subject();
446 switch (event.type()) {
447 case OPENSTACK_NODE_COMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900448 setDefaultArpRule(osNode, true);
Jian Lieae12362018-04-10 18:48:32 +0900449 break;
450 case OPENSTACK_NODE_INCOMPLETE:
Jian Li51b844c2018-05-31 10:59:03 +0900451 setDefaultArpRule(osNode, false);
Jian Lieae12362018-04-10 18:48:32 +0900452 break;
Jian Lieae12362018-04-10 18:48:32 +0900453 default:
454 break;
455 }
456 }
457
Jian Lif96685c2018-05-21 14:14:16 +0900458 private void setDefaultArpRule(OpenstackNode osNode, boolean install) {
459 switch (arpMode) {
460 case ARP_PROXY_MODE:
461 setDefaultArpRuleForProxyMode(osNode, install);
462 break;
463 case ARP_BROADCAST_MODE:
464 setDefaultArpRuleForBroadcastMode(osNode, install);
Daniel Park613ac372018-06-28 14:30:11 +0900465 osNetworkService.subnets().forEach(subnet -> setFakeGatewayArpRule(subnet, install, osNode));
Jian Lif96685c2018-05-21 14:14:16 +0900466 break;
467 default:
468 log.warn("Invalid ARP mode {}. Please use either " +
469 "broadcast or proxy mode.", arpMode);
470 break;
Jian Lieae12362018-04-10 18:48:32 +0900471 }
472 }
Jian Lif96685c2018-05-21 14:14:16 +0900473
474 private void setDefaultArpRuleForProxyMode(OpenstackNode osNode, boolean install) {
475 TrafficSelector selector = DefaultTrafficSelector.builder()
476 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
477 .build();
478
479 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
480 .punt()
481 .build();
482
483 osFlowRuleService.setRule(
484 appId,
485 osNode.intgBridge(),
486 selector,
487 treatment,
488 PRIORITY_ARP_CONTROL_RULE,
489 DHCP_ARP_TABLE,
490 install
491 );
492 }
493
494 private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
495 TrafficSelector selector = DefaultTrafficSelector.builder()
496 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
497 .matchArpOp(ARP.OP_REQUEST)
498 .build();
499
500 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
501 .setOutput(PortNumber.FLOOD)
502 .build();
503
504 osFlowRuleService.setRule(
505 appId,
506 osNode.intgBridge(),
507 selector,
508 treatment,
509 PRIORITY_ARP_SUBNET_RULE,
510 DHCP_ARP_TABLE,
511 install
512 );
513 }
Jian Lieae12362018-04-10 18:48:32 +0900514 }
515
516 /**
517 * An internal instance port listener which listens the port events generated
518 * from VM. When ARP a host which located in a remote compute node, we specify
519 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
520 * host IP address. When ARP a host which located in a local compute node,
521 * we specify only ARP OP mode as REQUEST.
522 */
523 private class InternalInstancePortListener implements InstancePortListener {
524
525 @Override
526 public boolean isRelevant(InstancePortEvent event) {
527
528 if (arpMode.equals(ARP_PROXY_MODE)) {
529 return false;
530 }
531
532 InstancePort instPort = event.subject();
533 return mastershipService.isLocalMaster(instPort.deviceId());
534 }
535
536 @Override
537 public void event(InstancePortEvent event) {
538 switch (event.type()) {
539 case OPENSTACK_INSTANCE_PORT_UPDATED:
540 case OPENSTACK_INSTANCE_PORT_DETECTED:
541 setArpRequestRule(event.subject(), true);
542 setArpReplyRule(event.subject(), true);
543 break;
544 case OPENSTACK_INSTANCE_PORT_VANISHED:
545 setArpRequestRule(event.subject(), false);
546 setArpReplyRule(event.subject(), false);
547 break;
Jian Li24ec59f2018-05-23 19:01:25 +0900548 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
549 setArpRequestRule(event.subject(), false);
550 break;
Jian Lieae12362018-04-10 18:48:32 +0900551 default:
552 break;
553 }
554 }
555
556 /**
557 * Installs flow rules to match ARP request packets.
558 *
559 * @param port instance port
560 * @param install installation flag
561 */
562 private void setArpRequestRule(InstancePort port, boolean install) {
563 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
564
565 switch (type) {
566 case VXLAN:
567 setRemoteArpRequestRuleForVxlan(port, install);
568 break;
569 case VLAN:
Jian Li59657882018-05-10 13:13:06 +0900570 // since VLAN ARP packet can be broadcasted to all hosts that connected with L2 network,
571 // there is no need to add any flow rules to handle ARP request
Jian Lieae12362018-04-10 18:48:32 +0900572 break;
573 default:
574 break;
575 }
576 }
577
578 /**
579 * Installs flow rules to match ARP reply packets.
580 *
581 * @param port instance port
582 * @param install installation flag
583 */
584 private void setArpReplyRule(InstancePort port, boolean install) {
585 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
586
587 switch (type) {
588 case VXLAN:
Jian Li59657882018-05-10 13:13:06 +0900589 setArpReplyRuleForVxlan(port, install);
Jian Lieae12362018-04-10 18:48:32 +0900590 break;
591 case VLAN:
Jian Li59657882018-05-10 13:13:06 +0900592 setArpReplyRuleForVlan(port, install);
Jian Lieae12362018-04-10 18:48:32 +0900593 break;
594 default:
595 break;
596 }
597 }
598
599 /**
600 * Installs flow rules to match ARP request packets only for VxLAN.
601 *
602 * @param port instance port
603 * @param install installation flag
604 */
605 private void setRemoteArpRequestRuleForVxlan(InstancePort port, boolean install) {
606
607 OpenstackNode localNode = osNodeService.node(port.deviceId());
608
609 TrafficSelector selector = DefaultTrafficSelector.builder()
610 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
611 .matchArpOp(ARP.OP_REQUEST)
612 .matchArpTpa(port.ipAddress().getIp4Address())
613 .build();
614
615 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
616 }
617
618 /**
619 * Installs flow rules to match ARP reply packets only for VxLAN.
620 *
621 * @param port instance port
622 * @param install installation flag
623 */
Jian Li59657882018-05-10 13:13:06 +0900624 private void setArpReplyRuleForVxlan(InstancePort port, boolean install) {
Jian Lieae12362018-04-10 18:48:32 +0900625
626 OpenstackNode localNode = osNodeService.node(port.deviceId());
627
Jian Li59657882018-05-10 13:13:06 +0900628 TrafficSelector selector = setArpReplyRuleForVnet(port, install);
629 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
630 }
631
632 /**
633 * Installs flow rules to match ARP reply packets only for VLAN.
634 *
635 * @param port instance port
636 * @param install installation flag
637 */
638 private void setArpReplyRuleForVlan(InstancePort port, boolean install) {
639
640 TrafficSelector selector = setArpReplyRuleForVnet(port, install);
641 setRemoteArpTreatmentForVlan(selector, port, install);
642 }
643
644 // a helper method
645 private TrafficSelector setArpReplyRuleForVnet(InstancePort port, boolean install) {
Jian Lieae12362018-04-10 18:48:32 +0900646 TrafficSelector selector = DefaultTrafficSelector.builder()
647 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
648 .matchArpOp(ARP.OP_REPLY)
649 .matchArpTpa(port.ipAddress().getIp4Address())
650 .matchArpTha(port.macAddress())
651 .build();
652
653 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
654 .setOutput(port.portNumber())
655 .build();
656
657 osFlowRuleService.setRule(
658 appId,
659 port.deviceId(),
660 selector,
661 treatment,
662 PRIORITY_ARP_REPLY_RULE,
663 DHCP_ARP_TABLE,
664 install
665 );
666
Jian Li59657882018-05-10 13:13:06 +0900667 return selector;
Jian Lieae12362018-04-10 18:48:32 +0900668 }
669
670 // a helper method
671 private void setRemoteArpTreatmentForVxlan(TrafficSelector selector,
672 InstancePort port,
673 OpenstackNode localNode,
674 boolean install) {
675 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
676 if (!remoteNode.intgBridge().equals(port.deviceId())) {
677 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
678 .extension(buildExtension(
679 deviceService,
680 remoteNode.intgBridge(),
681 localNode.dataIp().getIp4Address()),
682 remoteNode.intgBridge())
683 .setOutput(remoteNode.tunnelPortNum())
684 .build();
685
686 osFlowRuleService.setRule(
687 appId,
688 remoteNode.intgBridge(),
689 selector,
690 treatmentToRemote,
691 PRIORITY_ARP_REQUEST_RULE,
692 DHCP_ARP_TABLE,
693 install
694 );
695 }
696 }
697 }
Jian Li59657882018-05-10 13:13:06 +0900698
699 // a helper method
700 private void setRemoteArpTreatmentForVlan(TrafficSelector selector,
701 InstancePort port,
702 boolean install) {
703 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
704 if (!remoteNode.intgBridge().equals(port.deviceId()) && remoteNode.vlanIntf() != null) {
705 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
706 .setOutput(remoteNode.vlanPortNum())
707 .build();
708
709 osFlowRuleService.setRule(
710 appId,
711 remoteNode.intgBridge(),
712 selector,
713 treatmentToRemote,
714 PRIORITY_ARP_REQUEST_RULE,
715 DHCP_ARP_TABLE,
716 install);
717 }
718 }
719 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900720 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700721}