move vpnservice and cleanup poms
[netvirt.git] / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / listeners / AclInterfaceListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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 package org.opendaylight.netvirt.aclservice.listeners;
9
10 import java.util.ArrayList;
11 import java.util.HashSet;
12 import java.util.List;
13 import javax.annotation.PostConstruct;
14 import javax.inject.Inject;
15 import javax.inject.Singleton;
16 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
20 import org.opendaylight.genius.mdsalutil.NwConstants;
21 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
22 import org.opendaylight.netvirt.aclservice.api.AclServiceManager;
23 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
24 import org.opendaylight.netvirt.aclservice.api.utils.AclInterface;
25 import org.opendaylight.netvirt.aclservice.utils.AclClusterUtil;
26 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
27 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionEgress;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionIngress;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 @Singleton
40 public class AclInterfaceListener extends AsyncDataTreeChangeListenerBase<Interface, AclInterfaceListener>
41         implements ClusteredDataTreeChangeListener<Interface> {
42     private static final Logger LOG = LoggerFactory.getLogger(AclInterfaceListener.class);
43
44     private final AclServiceManager aclServiceManager;
45     private final AclClusterUtil aclClusterUtil;
46     private final DataBroker dataBroker;
47     private final AclDataUtil aclDataUtil;
48     private final AclInterfaceCache aclInterfaceCache;
49     private final AclServiceUtils aclServiceUtils;
50
51     @Inject
52     public AclInterfaceListener(AclServiceManager aclServiceManager, AclClusterUtil aclClusterUtil,
53             DataBroker dataBroker, AclDataUtil aclDataUtil, AclInterfaceCache aclInterfaceCache,
54             AclServiceUtils aclServicUtils) {
55         super(Interface.class, AclInterfaceListener.class);
56         this.aclServiceManager = aclServiceManager;
57         this.aclClusterUtil = aclClusterUtil;
58         this.dataBroker = dataBroker;
59         this.aclDataUtil = aclDataUtil;
60         this.aclInterfaceCache = aclInterfaceCache;
61         this.aclServiceUtils = aclServicUtils;
62     }
63
64     @Override
65     @PostConstruct
66     public void init() {
67         LOG.info("{} start", getClass().getSimpleName());
68         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
69     }
70
71     @Override
72     protected InstanceIdentifier<Interface> getWildCardPath() {
73         return InstanceIdentifier
74                 .create(Interfaces.class)
75                 .child(Interface.class);
76     }
77
78     @Override
79     protected void remove(InstanceIdentifier<Interface> key, Interface port) {
80         LOG.trace("Received AclInterface remove event, port={}", port);
81         String interfaceId = port.getName();
82         AclInterface aclInterface = aclInterfaceCache.remove(interfaceId);
83         if (AclServiceUtils.isOfInterest(aclInterface)) {
84             if (aclClusterUtil.isEntityOwner()) {
85                 LOG.debug("On remove event, notify ACL service manager to unbind ACL from interface: {}", port);
86                 aclServiceManager.notify(aclInterface, null, Action.UNBIND);
87                 AclServiceUtils.deleteSubnetIpPrefixes(dataBroker, interfaceId);
88             }
89         }
90     }
91
92     @Override
93     protected void update(InstanceIdentifier<Interface> key, Interface portBefore, Interface portAfter) {
94         if (portBefore.getAugmentation(ParentRefs.class) == null
95                 && portAfter.getAugmentation(ParentRefs.class) != null) {
96             LOG.trace("Ignoring event for update in ParentRefs for {} ", portAfter.getName());
97             return;
98         }
99         LOG.trace("Received AclInterface update event, portBefore={}, portAfter={}", portBefore, portAfter);
100         InterfaceAcl aclInPortAfter = portAfter.getAugmentation(InterfaceAcl.class);
101         InterfaceAcl aclInPortBefore = portBefore.getAugmentation(InterfaceAcl.class);
102
103         String interfaceId = portAfter.getName();
104         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
105             .Interface interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, interfaceId);
106
107         AclInterface aclInterfaceBefore = aclInterfaceCache.get(interfaceId);
108         if (aclInterfaceBefore == null || isPortSecurityEnabledNow(aclInPortBefore, aclInPortAfter)) {
109             // Updating cache now as it might have not updated when
110             // port-security-enable=false
111             aclInterfaceBefore = addOrUpdateAclInterfaceCache(interfaceId, aclInPortBefore, true, interfaceState);
112         }
113         if (aclInPortAfter != null && aclInPortAfter.isPortSecurityEnabled()
114                 || aclInPortBefore != null && aclInPortBefore.isPortSecurityEnabled()) {
115             boolean isSgChanged =
116                     isSecurityGroupsChanged(aclInPortBefore.getSecurityGroups(), aclInPortAfter.getSecurityGroups());
117             AclInterface aclInterfaceAfter =
118                     addOrUpdateAclInterfaceCache(interfaceId, aclInPortAfter, isSgChanged, interfaceState);
119
120             if (aclClusterUtil.isEntityOwner()) {
121                 // Handle bind/unbind service irrespective of interface state (up/down)
122                 boolean isPortSecurityEnable = aclInterfaceAfter.isPortSecurityEnabled();
123                 boolean isPortSecurityEnableBefore = aclInterfaceBefore.isPortSecurityEnabled();
124                 // if port security enable is changed, bind/unbind ACL service
125                 if (isPortSecurityEnableBefore != isPortSecurityEnable) {
126                     LOG.debug("Notify bind/unbind ACL service for interface={}, isPortSecurityEnable={}", interfaceId,
127                             isPortSecurityEnable);
128                     if (isPortSecurityEnable) {
129                         aclServiceManager.notify(aclInterfaceAfter, null, Action.BIND);
130                     } else {
131                         aclServiceManager.notify(aclInterfaceAfter, null, Action.UNBIND);
132                     }
133                 }
134                 if (interfaceState != null && interfaceState.getOperStatus().equals(
135                         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
136                             .state.Interface.OperStatus.Up)) {
137                     LOG.debug("On update event, notify ACL service manager to update ACL for interface: {}",
138                             interfaceId);
139                     // handle add for AclPortsLookup before processing update
140                     AclServiceUtils.updateAclPortsLookupForInterfaceUpdate(aclInterfaceBefore, aclInterfaceAfter,
141                             dataBroker, NwConstants.ADD_FLOW);
142
143                     aclServiceManager.notify(aclInterfaceAfter, aclInterfaceBefore, AclServiceManager.Action.UPDATE);
144                     // handle delete for AclPortsLookup after processing update
145                     AclServiceUtils.updateAclPortsLookupForInterfaceUpdate(aclInterfaceBefore, aclInterfaceAfter,
146                             dataBroker, NwConstants.DEL_FLOW);
147                 }
148             }
149             updateCacheWithAclChange(aclInterfaceBefore, aclInterfaceAfter);
150         }
151     }
152
153     private void updateCacheWithAclChange(AclInterface aclInterfaceBefore, AclInterface aclInterfaceAfter) {
154         List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(aclInterfaceAfter.getSecurityGroups(),
155                 aclInterfaceBefore.getSecurityGroups());
156         List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(aclInterfaceBefore.getSecurityGroups(),
157                 aclInterfaceAfter.getSecurityGroups());
158         if (deletedAcls != null && !deletedAcls.isEmpty()) {
159             aclDataUtil.removeAclInterfaceMap(deletedAcls, aclInterfaceAfter);
160         }
161         if (addedAcls != null && !addedAcls.isEmpty()) {
162             aclDataUtil.addOrUpdateAclInterfaceMap(addedAcls, aclInterfaceAfter);
163         }
164     }
165
166     private boolean isPortSecurityEnabledNow(InterfaceAcl aclInPortBefore, InterfaceAcl aclInPortAfter) {
167         return aclInPortBefore != null && !aclInPortBefore.isPortSecurityEnabled() && aclInPortAfter != null
168                 && aclInPortAfter.isPortSecurityEnabled();
169     }
170
171     private boolean isSecurityGroupsChanged(List<Uuid> sgsBefore, List<Uuid> sgsAfter) {
172         if (sgsBefore == null && sgsAfter == null) {
173             return false;
174         }
175         if ((sgsBefore == null && sgsAfter != null) || (sgsBefore != null && sgsAfter == null)) {
176             return true;
177         }
178         if (sgsBefore != null && sgsAfter != null) {
179             return !(new HashSet<>(sgsBefore)).equals(new HashSet<>(sgsAfter));
180         }
181         return true;
182     }
183
184     private AclInterface addOrUpdateAclInterfaceCache(String interfaceId, InterfaceAcl aclInPort) {
185         return addOrUpdateAclInterfaceCache(interfaceId, aclInPort, true, null);
186     }
187
188     private AclInterface addOrUpdateAclInterfaceCache(String interfaceId, InterfaceAcl aclInPort, boolean isSgChanged,
189             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
190                     .Interface interfaceState) {
191         AclInterface aclInterface = aclInterfaceCache.addOrUpdate(interfaceId, (prevAclInterface, builder) -> {
192             List<Uuid> sgs = new ArrayList<>();
193             if (aclInPort != null) {
194                 sgs = aclInPort.getSecurityGroups();
195                 builder.portSecurityEnabled(aclInPort.isPortSecurityEnabled()).securityGroups(sgs)
196                         .allowedAddressPairs(aclInPort.getAllowedAddressPairs());
197             }
198
199             if ((prevAclInterface == null || prevAclInterface.getLPortTag() == null) && interfaceState != null) {
200                 builder.dpId(AclServiceUtils.getDpIdFromIterfaceState(interfaceState))
201                         .lPortTag(interfaceState.getIfIndex()).isMarkedForDelete(false);
202             }
203
204             if (prevAclInterface == null) {
205                 builder.subnetIpPrefixes(AclServiceUtils.getSubnetIpPrefixes(dataBroker, interfaceId));
206             }
207             if (prevAclInterface == null || prevAclInterface.getElanId() == null) {
208                 builder.elanId(AclServiceUtils.getElanIdFromInterface(interfaceId, dataBroker));
209             }
210             if (prevAclInterface == null || isSgChanged) {
211                 builder.ingressRemoteAclTags(aclServiceUtils.getRemoteAclTags(sgs, DirectionIngress.class))
212                         .egressRemoteAclTags(aclServiceUtils.getRemoteAclTags(sgs, DirectionEgress.class));
213             }
214         });
215         // Clone and return the ACL interface object
216         return AclInterface.builder(aclInterface).build();
217     }
218
219     @Override
220     protected void add(InstanceIdentifier<Interface> key, Interface port) {
221         LOG.trace("Received AclInterface add event, port={}", port);
222         InterfaceAcl aclInPort = port.getAugmentation(InterfaceAcl.class);
223         if (aclInPort != null && aclInPort.isPortSecurityEnabled()) {
224             String interfaceId = port.getName();
225             AclInterface aclInterface = addOrUpdateAclInterfaceCache(interfaceId, aclInPort);
226
227             if (aclClusterUtil.isEntityOwner()) {
228                 LOG.debug("On add event, notify ACL service manager to bind ACL for interface: {}", port);
229                 aclServiceManager.notify(aclInterface, null, Action.BIND);
230             }
231         }
232     }
233
234     @Override
235     protected AclInterfaceListener getDataTreeChangeListener() {
236         return this;
237     }
238 }