blob: 0cdb78bcd5a2e51d06be87f308ef1a1f9c90a361 [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;
89import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
Hyunsun Moonb974fca2016-06-30 21:20:39 -070090
91/**
92 * Handles ARP packet from VMs.
93 */
94@Component(immediate = true)
Hyunsun Moon44aac662017-02-18 02:07:01 +090095public final class OpenstackSwitchingArpHandler {
Hyunsun Moonb974fca2016-06-30 21:20:39 -070096
97 private final Logger log = LoggerFactory.getLogger(getClass());
98
99 private static final String GATEWAY_MAC = "gatewayMac";
Jian Lieae12362018-04-10 18:48:32 +0900100 private static final String ARP_MODE = "arpMode";
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800103 CoreService coreService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900104
105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800106 PacketService packetService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lieae12362018-04-10 18:48:32 +0900109 OpenstackFlowRuleService osFlowRuleService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800112 ComponentConfigService configService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jian Lieae12362018-04-10 18:48:32 +0900115 ClusterService clusterService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 LeadershipService leadershipService;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 DeviceService deviceService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 MastershipService mastershipService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800127 InstancePortService instancePortService;
Hyunsun Moon44aac662017-02-18 02:07:01 +0900128
129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkey9c9cde42018-01-12 14:22:06 -0800130 OpenstackNetworkService osNetworkService;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700131
Jian Lieae12362018-04-10 18:48:32 +0900132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected OpenstackNodeService osNodeService;
134
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700135 @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700136 label = "Fake MAC address for virtual network subnet gateway")
Hyunsun Moonb3eb84d2016-07-27 19:10:52 -0700137 private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700138
Jian Lieae12362018-04-10 18:48:32 +0900139 @Property(name = ARP_MODE, value = DEFAULT_ARP_MODE_STR,
Jian Li2a43cb32018-04-13 16:23:10 +0900140 label = "ARP processing mode, proxy (default) | broadcast ")
Jian Lieae12362018-04-10 18:48:32 +0900141 protected String arpMode = DEFAULT_ARP_MODE_STR;
142
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700143 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900144 private final InternalOpenstackNetworkListener osNetworkListener =
145 new InternalOpenstackNetworkListener();
Jian Lieae12362018-04-10 18:48:32 +0900146 private final InstancePortListener instancePortListener = new InternalInstancePortListener();
147 private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
148
Hyunsun Moon44aac662017-02-18 02:07:01 +0900149 private final Set<IpAddress> gateways = Sets.newConcurrentHashSet();
150
151 private ApplicationId appId;
Jian Lieae12362018-04-10 18:48:32 +0900152 private NodeId localNodeId;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700153
154 @Activate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800155 void activate() {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900156 appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
157 configService.registerProperties(getClass());
Jian Lieae12362018-04-10 18:48:32 +0900158 localNodeId = clusterService.getLocalNode().id();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900159 osNetworkService.addListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900160 osNodeService.addListener(osNodeListener);
161 leadershipService.runForLeadership(appId.name());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700162 packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
Jian Lieae12362018-04-10 18:48:32 +0900163
164 instancePortService.addListener(instancePortListener);
165
166 osNetworkService.networks().forEach(n -> {
167 if (n.getNetworkType() != NetworkType.FLAT) {
168 osNetworkService.subnets().forEach(s -> {
169 if (s.getNetworkId().equals(n.getId())) {
170 addSubnetGateway(s);
171 }
172 });
173 }
174 });
Hyunsun Moon44aac662017-02-18 02:07:01 +0900175
176 log.info("Started");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700177 }
178
179 @Deactivate
Ray Milkey9c9cde42018-01-12 14:22:06 -0800180 void deactivate() {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700181 packetService.removeProcessor(packetProcessor);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900182 osNetworkService.removeListener(osNetworkListener);
Jian Lieae12362018-04-10 18:48:32 +0900183 osNodeService.removeListener(osNodeListener);
184 instancePortService.removeListener(instancePortListener);
185 leadershipService.withdraw(appId.name());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900186 configService.unregisterProperties(getClass(), false);
187
188 log.info("Stopped");
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700189 }
190
191 @Modified
Ray Milkey9c9cde42018-01-12 14:22:06 -0800192 void modified(ComponentContext context) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700193 Dictionary<?, ?> properties = context.getProperties();
194 String updatedMac;
195
196 updatedMac = Tools.get(properties, GATEWAY_MAC);
197 if (!Strings.isNullOrEmpty(updatedMac) && !updatedMac.equals(gatewayMac)) {
198 gatewayMac = updatedMac;
199 }
200
Jian Lieae12362018-04-10 18:48:32 +0900201 String updateArpMode;
202
203 updateArpMode = Tools.get(properties, ARP_MODE);
204 if (!Strings.isNullOrEmpty(updateArpMode) && !updateArpMode.equals(arpMode)) {
205 arpMode = updateArpMode;
206 }
207
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700208 log.info("Modified");
209 }
210
Hyunsun Moon44aac662017-02-18 02:07:01 +0900211 private void addSubnetGateway(Subnet osSubnet) {
212 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
213 return;
214 }
215 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
216 gateways.add(gatewayIp);
217 log.debug("Added ARP proxy entry IP:{}", gatewayIp);
218 }
219
220 private void removeSubnetGateway(Subnet osSubnet) {
221 if (Strings.isNullOrEmpty(osSubnet.getGateway())) {
222 return;
223 }
224 IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
225 gateways.remove(gatewayIp);
226 log.debug("Removed ARP proxy entry IP:{}", gatewayIp);
227 }
228
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700229 /**
230 * Processes ARP request packets.
231 * It checks if the target IP is owned by a known host first and then ask to
232 * OpenStack if it's not. This ARP proxy does not support overlapping IP.
233 *
Hyunsun Moon44aac662017-02-18 02:07:01 +0900234 * @param context packet context
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700235 * @param ethPacket ethernet packet
236 */
237 private void processPacketIn(PacketContext context, Ethernet ethPacket) {
Jian Lieae12362018-04-10 18:48:32 +0900238
239 // if the ARP mode is configured as broadcast mode, we simply ignore ARP packet_in
240 if (arpMode.equals(ARP_BROADCAST_MODE)) {
241 return;
242 }
243
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700244 ARP arpPacket = (ARP) ethPacket.getPayload();
245 if (arpPacket.getOpCode() != ARP.OP_REQUEST) {
246 return;
247 }
248
Hyunsun Moon44aac662017-02-18 02:07:01 +0900249 InstancePort srcInstPort = instancePortService.instancePort(ethPacket.getSourceMAC());
250 if (srcInstPort == null) {
251 log.trace("Failed to find source instance port(MAC:{})",
252 ethPacket.getSourceMAC());
253 return;
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700254 }
255
Hyunsun Moon44aac662017-02-18 02:07:01 +0900256 IpAddress targetIp = Ip4Address.valueOf(arpPacket.getTargetProtocolAddress());
257 MacAddress replyMac = gateways.contains(targetIp) ? MacAddress.valueOf(gatewayMac) :
258 getMacFromHostOpenstack(targetIp, srcInstPort.networkId());
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700259 if (replyMac == MacAddress.NONE) {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900260 log.trace("Failed to find MAC address for {}", targetIp);
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700261 return;
262 }
263
264 Ethernet ethReply = ARP.buildArpReply(
265 targetIp.getIp4Address(),
266 replyMac,
267 ethPacket);
268
269 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
270 .setOutput(context.inPacket().receivedFrom().port())
271 .build();
272
273 packetService.emit(new DefaultOutboundPacket(
274 context.inPacket().receivedFrom().deviceId(),
275 treatment,
276 ByteBuffer.wrap(ethReply.serialize())));
277 }
278
279 /**
280 * Returns MAC address of a host with a given target IP address by asking to
Hyunsun Moon44aac662017-02-18 02:07:01 +0900281 * instance port service.
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700282 *
283 * @param targetIp target ip
Hyunsun Moon44aac662017-02-18 02:07:01 +0900284 * @param osNetId openstack network id of the source instance port
285 * @return mac address, or none mac address if it fails to find the mac
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700286 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900287 private MacAddress getMacFromHostOpenstack(IpAddress targetIp, String osNetId) {
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700288 checkNotNull(targetIp);
289
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 InstancePort instPort = instancePortService.instancePort(targetIp, osNetId);
291 if (instPort != null) {
292 log.trace("Found MAC from host service for {}", targetIp);
293 return instPort.macAddress();
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700294 } else {
295 return MacAddress.NONE;
296 }
297 }
298
Jian Lieae12362018-04-10 18:48:32 +0900299 /**
300 * An internal packet processor which processes ARP request, and results in
301 * packet-out ARP reply.
302 */
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700303 private class InternalPacketProcessor implements PacketProcessor {
304
305 @Override
306 public void process(PacketContext context) {
307 if (context.isHandled()) {
308 return;
309 }
310
311 Ethernet ethPacket = context.inPacket().parsed();
312 if (ethPacket == null || ethPacket.getEtherType() != Ethernet.TYPE_ARP) {
313 return;
314 }
315 processPacketIn(context, ethPacket);
316 }
317 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900318
Jian Lieae12362018-04-10 18:48:32 +0900319 /**
320 * An internal network listener which listens to openstack network event,
321 * manages the gateway collection and installs flow rule that handles
322 * ARP request in data plane.
323 */
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
325
326 @Override
327 public boolean isRelevant(OpenstackNetworkEvent event) {
328 Subnet osSubnet = event.subnet();
329 if (osSubnet == null) {
330 return false;
331 }
Jian Lieae12362018-04-10 18:48:32 +0900332
Jian Libb4f5412018-04-12 09:48:50 +0900333 Network network = osNetworkService.network(osSubnet.getNetworkId());
334
Jian Lieae12362018-04-10 18:48:32 +0900335 if (network == null) {
336 log.warn("Network is not specified.");
337 return false;
338 } else {
339 if (network.getNetworkType().equals(NetworkType.FLAT)) {
340 return false;
341 }
342 }
343
344 // do not allow to proceed without leadership
345 NodeId leader = leadershipService.getLeader(appId.name());
346 if (!Objects.equals(localNodeId, leader)) {
347 return false;
348 }
349
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 return !Strings.isNullOrEmpty(osSubnet.getGateway());
351 }
352
353 @Override
354 public void event(OpenstackNetworkEvent event) {
355 switch (event.type()) {
356 case OPENSTACK_SUBNET_CREATED:
357 case OPENSTACK_SUBNET_UPDATED:
358 addSubnetGateway(event.subnet());
Jian Lieae12362018-04-10 18:48:32 +0900359 setFakeGatewayArpRule(event.subnet(), true);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900360 break;
361 case OPENSTACK_SUBNET_REMOVED:
362 removeSubnetGateway(event.subnet());
Jian Lieae12362018-04-10 18:48:32 +0900363 setFakeGatewayArpRule(event.subnet(), false);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364 break;
365 case OPENSTACK_NETWORK_CREATED:
366 case OPENSTACK_NETWORK_UPDATED:
367 case OPENSTACK_NETWORK_REMOVED:
368 case OPENSTACK_PORT_CREATED:
369 case OPENSTACK_PORT_UPDATED:
370 case OPENSTACK_PORT_REMOVED:
371 default:
372 // do nothing for the other events
373 break;
374 }
375 }
Jian Lieae12362018-04-10 18:48:32 +0900376
377 /**
378 * Installs flow rules which convert ARP request packet into ARP reply
379 * by adding a fake gateway MAC address as Source Hardware Address.
380 *
381 * @param osSubnet openstack subnet
382 * @param install flag which indicates whether to install rule or remove rule
383 */
384 private void setFakeGatewayArpRule(Subnet osSubnet, boolean install) {
385
386 if (arpMode.equals(ARP_BROADCAST_MODE)) {
387 String gateway = osSubnet.getGateway();
388
389 TrafficSelector selector = DefaultTrafficSelector.builder()
390 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
391 .matchArpOp(ARP.OP_REQUEST)
392 .matchArpTpa(Ip4Address.valueOf(gateway))
393 .build();
394
395 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
396 .setArpOp(ARP.OP_REPLY)
397 .setArpSha(MacAddress.valueOf(gatewayMac))
398 .setArpSpa(Ip4Address.valueOf(gateway))
399 .setOutput(PortNumber.IN_PORT)
400 .build();
401
402 osNodeService.completeNodes(COMPUTE).forEach(n ->
403 osFlowRuleService.setRule(
404 appId,
405 n.intgBridge(),
406 selector,
407 treatment,
408 PRIORITY_ARP_GATEWAY_RULE,
409 DHCP_ARP_TABLE,
410 install
411 )
412 );
413 }
414 }
415 }
416
417 /**
418 * An internal openstack node listener which is used for listening openstack
419 * node activity. As long as a node is in complete state, we will install
420 * default ARP rule to handle ARP request.
421 */
422 private class InternalNodeEventListener implements OpenstackNodeListener {
423
424 @Override
425 public boolean isRelevant(OpenstackNodeEvent event) {
426 // do not allow to proceed without leadership
427 NodeId leader = leadershipService.getLeader(appId.name());
428 return Objects.equals(localNodeId, leader);
429 }
430
431 @Override
432 public void event(OpenstackNodeEvent event) {
433 OpenstackNode osNode = event.subject();
434 switch (event.type()) {
435 case OPENSTACK_NODE_COMPLETE:
436 setDefaultArpRule(osNode, true);
437 break;
438 case OPENSTACK_NODE_INCOMPLETE:
439 setDefaultArpRule(osNode, false);
440 break;
441 case OPENSTACK_NODE_CREATED:
442 case OPENSTACK_NODE_UPDATED:
443 case OPENSTACK_NODE_REMOVED:
444 default:
445 break;
446 }
447 }
448
449 private void setDefaultArpRule(OpenstackNode openstackNode, boolean install) {
450 if (openstackNode.type().equals(GATEWAY)) {
451 return;
452 }
453
454 if (arpMode.equals(ARP_PROXY_MODE)) {
455 TrafficSelector selector = DefaultTrafficSelector.builder()
456 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
457 .build();
458
459 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
460 .punt()
461 .build();
462
463 osFlowRuleService.setRule(
464 appId,
465 openstackNode.intgBridge(),
466 selector,
467 treatment,
468 PRIORITY_ARP_CONTROL_RULE,
469 DHCP_ARP_TABLE,
470 install
471 );
472 } else if (arpMode.equals(ARP_BROADCAST_MODE)) {
473 TrafficSelector selector = DefaultTrafficSelector.builder()
474 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
475 .matchArpOp(ARP.OP_REQUEST)
476 .build();
477
478 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
479 .setOutput(PortNumber.FLOOD)
480 .build();
481
482 osFlowRuleService.setRule(
483 appId,
484 openstackNode.intgBridge(),
485 selector,
486 treatment,
487 PRIORITY_ARP_SUBNET_RULE,
488 DHCP_ARP_TABLE,
489 install
490 );
491 } else {
492 log.warn("Invalid ARP mode {}. Please use either broadcast or proxy mode.", arpMode);
493 }
494 }
495 }
496
497 /**
498 * An internal instance port listener which listens the port events generated
499 * from VM. When ARP a host which located in a remote compute node, we specify
500 * both ARP OP mode as REQUEST and Target Protocol Address (TPA) with
501 * host IP address. When ARP a host which located in a local compute node,
502 * we specify only ARP OP mode as REQUEST.
503 */
504 private class InternalInstancePortListener implements InstancePortListener {
505
506 @Override
507 public boolean isRelevant(InstancePortEvent event) {
508
509 if (arpMode.equals(ARP_PROXY_MODE)) {
510 return false;
511 }
512
513 InstancePort instPort = event.subject();
514 return mastershipService.isLocalMaster(instPort.deviceId());
515 }
516
517 @Override
518 public void event(InstancePortEvent event) {
519 switch (event.type()) {
520 case OPENSTACK_INSTANCE_PORT_UPDATED:
521 case OPENSTACK_INSTANCE_PORT_DETECTED:
522 setArpRequestRule(event.subject(), true);
523 setArpReplyRule(event.subject(), true);
524 break;
525 case OPENSTACK_INSTANCE_PORT_VANISHED:
526 setArpRequestRule(event.subject(), false);
527 setArpReplyRule(event.subject(), false);
528 break;
529 default:
530 break;
531 }
532 }
533
534 /**
535 * Installs flow rules to match ARP request packets.
536 *
537 * @param port instance port
538 * @param install installation flag
539 */
540 private void setArpRequestRule(InstancePort port, boolean install) {
541 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
542
543 switch (type) {
544 case VXLAN:
545 setRemoteArpRequestRuleForVxlan(port, install);
546 break;
547 case VLAN:
548 // TODO: handle VLAN differently
549 break;
550 default:
551 break;
552 }
553 }
554
555 /**
556 * Installs flow rules to match ARP reply packets.
557 *
558 * @param port instance port
559 * @param install installation flag
560 */
561 private void setArpReplyRule(InstancePort port, boolean install) {
562 NetworkType type = osNetworkService.network(port.networkId()).getNetworkType();
563
564 switch (type) {
565 case VXLAN:
566 setArpReplyRuleVxlan(port, install);
567 break;
568 case VLAN:
569 // TODO: handle VLAN differently
570 break;
571 default:
572 break;
573 }
574 }
575
576 /**
577 * Installs flow rules to match ARP request packets only for VxLAN.
578 *
579 * @param port instance port
580 * @param install installation flag
581 */
582 private void setRemoteArpRequestRuleForVxlan(InstancePort port, boolean install) {
583
584 OpenstackNode localNode = osNodeService.node(port.deviceId());
585
586 TrafficSelector selector = DefaultTrafficSelector.builder()
587 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
588 .matchArpOp(ARP.OP_REQUEST)
589 .matchArpTpa(port.ipAddress().getIp4Address())
590 .build();
591
592 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
593 }
594
595 /**
596 * Installs flow rules to match ARP reply packets only for VxLAN.
597 *
598 * @param port instance port
599 * @param install installation flag
600 */
601 private void setArpReplyRuleVxlan(InstancePort port, boolean install) {
602
603 OpenstackNode localNode = osNodeService.node(port.deviceId());
604
605 TrafficSelector selector = DefaultTrafficSelector.builder()
606 .matchEthType(EthType.EtherType.ARP.ethType().toShort())
607 .matchArpOp(ARP.OP_REPLY)
608 .matchArpTpa(port.ipAddress().getIp4Address())
609 .matchArpTha(port.macAddress())
610 .build();
611
612 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
613 .setOutput(port.portNumber())
614 .build();
615
616 osFlowRuleService.setRule(
617 appId,
618 port.deviceId(),
619 selector,
620 treatment,
621 PRIORITY_ARP_REPLY_RULE,
622 DHCP_ARP_TABLE,
623 install
624 );
625
626 setRemoteArpTreatmentForVxlan(selector, port, localNode, install);
627 }
628
629 // a helper method
630 private void setRemoteArpTreatmentForVxlan(TrafficSelector selector,
631 InstancePort port,
632 OpenstackNode localNode,
633 boolean install) {
634 for (OpenstackNode remoteNode : osNodeService.completeNodes(COMPUTE)) {
635 if (!remoteNode.intgBridge().equals(port.deviceId())) {
636 TrafficTreatment treatmentToRemote = DefaultTrafficTreatment.builder()
637 .extension(buildExtension(
638 deviceService,
639 remoteNode.intgBridge(),
640 localNode.dataIp().getIp4Address()),
641 remoteNode.intgBridge())
642 .setOutput(remoteNode.tunnelPortNum())
643 .build();
644
645 osFlowRuleService.setRule(
646 appId,
647 remoteNode.intgBridge(),
648 selector,
649 treatmentToRemote,
650 PRIORITY_ARP_REQUEST_RULE,
651 DHCP_ARP_TABLE,
652 install
653 );
654 }
655 }
656 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900657 }
Hyunsun Moonb974fca2016-06-30 21:20:39 -0700658}