Merge "Fixes related to ACL service."
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / AbstractAclServiceImpl.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. 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;
9
10 import java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.List;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.genius.mdsalutil.ActionInfo;
15 import org.opendaylight.genius.mdsalutil.ActionType;
16 import org.opendaylight.genius.mdsalutil.FlowEntity;
17 import org.opendaylight.genius.mdsalutil.InstructionInfo;
18 import org.opendaylight.genius.mdsalutil.InstructionType;
19 import org.opendaylight.genius.mdsalutil.MDSALUtil;
20 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
21 import org.opendaylight.genius.mdsalutil.NwConstants;
22 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
23 import org.opendaylight.netvirt.aclservice.api.AclServiceListener;
24 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
25 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeBase;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public abstract class AbstractAclServiceImpl implements AclServiceListener {
37
38     private static final Logger LOG = LoggerFactory.getLogger(AbstractAclServiceImpl.class);
39
40     private final IMdsalApiManager mdsalManager;
41     private final OdlInterfaceRpcService interfaceManager;
42     private final DataBroker dataBroker;
43     private final Class<? extends ServiceModeBase> serviceMode;
44
45     /**
46      * Initialize the member variables.
47      *
48      * @param serviceMode the service mode
49      * @param dataBroker the data broker instance.
50      * @param interfaceManager the interface manager instance.
51      * @param mdsalManager the mdsal manager instance.
52      */
53     public AbstractAclServiceImpl(Class<? extends ServiceModeBase> serviceMode, DataBroker dataBroker,
54             OdlInterfaceRpcService interfaceManager, IMdsalApiManager mdsalManager) {
55         this.dataBroker = dataBroker;
56         this.interfaceManager = interfaceManager;
57         this.mdsalManager = mdsalManager;
58         this.serviceMode = serviceMode;
59     }
60
61     @Override
62     public boolean applyAcl(Interface port) {
63
64         if (!AclServiceUtils.isPortSecurityEnabled(port)) {
65             return false;
66         }
67
68         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
69             interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
70         BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
71         if (dpId == null) {
72             LOG.error("Unable to find DP Id from interface state {}", interfaceState.getName());
73             return false;
74         }
75
76         programAclWithAllowedAddress(dpId, AclServiceUtils.getPortAllowedAddresses(port), interfaceState.getIfIndex(),
77                 AclServiceUtils.getInterfaceAcls(port), NwConstants.ADD_FLOW);
78
79         // TODO: uncomment bindservice() when the acl flow programming is
80         // implemented
81         // bindService(port.getName());
82         return true;
83     }
84
85     @Override
86     public boolean updateAcl(Interface portBefore, Interface portAfter) {
87         boolean result = false;
88         boolean isPortSecurityEnable = AclServiceUtils.isPortSecurityEnabled(portAfter);
89         boolean isPortSecurityEnableBefore = AclServiceUtils.isPortSecurityEnabled(portBefore);
90         // if port security is changed, apply/remove Acls
91         if (isPortSecurityEnableBefore != isPortSecurityEnable) {
92             if (isPortSecurityEnable) {
93                 result = applyAcl(portAfter);
94             } else {
95                 result = removeAcl(portAfter);
96             }
97         } else if (isPortSecurityEnable) {
98             // Acls has been updated, find added/removed Acls and act accordingly.
99             this.processInterfaceUpdate(portBefore, portAfter);
100         }
101
102         return result;
103     }
104
105     private void processInterfaceUpdate(Interface portBefore, Interface portAfter) {
106         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
107                 interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, portAfter.getName());
108         BigInteger dpId = AclServiceUtils.getDpIdFromIterfaceState(interfaceState);
109         List<AllowedAddressPairs> addedAllowedAddressPairs =
110                 AclServiceUtils.getUpdatedAllowedAddressPairs(portAfter,portBefore);
111         List<AllowedAddressPairs> deletedAllowedAddressPairs =
112                 AclServiceUtils.getUpdatedAllowedAddressPairs(portBefore, portAfter);
113         if (addedAllowedAddressPairs != null && !addedAllowedAddressPairs.isEmpty()) {
114             programAclWithAllowedAddress(dpId, addedAllowedAddressPairs, interfaceState.getIfIndex(),
115                     AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.ADD_FLOW);
116         }
117         if (deletedAllowedAddressPairs != null && !deletedAllowedAddressPairs.isEmpty()) {
118             programAclWithAllowedAddress(dpId, deletedAllowedAddressPairs, interfaceState.getIfIndex(),
119                     AclServiceUtils.getInterfaceAcls(portAfter), NwConstants.DEL_FLOW);
120         }
121
122         List<Uuid> addedAcls = AclServiceUtils.getUpdatedAclList(portAfter, portBefore);
123         List<Uuid> deletedAcls = AclServiceUtils.getUpdatedAclList(portBefore, portAfter);
124         if (addedAcls != null && !addedAcls.isEmpty()) {
125             updateCustomRules(dpId, interfaceState.getIfIndex(), addedAcls, NwConstants.ADD_FLOW);
126         }
127         if (deletedAcls != null && !deletedAcls.isEmpty()) {
128             updateCustomRules(dpId, interfaceState.getIfIndex(), deletedAcls, NwConstants.DEL_FLOW);
129         }
130     }
131
132     private void updateCustomRules(BigInteger dpId, int lportTag, List<Uuid> aclUuidList, int action) {
133         programAclRules(aclUuidList, dpId, lportTag, action);
134     }
135
136     private void programAclWithAllowedAddress(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses,
137             int lportTag, List<Uuid> aclUuidList, int addOrRemove) {
138         programFixedRules(dpId, "", allowedAddresses, lportTag, addOrRemove);
139         programAclRules(aclUuidList, dpId, lportTag, addOrRemove);
140     }
141
142     @Override
143     public boolean removeAcl(Interface port) {
144         if (!AclServiceUtils.isPortSecurityEnabled(port)) {
145             return false;
146         }
147         BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
148         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
149             interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
150         programAclWithAllowedAddress(dpId, AclServiceUtils.getPortAllowedAddresses(port), interfaceState.getIfIndex(),
151                 AclServiceUtils.getInterfaceAcls(port), NwConstants.DEL_FLOW);
152
153         // TODO: uncomment unbindService() when the acl flow programming is
154         // implemented
155         // unbindService(port.getName());
156         return true;
157     }
158
159     @Override
160     public boolean applyAce(Interface port, Ace ace) {
161         if (!AclServiceUtils.isPortSecurityEnabled(port)) {
162             return false;
163         }
164         BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
165         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
166                 interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
167         programAceRule(dpId, interfaceState.getIfIndex(), NwConstants.ADD_FLOW, ace);
168         return true;
169     }
170
171     @Override
172     public boolean removeAce(Interface port, Ace ace) {
173         if (!AclServiceUtils.isPortSecurityEnabled(port)) {
174             return false;
175         }
176         BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
177         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
178                 interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
179         programAceRule(dpId, interfaceState.getIfIndex(), NwConstants.DEL_FLOW, ace);
180         return true;
181     }
182
183
184     /**
185      * Bind service.
186      *
187      * @param interfaceName the interface name
188      */
189     protected abstract void bindService(String interfaceName);
190
191     /**
192      * Unbind service.
193      *
194      * @param interfaceName the interface name
195      */
196     protected abstract void unbindService(String interfaceName);
197
198     /**
199      * Program the default anti-spoofing rule and the conntrack rules.
200      *
201      * @param dpid the dpid
202      * @param dhcpMacAddress the dhcp mac address.
203      * @param allowedAddresses the allowed addresses
204      * @param lportTag the lport tag
205      * @param addOrRemove addorRemove
206      */
207     protected abstract void programFixedRules(BigInteger dpid, String dhcpMacAddress,
208             List<AllowedAddressPairs> allowedAddresses, int lportTag, int addOrRemove);
209
210     /**
211      * Programs the acl custom rules.
212      *
213      * @param aclUuidList the list of acl uuid to be applied
214      * @param dpId the dpId
215      * @param lportTag the lport tag
216      * @param addOrRemove whether to delete or add flow
217      */
218     protected abstract void programAclRules(List<Uuid> aclUuidList, BigInteger dpId, int lportTag, int addOrRemove);
219
220     /**
221      * Programs the ace custom rule.
222      *
223      * @param dpId the dpId
224      * @param lportTag the lport tag
225      * @param addOrRemove whether to delete or add flow
226      * @param ace rule to be program
227      */
228     protected abstract void programAceRule(BigInteger dpId, int lportTag, int addOrRemove, Ace ace);
229
230     /**
231      * Writes/remove the flow to/from the datastore.
232      * @param dpId the dpId
233      * @param tableId the tableId
234      * @param flowId the flowId
235      * @param priority the priority
236      * @param flowName the flow name
237      * @param idleTimeOut the idle timeout
238      * @param hardTimeOut the hard timeout
239      * @param cookie the cookie
240      * @param matches the list of matches to be writted
241      * @param instructions the list of instruction to be written.
242      * @param addOrRemove add or remove the entries.
243      */
244     protected void syncFlow(BigInteger dpId, short tableId, String flowId, int priority, String flowName,
245                           int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase>  matches,
246                           List<InstructionInfo> instructions, int addOrRemove) {
247         if (addOrRemove == NwConstants.DEL_FLOW) {
248             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,flowId,
249                 priority, flowName , idleTimeOut, hardTimeOut, cookie, matches, null);
250             LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
251             mdsalManager.removeFlow(flowEntity);
252         } else {
253             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId,
254                 priority, flowName, idleTimeOut, hardTimeOut, cookie, matches, instructions);
255             LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
256             mdsalManager.installFlow(flowEntity);
257         }
258     }
259
260     /**
261      * Gets the dispatcher table resubmit instructions based on ingress/egress
262      * service mode w.r.t switch.
263      *
264      * @param actionsInfos the actions infos
265      * @return the instructions for dispatcher table resubmit
266      */
267     protected List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos) {
268         short dispatcherTableId = NwConstants.LPORT_DISPATCHER_TABLE;
269         if (ServiceModeEgress.class.equals(this.serviceMode)) {
270             dispatcherTableId = AclConstants.EGRESS_LPORT_DISPATCHER_TABLE;
271         }
272
273         List<InstructionInfo> instructions = new ArrayList<>();
274         actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] {Short.toString(dispatcherTableId)}));
275         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
276         return instructions;
277     }
278 }