2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.aclservice.listeners;
10 import com.google.common.util.concurrent.Futures;
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.concurrent.ExecutionException;
15 import javax.annotation.PostConstruct;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
22 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
23 import org.opendaylight.netvirt.aclservice.api.AclServiceManager;
24 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
25 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
26 import org.opendaylight.netvirt.aclservice.utils.AclClusterUtil;
27 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
28 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
41 public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interface, AclInterfaceListener>
42 implements ClusteredDataTreeChangeListener<Interface> {
43 private static final Logger LOG = LoggerFactory.getLogger(AclInterfaceListener.class);
45 private final AclServiceManager aclServiceManager;
46 private final AclClusterUtil aclClusterUtil;
47 private final DataBroker dataBroker;
48 private final AclDataUtil aclDataUtil;
49 private final AclInterfaceCache aclInterfaceCache;
50 private final AclServiceUtils aclServiceUtils;
53 public AclInterfaceListener(AclServiceManager aclServiceManager, AclClusterUtil aclClusterUtil,
54 DataBroker dataBroker, AclDataUtil aclDataUtil, AclInterfaceCache aclInterfaceCache,
55 AclServiceUtils aclServicUtils) {
56 super(Interface.class, AclInterfaceListener.class);
57 this.aclServiceManager = aclServiceManager;
58 this.aclClusterUtil = aclClusterUtil;
59 this.dataBroker = dataBroker;
60 this.aclDataUtil = aclDataUtil;
61 this.aclInterfaceCache = aclInterfaceCache;
62 this.aclServiceUtils = aclServicUtils;
68 LOG.info("{} start", getClass().getSimpleName());
69 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
73 protected InstanceIdentifier<Interface> getWildCardPath() {
74 return InstanceIdentifier
75 .create(Interfaces.class)
76 .child(Interface.class);
80 protected void remove(InstanceIdentifier<Interface> key, Interface port) {
81 LOG.trace("Received AclInterface remove event, port={}", port);
82 String interfaceId = port.getName();
83 AclInterface aclInterface = aclInterfaceCache.remove(interfaceId);
84 if (AclServiceUtils.isOfInterest(aclInterface)) {
85 if (aclClusterUtil.isEntityOwner()) {
86 LOG.debug("On remove event, notify ACL service manager to unbind ACL from interface: {}", port);
87 aclServiceManager.notify(aclInterface, null, Action.UNBIND);
88 AclServiceUtils.deleteSubnetIpPrefixes(dataBroker, interfaceId);
94 protected void update(InstanceIdentifier<Interface> key, Interface portBefore, Interface portAfter) {
95 if (portBefore.getAugmentation(ParentRefs.class) == null
96 && portAfter.getAugmentation(ParentRefs.class) != null) {
97 LOG.trace("Ignoring event for update in ParentRefs for {} ", portAfter.getName());
100 LOG.trace("Received AclInterface update event, portBefore={}, portAfter={}", portBefore, portAfter);
101 InterfaceAcl aclInPortAfter = portAfter.getAugmentation(InterfaceAcl.class);
102 InterfaceAcl aclInPortBefore = portBefore.getAugmentation(InterfaceAcl.class);
104 String interfaceId = portAfter.getName();
105 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
106 .Interface interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceId);
108 AclInterface aclInterfaceBefore = aclInterfaceCache.get(interfaceId);
109 if (aclInterfaceBefore == null || isPortSecurityEnabledNow(aclInPortBefore, aclInPortAfter)) {
110 // Updating cache now as it might have not updated when
111 // port-security-enable=false
112 aclInterfaceBefore = addOrUpdateAclInterfaceCache(interfaceId, aclInPortBefore, true, interfaceState);
114 if (aclInPortAfter != null && aclInPortAfter.isPortSecurityEnabled()
115 || aclInPortBefore != null && aclInPortBefore.isPortSecurityEnabled()) {
116 boolean isSgChanged =
117 isSecurityGroupsChanged(aclInPortBefore.getSecurityGroups(), aclInPortAfter.getSecurityGroups());
118 AclInterface aclInterfaceAfter =
119 addOrUpdateAclInterfaceCache(interfaceId, aclInPortAfter, isSgChanged, interfaceState);
121 if (aclClusterUtil.isEntityOwner()) {
122 // Handle bind/unbind service irrespective of interface state (up/down)
123 boolean isPortSecurityEnable = aclInterfaceAfter.isPortSecurityEnabled();
124 boolean isPortSecurityEnableBefore = aclInterfaceBefore.isPortSecurityEnabled();
125 // if port security enable is changed, bind/unbind ACL service
126 if (isPortSecurityEnableBefore != isPortSecurityEnable) {
127 LOG.debug("Notify bind/unbind ACL service for interface={}, isPortSecurityEnable={}", interfaceId,
128 isPortSecurityEnable);
129 if (isPortSecurityEnable) {
130 aclServiceManager.notify(aclInterfaceAfter, null, Action.BIND);
132 aclServiceManager.notify(aclInterfaceAfter, null, Action.UNBIND);
135 if (interfaceState != null && interfaceState.getOperStatus().equals(
136 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
137 .state.Interface.OperStatus.Up)) {
138 LOG.debug("On update event, notify ACL service manager to update ACL for interface: {}",
140 // handle add for AclPortsLookup before processing update
142 Futures.allAsList(aclServiceUtils.addAclPortsLookupForInterfaceUpdate(aclInterfaceBefore,
143 aclInterfaceAfter)).get();
144 } catch (InterruptedException | ExecutionException e) {
145 LOG.error("Error adding ACL ports for interface update", e);
148 aclServiceManager.notify(aclInterfaceAfter, aclInterfaceBefore, AclServiceManager.Action.UPDATE);
149 // handle delete for AclPortsLookup after processing update
151 Futures.allAsList(aclServiceUtils.deleteAclPortsLookupForInterfaceUpdate(aclInterfaceBefore,
152 aclInterfaceAfter)).get();
153 } catch (InterruptedException | ExecutionException e) {
154 LOG.error("Error deleting ACL ports for interface update", e);
158 updateCacheWithAclChange(aclInterfaceBefore, aclInterfaceAfter);
162 private void updateCacheWithAclChange(AclInterface aclInterfaceBefore, AclInterface aclInterfaceAfter) {
163 List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(aclInterfaceAfter.getSecurityGroups(),
164 aclInterfaceBefore.getSecurityGroups());
165 List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(aclInterfaceBefore.getSecurityGroups(),
166 aclInterfaceAfter.getSecurityGroups());
167 if (deletedAcls != null && !deletedAcls.isEmpty()) {
168 aclDataUtil.removeAclInterfaceMap(deletedAcls, aclInterfaceAfter);
170 if (addedAcls != null && !addedAcls.isEmpty()) {
171 aclDataUtil.addOrUpdateAclInterfaceMap(addedAcls, aclInterfaceAfter);
175 private boolean isPortSecurityEnabledNow(InterfaceAcl aclInPortBefore, InterfaceAcl aclInPortAfter) {
176 return aclInPortBefore != null && !aclInPortBefore.isPortSecurityEnabled() && aclInPortAfter != null
177 && aclInPortAfter.isPortSecurityEnabled();
180 private boolean isSecurityGroupsChanged(List<Uuid> sgsBefore, List<Uuid> sgsAfter) {
181 if (sgsBefore == null && sgsAfter == null) {
184 if ((sgsBefore == null && sgsAfter != null) || (sgsBefore != null && sgsAfter == null)) {
187 if (sgsBefore != null && sgsAfter != null) {
188 return !(new HashSet<>(sgsBefore)).equals(new HashSet<>(sgsAfter));
193 private AclInterface addOrUpdateAclInterfaceCache(String interfaceId, InterfaceAcl aclInPort) {
194 return addOrUpdateAclInterfaceCache(interfaceId, aclInPort, true, null);
197 private AclInterface addOrUpdateAclInterfaceCache(String interfaceId, InterfaceAcl aclInPort, boolean isSgChanged,
198 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
199 .Interface interfaceState) {
200 AclInterface aclInterface = aclInterfaceCache.addOrUpdate(interfaceId, (prevAclInterface, builder) -> {
201 List<Uuid> sgs = new ArrayList<>();
202 if (aclInPort != null) {
203 sgs = aclInPort.getSecurityGroups();
204 builder.portSecurityEnabled(aclInPort.isPortSecurityEnabled()).securityGroups(sgs)
205 .allowedAddressPairs(aclInPort.getAllowedAddressPairs());
208 if ((prevAclInterface == null || prevAclInterface.getLPortTag() == null) && interfaceState != null) {
209 builder.dpId(AclServiceUtils.getDpIdFromIterfaceState(interfaceState))
210 .lPortTag(interfaceState.getIfIndex()).isMarkedForDelete(false);
213 if (prevAclInterface == null) {
214 builder.subnetIpPrefixes(AclServiceUtils.getSubnetIpPrefixes(dataBroker, interfaceId));
216 if (prevAclInterface == null || prevAclInterface.getElanId() == null) {
217 builder.elanId(AclServiceUtils.getElanIdFromInterface(interfaceId, dataBroker));
219 if (prevAclInterface == null || isSgChanged) {
220 builder.ingressRemoteAclTags(aclServiceUtils.getRemoteAclTags(sgs, DirectionIngress.class))
221 .egressRemoteAclTags(aclServiceUtils.getRemoteAclTags(sgs, DirectionEgress.class));
224 // Clone and return the ACL interface object
225 return AclInterface.builder(aclInterface).build();
229 protected void add(InstanceIdentifier<Interface> key, Interface port) {
230 LOG.trace("Received AclInterface add event, port={}", port);
231 InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
232 if (aclInPort != null && aclInPort.isPortSecurityEnabled()) {
233 String interfaceId = port.getName();
234 AclInterface aclInterface = addOrUpdateAclInterfaceCache(interfaceId, aclInPort);
236 if (aclClusterUtil.isEntityOwner()) {
237 LOG.debug("On add event, notify ACL service manager to bind ACL for interface: {}", port);
238 aclServiceManager.notify(aclInterface, null, Action.BIND);
244 protected AclInterfaceListener getDataTreeChangeListener() {