aedf9800c9d4529cc3ae16ddd14156b00931744e
[ovsdb.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / impl / DistributedArpService.java
1 /*
2  * Copyright (c) 2016 NEC Corporation and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.ovsdb.openstack.netvirt.impl;
10
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.util.List;
14
15 import com.google.common.base.Preconditions;
16
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Action;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.ArpProvider;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
20 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
22 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
25 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
26 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
27 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
28 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
29 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
31 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
34 import org.osgi.framework.ServiceReference;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * ARP flows programmed for Neutron port.
40  */
41 public class DistributedArpService implements ConfigInterface {
42
43     private static final Logger LOG = LoggerFactory.getLogger(DistributedArpService.class);
44     // The implementation for each of these services is resolved by the OSGi Service Manager
45     private volatile ConfigurationService configurationService;
46     private volatile TenantNetworkManager tenantNetworkManager;
47     private volatile NodeCacheManager nodeCacheManager;
48     private volatile INeutronNetworkCRUD neutronNetworkCache;
49     private volatile INeutronPortCRUD neutronPortCache;
50     private volatile ArpProvider arpProvider;
51     private volatile NeutronL3Adapter neutronL3Adapter;
52
53     private Southbound southbound;
54     private Boolean flgDistributedARPEnabled = true;
55
56     private void initMembers() {
57         Preconditions.checkNotNull(configurationService);
58         if (configurationService.isDistributedArpDisabled()) {
59             this.flgDistributedARPEnabled = false;
60             LOG.debug("Distributed ARP responder is disabled");
61         } else {
62             LOG.debug("Distributed ARP responder is enabled");
63         }
64     }
65
66      /**
67      * Process the port event to write Arp rules for neutron ports.
68      *
69      * @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
70      * @param neutronPort An instance of NeutronPort object.
71      */
72     public void handlePortEvent(NeutronPort neutronPort, Action action) {
73         LOG.debug("neutronPort Event {} action event {} ", neutronPort, action);
74         if (action == Action.DELETE) {
75             this.handleNeutornPortForArp(neutronPort, action);
76         } else {
77             for (NeutronPort neutronPort1 : neutronPortCache.getAllPorts()) {
78                this.handleNeutornPortForArp(neutronPort1, action);
79             }
80         }
81     }
82
83      /**
84      * Arp rules are added/removed based on neutron port event
85      *
86      */
87     boolean programStaticRuleStage1(Long dpid, String segOrOfPort,
88                                            String macAddress, String ipStr,
89                                            Action action) {
90         if (action == Action.DELETE ) {
91             LOG.trace("Deleting Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {}",
92                          dpid, segOrOfPort, macAddress, ipStr, action);
93         }
94         if (action == Action.ADD) {
95             LOG.trace("Adding Flow : programStaticArpStage1 dpid {} segOrOfPort {} mac {} ip {} action {}",
96                          dpid, segOrOfPort, macAddress, ipStr, action);
97         }
98
99         Status status = this.programStaticRuleStage2(dpid, segOrOfPort, macAddress, ipStr, action);
100         return status.isSuccess();
101     }
102
103      /**
104      * Arp rules are programmed by invoke arpProvider
105      *
106      */
107     private Status programStaticRuleStage2(Long dpid,
108                                           String segOrOfPort,
109                                           String macAddress,
110                                           String address,
111                                           Action action) {
112         Status status;
113         try {
114             InetAddress inetAddress = InetAddress.getByName(address);
115             status = arpProvider == null ?
116                      new Status(StatusCode.SUCCESS) :
117                      arpProvider.programStaticArpEntry(dpid, segOrOfPort,
118                                                        macAddress, inetAddress, action);
119         } catch (UnknownHostException e) {
120             status = new Status(StatusCode.BADREQUEST);
121         }
122
123         if (status.isSuccess()) {
124             LOG.debug("programStaticRuleStage2 {} for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{}",
125                          arpProvider == null ? "skipped" : "programmed",
126                          macAddress, address, dpid, segOrOfPort, action);
127         } else {
128             LOG.error("programStaticRuleStage2 failed for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{} status:{}",
129                          macAddress, address, dpid, segOrOfPort, action, status);
130         }
131         return status;
132     }
133
134     /**
135      * Write Arp rules based on event for neutron port.
136      *
137      * @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
138      * @param neutronPort An instance of NeutronPort object.
139      */
140     private void handleNeutornPortForArp(NeutronPort neutronPort, Action action) {
141
142         final String networkUUID = neutronPort.getNetworkUUID();
143         NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
144         if (null == neutronNetwork) {
145             neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(networkUUID);
146         }
147         final String providerSegmentationId = neutronNetwork != null ?
148                                               neutronNetwork.getProviderSegmentationID() : null;
149         final String tenantMac = neutronPort.getMacAddress();
150         if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
151             tenantMac == null || tenantMac.isEmpty()) {
152             // done: go no further w/out all the info needed...
153             return;
154         }
155
156         final boolean isDelete = action == Action.DELETE;
157         final Action action1 = isDelete ? Action.DELETE : Action.ADD;
158
159
160         List<Node> nodes = nodeCacheManager.getBridgeNodes();
161         if (nodes.isEmpty()) {
162             LOG.trace("updateL3ForNeutronPort has no nodes to work with");
163         }
164         for (Node node : nodes) {
165             final Long dpid = getDatapathIdIntegrationBridge(node);
166             if (dpid == null) {
167                 continue;
168             }
169             if (neutronPort.getFixedIPs() == null) {
170                 continue;
171             }
172             for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
173                 final String tenantIpStr = neutronIP.getIpAddress();
174                 if (tenantIpStr.isEmpty()) {
175                     continue;
176                 }
177                 // Configure distributed ARP responder
178                 if (flgDistributedARPEnabled) {
179                     // Arp rule is only needed when segmentation exists in the given node (bug 4752).
180                     boolean arpNeeded = tenantNetworkManager.isTenantNetworkPresentInNode(node, providerSegmentationId);
181                     final Action actionForNode = arpNeeded ? action1 : Action.DELETE;
182                     programStaticRuleStage1(dpid, providerSegmentationId, tenantMac, tenantIpStr, actionForNode);
183                 }
184             }
185         }
186     }
187
188     /**
189      * Check if node is integration bridge, then return its datapathID.
190      * @param bridgeNode An instance of Node object.
191      */
192     private Long getDatapathIdIntegrationBridge(Node node) {
193         if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
194             return southbound.getDataPathId(node);
195         }
196         return null;
197     }
198
199     /**
200      * Process the event.
201      *
202      * @param bridgeNode An instance of Node object.
203      * @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
204      * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
205      * @param neutronNetwork An {@link org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork} instance of NeutronNetwork
206      * object.
207      * @param action the {@link org.opendaylight.ovsdb.openstack.netvirt.api.Action} action to be handled.
208      */
209     public void processInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
210                                      final NeutronNetwork neutronNetwork, Action action) {
211         LOG.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
212                      action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
213         final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
214         if (neutronPort != null) {
215             this.handlePortEvent(neutronPort, action);
216         }
217     }
218
219     @Override
220     public void setDependencies(ServiceReference serviceReference) {
221         tenantNetworkManager =
222                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
223         configurationService =
224                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
225         arpProvider =
226                 (ArpProvider) ServiceHelper.getGlobalInstance(ArpProvider.class, this);
227         nodeCacheManager =
228                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
229         southbound =
230                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
231         neutronL3Adapter =
232                 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
233         initMembers();
234     }
235
236     @Override
237     public void setDependencies(Object impl) {
238         if (impl instanceof INeutronNetworkCRUD) {
239             neutronNetworkCache = (INeutronNetworkCRUD)impl;
240         } else if (impl instanceof INeutronPortCRUD) {
241             neutronPortCache = (INeutronPortCRUD)impl;
242         } else if (impl instanceof ArpProvider) {
243             arpProvider = (ArpProvider)impl;
244         }
245     }
246
247 }