Bug 8400 - ACL changes doesn't affect the existing connections
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / StatefulEgressAclServiceImpl.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 java.util.Map;
14 import java.util.stream.Collectors;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.genius.mdsalutil.ActionInfo;
17 import org.opendaylight.genius.mdsalutil.InstructionInfo;
18 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
19 import org.opendaylight.genius.mdsalutil.NwConstants;
20 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack;
21 import org.opendaylight.genius.mdsalutil.actions.ActionNxConntrack.NxCtAction;
22 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
23 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetSource;
25 import org.opendaylight.genius.mdsalutil.nxmatches.NxMatchCtState;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.netvirt.aclservice.api.AclInterfaceCache;
28 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.Action;
29 import org.opendaylight.netvirt.aclservice.api.AclServiceManager.MatchCriteria;
30 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
31 import org.opendaylight.netvirt.aclservice.utils.AclDataUtil;
32 import org.opendaylight.netvirt.aclservice.utils.AclServiceOFFlowBuilder;
33 import org.opendaylight.netvirt.aclservice.utils.AclServiceUtils;
34 import org.opendaylight.netvirt.aclservice.utils.StatefulAclServiceHelper;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.actions.PacketHandling;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.actions.packet.handling.Permit;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIp;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeEgress;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.IpPrefixOrAddress;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 /**
47  * Provides the stateful implementation for egress (w.r.t VM) ACL service.
48  *
49  * <p>
50  * Note: Table names used are w.r.t switch. Hence, switch ingress is VM egress
51  * and vice versa.
52  */
53
54 public class StatefulEgressAclServiceImpl extends AbstractEgressAclServiceImpl {
55
56     private static final Logger LOG = LoggerFactory.getLogger(StatefulEgressAclServiceImpl.class);
57
58     public StatefulEgressAclServiceImpl(DataBroker dataBroker, IMdsalApiManager mdsalManager, AclDataUtil aclDataUtil,
59             AclServiceUtils aclServiceUtils, JobCoordinator jobCoordinator, AclInterfaceCache aclInterfaceCache) {
60         super(dataBroker, mdsalManager, aclDataUtil, aclServiceUtils, jobCoordinator, aclInterfaceCache);
61     }
62
63     /**
64      * Program conntrack rules.
65      *
66      * @param dpid the dpid
67      * @param dhcpMacAddress the dhcp mac address.
68      * @param allowedAddresses the allowed addresses
69      * @param lportTag the lport tag
70      * @param addOrRemove addorRemove
71      */
72     @Override
73     protected void programSpecificFixedRules(BigInteger dpid, String dhcpMacAddress,
74             List<AllowedAddressPairs> allowedAddresses, int lportTag, String portId, Action action, int addOrRemove) {
75         programEgressAclFixedConntrackRule(dpid, allowedAddresses, lportTag, portId, action, addOrRemove);
76     }
77
78     @Override
79     protected String syncSpecificAclFlow(BigInteger dpId, int lportTag, int addOrRemove, Ace ace, String portId,
80             Map<String, List<MatchInfoBase>> flowMap, String flowName) {
81
82         Long elanId = getElanIdFromAclInterface(portId);
83         List<ActionInfo> actionsInfos = new ArrayList<>();
84         List<InstructionInfo> instructions;
85         PacketHandling packetHandling = ace.getActions() != null ? ace.getActions().getPacketHandling() : null;
86         if (packetHandling instanceof Permit) {
87             List<NxCtAction> ctActionsList = new ArrayList<>();
88             NxCtAction nxCtMarkSetAction = new ActionNxConntrack.NxCtMark(AclConstants.CT_MARK_EST_STATE);
89             ctActionsList.add(nxCtMarkSetAction);
90
91             ActionNxConntrack actionNxConntrack = new ActionNxConntrack(2, 1, 0, elanId.intValue(),
92                     (short) 255, ctActionsList);
93             actionsInfos.add(actionNxConntrack);
94             instructions = getDispatcherTableResubmitInstructions(actionsInfos);
95         } else {
96             instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
97         }
98         List<MatchInfoBase> matches = flowMap.get(flowName);
99         matches.add(buildLPortTagMatch(lportTag));
100         matches.add(new NxMatchCtState(AclConstants.TRACKED_CT_STATE, AclConstants.TRACKED_CT_STATE_MASK));
101         AceIp acl = (AceIp) ace.getMatches().getAceType();
102         final String applyChangeOnExistingTrafficFlowName = flowName + "Egress" + lportTag
103                 + ((acl.getAceIpVersion() instanceof AceIpv4) ? "_IPv4" : "_IPv6") + "_FlowAfterRuleDeleted";
104         flowName += "Egress" + lportTag + ace.getKey().getRuleName();
105         String poolName = AclServiceUtils.getAclPoolName(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE, packetHandling);
106         // For flows related remote ACL, unique flow priority is used for
107         // each flow to avoid overlapping flows
108         int priority = getAclFlowPriority(poolName, flowName, addOrRemove);
109
110         syncFlow(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE, flowName, priority, "ACL", 0, 0,
111             AclConstants.COOKIE_ACL_BASE, matches, instructions,
112             (addOrRemove == NwConstants.MOD_FLOW) ? NwConstants.DEL_FLOW : addOrRemove);
113
114         if (addOrRemove != NwConstants.DEL_FLOW) {
115             final List<MatchInfoBase> applyChangeOnExistingTrafficFlowMatches = matches.stream()
116                 .filter(obj -> !(obj instanceof NxMatchCtState))
117                 .collect(Collectors.toList());
118             applyChangeOnExistingTrafficFlowMatches.add(new NxMatchCtState(AclConstants.TRACKED_RPL_CT_STATE,
119                 AclConstants.TRACKED_RPL_CT_STATE_MASK));
120
121             instructions = StatefulAclServiceHelper.createCtMarkInstructionForNewState(getEgressAclFilterTable(),
122                     elanId);
123             syncFlow(dpId, NwConstants.INGRESS_ACL_STATEFUL_APPLY_CHANGE_EXIST_TRAFFIC_TABLE,
124                 applyChangeOnExistingTrafficFlowName, priority, "ACL",
125                 0, StatefulAclServiceHelper.getHardTimoutForApplyStatefulChangeOnExistingTraffic(ace, aclServiceUtils),
126                 AclConstants.COOKIE_ACL_BASE, applyChangeOnExistingTrafficFlowMatches,
127                 instructions, (addOrRemove == NwConstants.ADD_FLOW) ? 1 : 0);
128         }
129
130         return flowName;
131     }
132
133     /**
134      * Adds the rule to send the packet to the netfilter to check whether it is
135      * a known packet.
136      *
137      * @param dpId the dpId
138      * @param allowedAddresses the allowed addresses
139      * @param priority the priority of the flow
140      * @param flowId the flowId
141      * @param conntrackState the conntrack state of the packets thats should be
142      *        send
143      * @param conntrackMask the conntrack mask
144      * @param portId the portId
145      * @param addOrRemove whether to add or remove the flow
146      */
147     private void programConntrackRecircRules(BigInteger dpId, List<AllowedAddressPairs> allowedAddresses,
148             Integer priority, String flowId, String portId, int addOrRemove) {
149         for (AllowedAddressPairs allowedAddress : allowedAddresses) {
150             IpPrefixOrAddress attachIp = allowedAddress.getIpAddress();
151             MacAddress attachMac = allowedAddress.getMacAddress();
152
153             List<MatchInfoBase> matches = new ArrayList<>();
154             matches.add(new MatchEthernetSource(attachMac));
155             matches.addAll(AclServiceUtils.buildIpMatches(attachIp, MatchCriteria.MATCH_SOURCE));
156
157             Long elanTag = getElanIdFromAclInterface(portId);
158             List<InstructionInfo> instructions = new ArrayList<>();
159             List<ActionInfo> actionsInfos = new ArrayList<>();
160             actionsInfos.add(new ActionNxConntrack(2, 0, 0, elanTag.intValue(),
161                     NwConstants.INGRESS_ACL_REMOTE_ACL_TABLE));
162             instructions.add(new InstructionApplyActions(actionsInfos));
163
164             String flowName = "Egress_Fixed_Conntrk_" + dpId + "_" + attachMac.getValue() + "_"
165                     + String.valueOf(attachIp.getValue()) + "_" + flowId;
166             syncFlow(dpId, NwConstants.INGRESS_ACL_TABLE, flowName, AclConstants.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
167                     AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
168         }
169     }
170
171     /**
172      * Programs the default connection tracking rules.
173      *
174      * @param dpid the dp id
175      * @param allowedAddresses the allowed addresses
176      * @param lportTag the lport tag
177      * @param portId the portId
178      * @param action the action
179      * @param write whether to add or remove the flow.
180      */
181     private void programEgressAclFixedConntrackRule(BigInteger dpid, List<AllowedAddressPairs> allowedAddresses,
182             int lportTag, String portId, Action action, int write) {
183         programConntrackRecircRules(dpid, allowedAddresses, AclConstants.CT_STATE_UNTRACKED_PRIORITY,
184             "Recirc", portId, write);
185         programEgressConntrackDropRules(dpid, lportTag, write);
186         LOG.info("programEgressAclFixedConntrackRule :  default connection tracking rule are {} on DpId {}"
187                 + "lportTag {}.", write == NwConstants.ADD_FLOW ? "added" : "removed", dpid, lportTag);
188     }
189
190     /**
191      * Adds the rule to drop the unknown/invalid packets .
192      *
193      * @param dpId the dpId
194      * @param lportTag the lport tag
195      * @param priority the priority of the flow
196      * @param flowId the flowId
197      * @param conntrackState the conntrack state of the packets thats should be
198      *        send
199      * @param conntrackMask the conntrack mask
200      * @param tableId table id
201      * @param addOrRemove whether to add or remove the flow
202      */
203     private void programConntrackDropRule(BigInteger dpId, int lportTag, Integer priority, String flowId,
204             int conntrackState, int conntrackMask, int addOrRemove) {
205         List<MatchInfoBase> matches = AclServiceOFFlowBuilder.addLPortTagMatches(lportTag, conntrackState,
206                 conntrackMask, ServiceModeEgress.class);
207         List<InstructionInfo> instructions = AclServiceOFFlowBuilder.getDropInstructionInfo();
208
209         flowId = "Ingress_Fixed_Conntrk_Drop" + dpId + "_" + lportTag + "_" + flowId;
210         syncFlow(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE, flowId, priority, "ACL", 0, 0,
211                 AclConstants.COOKIE_ACL_DROP_FLOW, matches, instructions, addOrRemove);
212     }
213
214     /**
215      * Adds the rules to drop the unknown/invalid packets .
216      *
217      * @param dpId the dpId
218      * @param lportTag the lport tag
219      * @param addOrRemove whether to add or remove the flow
220      */
221     private void programEgressConntrackDropRules(BigInteger dpId, int lportTag, int addOrRemove) {
222         LOG.debug("Applying Egress ConnTrack Drop Rules on DpId {}, lportTag {}", dpId, lportTag);
223         programConntrackDropRule(dpId, lportTag, AclConstants.CT_STATE_TRACKED_NEW_DROP_PRIORITY, "Tracked_New",
224                 AclConstants.TRACKED_CT_STATE, AclConstants.TRACKED_CT_STATE_MASK, addOrRemove);
225         programConntrackDropRule(dpId, lportTag, AclConstants.CT_STATE_TRACKED_INVALID_PRIORITY, "Tracked_Invalid",
226                 AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, addOrRemove);
227     }
228 }