ACL: Using non-deprecated ACL constants
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / listeners / AclNodeListener.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
9 package org.opendaylight.netvirt.aclservice.listeners;
10
11 import com.google.common.base.Optional;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
17 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
18 import org.opendaylight.genius.mdsalutil.ActionInfo;
19 import org.opendaylight.genius.mdsalutil.ActionType;
20 import org.opendaylight.genius.mdsalutil.FlowEntity;
21 import org.opendaylight.genius.mdsalutil.InstructionInfo;
22 import org.opendaylight.genius.mdsalutil.InstructionType;
23 import org.opendaylight.genius.mdsalutil.MDSALDataStoreUtils;
24 import org.opendaylight.genius.mdsalutil.MDSALUtil;
25 import org.opendaylight.genius.mdsalutil.MatchFieldType;
26 import org.opendaylight.genius.mdsalutil.MatchInfo;
27 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
28 import org.opendaylight.genius.mdsalutil.NwConstants;
29 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
30 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
31 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
32 import org.opendaylight.netvirt.aclservice.utils.AclConstants;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig.SecurityGroupMode;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.config.rev160806.AclserviceConfig;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 /**
44  * Listener to handle flow capable node updates.
45  */
46 @SuppressWarnings("deprecation")
47 public class AclNodeListener extends AsyncDataTreeChangeListenerBase<FlowCapableNode, AclNodeListener>
48         implements AutoCloseable {
49
50     /** The Constant LOG. */
51     private static final Logger LOG = LoggerFactory.getLogger(AclNodeListener.class);
52
53     /** The mdsal manager. */
54     private final IMdsalApiManager mdsalManager;
55
56     /** The data broker. */
57     private final DataBroker dataBroker;
58
59     private SecurityGroupMode securityGroupMode = null;
60
61     /**
62      * Instantiates a new acl node listener.
63      *
64      * @param mdsalManager the mdsal manager
65      */
66     public AclNodeListener(final IMdsalApiManager mdsalManager, DataBroker dataBroker) {
67         super(FlowCapableNode.class, AclNodeListener.class);
68
69         this.mdsalManager = mdsalManager;
70         this.dataBroker = dataBroker;
71     }
72
73     public void start() {
74         LOG.info("{} start", getClass().getSimpleName());
75         Optional<AclserviceConfig> aclConfig = MDSALDataStoreUtils.read(dataBroker,
76                 LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
77                 .create(AclserviceConfig.class));
78         if (aclConfig.isPresent()) {
79             this.securityGroupMode = aclConfig.get().getSecurityGroupMode();
80         }
81         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
82     }
83
84     /*
85      * (non-Javadoc)
86      *
87      * @see
88      * org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase#
89      * getWildCardPath()
90      */
91     @Override
92     protected InstanceIdentifier<FlowCapableNode> getWildCardPath() {
93         return InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class);
94     }
95
96     /*
97      * (non-Javadoc)
98      *
99      * @see
100      * org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase#
101      * remove(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
102      * org.opendaylight.yangtools.yang.binding.DataObject)
103      */
104     @Override
105     protected void remove(InstanceIdentifier<FlowCapableNode> key, FlowCapableNode dataObjectModification) {
106         // do nothing
107
108     }
109
110     /*
111      * (non-Javadoc)
112      *
113      * @see
114      * org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase#
115      * update(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
116      * org.opendaylight.yangtools.yang.binding.DataObject,
117      * org.opendaylight.yangtools.yang.binding.DataObject)
118      */
119     @Override
120     protected void update(InstanceIdentifier<FlowCapableNode> key, FlowCapableNode dataObjectModificationBefore,
121             FlowCapableNode dataObjectModificationAfter) {
122         // do nothing
123
124     }
125
126     /*
127      * (non-Javadoc)
128      *
129      * @see
130      * org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase#
131      * add(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
132      * org.opendaylight.yangtools.yang.binding.DataObject)
133      */
134     @Override
135     protected void add(InstanceIdentifier<FlowCapableNode> key, FlowCapableNode dataObjectModification) {
136         LOG.trace("FlowCapableNode Added: key: {}", key);
137
138         NodeKey nodeKey = key.firstKeyOf(Node.class);
139         BigInteger dpnId = MDSALUtil.getDpnIdFromNodeName(nodeKey.getId());
140         createTableDefaultEntries(dpnId);
141     }
142
143     /**
144      * Creates the table miss entries.
145      *
146      * @param dpnId the dpn id
147      */
148     private void createTableDefaultEntries(BigInteger dpnId) {
149         if (securityGroupMode == null || securityGroupMode == SecurityGroupMode.Stateful) {
150             addIngressAclTableMissFlow(dpnId);
151             addEgressAclTableMissFlow(dpnId);
152             addConntrackRules(dpnId, NwConstants.LPORT_DISPATCHER_TABLE, NwConstants.INGRESS_ACL_FILTER_TABLE,
153                     NwConstants.ADD_FLOW);
154             addConntrackRules(dpnId, NwConstants.EGRESS_LPORT_DISPATCHER_TABLE, NwConstants.EGRESS_ACL_FILTER_TABLE,
155                     NwConstants.ADD_FLOW);
156         } else {
157             addStatelessIngressAclTableMissFlow(dpnId);
158             addStatelessEgressAclTableMissFlow(dpnId);
159         }
160     }
161
162     /**
163      * Adds the ingress acl table miss flow.
164      *
165      * @param dpId the dp id
166      */
167     private void addIngressAclTableMissFlow(BigInteger dpId) {
168         List<MatchInfo> mkMatches = new ArrayList<>();
169         List<InstructionInfo> mkInstructions = new ArrayList<>();
170         List<ActionInfo> actionsInfos = new ArrayList<>();
171         actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
172         mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
173
174         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
175                 getTableMissFlowId(NwConstants.EGRESS_ACL_TABLE), 0, "Ingress ACL Table Miss Flow", 0, 0,
176                 AclConstants.COOKIE_ACL_BASE, mkMatches, mkInstructions);
177         mdsalManager.installFlow(flowEntity);
178
179         FlowEntity nextTblFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_FILTER_TABLE,
180                 getTableMissFlowId(NwConstants.EGRESS_ACL_FILTER_TABLE), 0, "Ingress ACL Filter Table Miss Flow",
181                 0, 0, AclConstants.COOKIE_ACL_BASE, mkMatches, mkInstructions);
182         mdsalManager.installFlow(nextTblFlowEntity);
183
184         LOG.debug("Added Ingress ACL Table Miss Flows for dpn {}", dpId);
185     }
186
187     /**
188      * Adds the ingress acl table miss flow.
189      *
190      * @param dpId the dp id
191      */
192     private void addStatelessIngressAclTableMissFlow(BigInteger dpId) {
193         List<InstructionInfo> synInstructions = new ArrayList<>();
194         List<MatchInfo> synMatches = new ArrayList<>();
195         synMatches.add(new MatchInfo(MatchFieldType.tcp_flags, new long[] { AclConstants.TCP_FLAG_SYN }));
196
197         List<ActionInfo> dropActionsInfos = new ArrayList<>();
198         dropActionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
199         synInstructions.add(new InstructionInfo(InstructionType.apply_actions, dropActionsInfos));
200
201         FlowEntity synFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
202                 "SYN-" + getTableMissFlowId(NwConstants.EGRESS_ACL_TABLE),
203                 AclConstants.PROTO_MATCH_SYN_DROP_PRIORITY, "Ingress Syn ACL Table Block", 0, 0,
204                 AclConstants.COOKIE_ACL_BASE, synMatches, synInstructions);
205         mdsalManager.installFlow(synFlowEntity);
206
207         synMatches = new ArrayList<>();
208         synMatches.add(new MatchInfo(MatchFieldType.tcp_flags, new long[] { AclConstants.TCP_FLAG_SYN_ACK }));
209
210         List<InstructionInfo> allowAllInstructions = new ArrayList<>();
211         allowAllInstructions.add(
212             new InstructionInfo(InstructionType.goto_table,
213                     new long[] { NwConstants.EGRESS_ACL_FILTER_TABLE }));
214
215         FlowEntity synAckFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
216                 "SYN-ACK-ALLOW-" + getTableMissFlowId(NwConstants.EGRESS_ACL_TABLE),
217                 AclConstants.PROTO_MATCH_SYN_ACK_ALLOW_PRIORITY, "Ingress Syn Ack ACL Table Allow", 0, 0,
218                 AclConstants.COOKIE_ACL_BASE, synMatches, allowAllInstructions);
219         mdsalManager.installFlow(synAckFlowEntity);
220
221
222         List<MatchInfo> mkMatches = new ArrayList<>();
223         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_TABLE,
224                 getTableMissFlowId(NwConstants.EGRESS_ACL_TABLE), 0, "Ingress Stateless ACL Table Miss Flow",
225                 0, 0, AclConstants.COOKIE_ACL_BASE, mkMatches, allowAllInstructions);
226         mdsalManager.installFlow(flowEntity);
227
228         FlowEntity nextTblFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.EGRESS_ACL_FILTER_TABLE,
229                 getTableMissFlowId(NwConstants.EGRESS_ACL_FILTER_TABLE), 0,
230                 "Ingress Stateless Next ACL Table Miss Flow", 0, 0, AclConstants.COOKIE_ACL_BASE,
231                 mkMatches, allowAllInstructions);
232         mdsalManager.installFlow(nextTblFlowEntity);
233
234         LOG.debug("Added Stateless Ingress ACL Table Miss Flows for dpn {}", dpId);
235     }
236
237     /**
238      * Adds the stateless egress acl table miss flow.
239      *
240      * @param dpId the dp id
241      */
242     private void addStatelessEgressAclTableMissFlow(BigInteger dpId) {
243         List<InstructionInfo> allowAllInstructions = new ArrayList<>();
244         allowAllInstructions.add(
245                 new InstructionInfo(InstructionType.goto_table, new long[] { NwConstants.INGRESS_ACL_FILTER_TABLE }));
246
247         List<InstructionInfo> synInstructions = new ArrayList<>();
248         List<MatchInfo> synMatches = new ArrayList<>();
249         synMatches.add(new MatchInfo(MatchFieldType.tcp_flags, new long[] { AclConstants.TCP_FLAG_SYN }));
250
251         List<ActionInfo> synActionsInfos = new ArrayList<>();
252         synActionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
253         synInstructions.add(new InstructionInfo(InstructionType.apply_actions, synActionsInfos));
254
255         FlowEntity synFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
256                 "SYN-" + getTableMissFlowId(NwConstants.INGRESS_ACL_TABLE),
257                 AclConstants.PROTO_MATCH_SYN_DROP_PRIORITY, "Egress Syn ACL Table Block", 0, 0,
258                 AclConstants.COOKIE_ACL_BASE, synMatches, synInstructions);
259         mdsalManager.installFlow(synFlowEntity);
260
261         synMatches = new ArrayList<>();
262         synMatches.add(new MatchInfo(MatchFieldType.tcp_flags, new long[] { AclConstants.TCP_FLAG_SYN_ACK }));
263
264         FlowEntity synAckFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
265                 "SYN-ACK-ALLOW-" + getTableMissFlowId(NwConstants.INGRESS_ACL_TABLE),
266                 AclConstants.PROTO_MATCH_SYN_ACK_ALLOW_PRIORITY, "Egress Syn Ack ACL Table Allow", 0, 0,
267                 AclConstants.COOKIE_ACL_BASE, synMatches, allowAllInstructions);
268         mdsalManager.installFlow(synAckFlowEntity);
269
270         List<MatchInfo> mkMatches = new ArrayList<>();
271         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
272                 getTableMissFlowId(NwConstants.INGRESS_ACL_TABLE), 0, "Egress Stateless ACL Table Miss Flow", 0, 0,
273                 AclConstants.COOKIE_ACL_BASE, mkMatches, allowAllInstructions);
274         mdsalManager.installFlow(flowEntity);
275
276         FlowEntity nextTblFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE,
277                 getTableMissFlowId(NwConstants.INGRESS_ACL_FILTER_TABLE), 0,
278                 "Egress Stateless Next ACL Table Miss Flow", 0, 0, AclConstants.COOKIE_ACL_BASE, mkMatches,
279                 allowAllInstructions);
280         mdsalManager.installFlow(nextTblFlowEntity);
281
282         LOG.debug("Added Stateless Egress ACL Table Miss Flows for dpn {}", dpId);
283     }
284
285     /**
286      * Adds the egress acl table miss flow.
287      *
288      * @param dpId the dp id
289      */
290     private void addEgressAclTableMissFlow(BigInteger dpId) {
291         List<MatchInfo> mkMatches = new ArrayList<>();
292         List<InstructionInfo> mkInstructions = new ArrayList<>();
293         List<ActionInfo> actionsInfos = new ArrayList<>();
294         actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
295         mkInstructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
296
297         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_TABLE,
298                 getTableMissFlowId(NwConstants.INGRESS_ACL_TABLE), 0, "Egress ACL Table Miss Flow", 0, 0,
299                 AclConstants.COOKIE_ACL_BASE, mkMatches, mkInstructions);
300         mdsalManager.installFlow(flowEntity);
301
302         FlowEntity nextTblFlowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.INGRESS_ACL_FILTER_TABLE,
303                 getTableMissFlowId(NwConstants.INGRESS_ACL_FILTER_TABLE), 0, "Egress ACL Table Miss Flow", 0, 0,
304                 AclConstants.COOKIE_ACL_BASE, mkMatches, mkInstructions);
305         mdsalManager.installFlow(nextTblFlowEntity);
306
307         LOG.debug("Added Egress ACL Table Miss Flows for dpn {}", dpId);
308     }
309
310     private void addConntrackRules(BigInteger dpnId, short dispatcherTableId,short tableId, int write) {
311         programConntrackForwardRule(dpnId, AclConstants.CT_STATE_TRACKED_EXIST_PRIORITY,
312             "Tracked_Established", AclConstants.TRACKED_EST_CT_STATE, AclConstants.TRACKED_EST_CT_STATE_MASK,
313             dispatcherTableId, tableId, write );
314         programConntrackForwardRule(dpnId, AclConstants.CT_STATE_TRACKED_EXIST_PRIORITY,"Tracked_Related", AclConstants
315             .TRACKED_REL_CT_STATE, AclConstants.TRACKED_REL_CT_STATE_MASK, dispatcherTableId, tableId, write );
316         programConntrackDropRule(dpnId, AclConstants.CT_STATE_NEW_PRIORITY_DROP,"Tracked_New",
317             AclConstants.TRACKED_NEW_CT_STATE, AclConstants.TRACKED_NEW_CT_STATE_MASK, tableId, write );
318         programConntrackDropRule(dpnId, AclConstants.CT_STATE_NEW_PRIORITY_DROP, "Tracked_Invalid",
319             AclConstants.TRACKED_INV_CT_STATE, AclConstants.TRACKED_INV_CT_STATE_MASK, tableId, write );
320
321     }
322
323     /**
324      * Adds the rule to forward the packets known packets.
325      *
326      * @param dpId the dpId
327      * @param lportTag the lport tag
328      * @param priority the priority of the flow
329      * @param flowId the flowId
330      * @param conntrackState the conntrack state of the packets thats should be
331      *        send
332      * @param conntrackMask the conntrack mask
333      * @param addOrRemove whether to add or remove the flow
334      */
335     private void programConntrackForwardRule(BigInteger dpId, Integer priority, String flowId,
336             int conntrackState, int conntrackMask, short dispatcherTableId, short tableId, int addOrRemove) {
337         List<MatchInfoBase> matches = new ArrayList<>();
338         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state, new long[] {conntrackState, conntrackMask}));
339
340         List<InstructionInfo> instructions = getDispatcherTableResubmitInstructions(
341             new ArrayList<>(),dispatcherTableId);
342
343         flowId = "Fixed_Conntrk_Trk_" + dpId + "_" + flowId + dispatcherTableId;
344         syncFlow(dpId, tableId, flowId, priority, "ACL", 0, 0,
345                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
346     }
347
348     /**
349      * Adds the rule to drop the unknown/invalid packets .
350      *
351      * @param dpId the dpId
352      * @param lportTag the lport tag
353      * @param priority the priority of the flow
354      * @param flowId the flowId
355      * @param conntrackState the conntrack state of the packets thats should be
356      *        send
357      * @param conntrackMask the conntrack mask
358      * @param addOrRemove whether to add or remove the flow
359      */
360     private void programConntrackDropRule(BigInteger dpId, Integer priority, String flowId,
361             int conntrackState, int conntrackMask, short tableId, int addOrRemove) {
362         List<MatchInfoBase> matches = new ArrayList<>();
363         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state, new long[] {conntrackState, conntrackMask}));
364
365         List<InstructionInfo> instructions = new ArrayList<>();
366         List<ActionInfo> actionsInfos = new ArrayList<>();
367         actionsInfos.add(new ActionInfo(ActionType.drop_action, new String[] {}));
368         instructions.add(new InstructionInfo(InstructionType.write_actions, actionsInfos));
369         flowId = "Fixed_Conntrk_NewDrop_" + dpId + "_" + flowId + tableId;
370         syncFlow(dpId, tableId, flowId, priority, "ACL", 0, 0,
371                 AclConstants.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
372     }
373
374     /**
375      * Gets the dispatcher table resubmit instructions.
376      *
377      * @param actionsInfos the actions infos
378      * @return the instructions for dispatcher table resubmit
379      */
380     private List<InstructionInfo> getDispatcherTableResubmitInstructions(List<ActionInfo> actionsInfos,
381                                                                          short dispatcherTableId) {
382         List<InstructionInfo> instructions = new ArrayList<>();
383         actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] {Short.toString(dispatcherTableId)}));
384         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
385         return instructions;
386     }
387
388     /**
389      * Writes/remove the flow to/from the datastore.
390      * @param dpId the dpId
391      * @param tableId the tableId
392      * @param flowId the flowId
393      * @param priority the priority
394      * @param flowName the flow name
395      * @param idleTimeOut the idle timeout
396      * @param hardTimeOut the hard timeout
397      * @param cookie the cookie
398      * @param matches the list of matches to be written
399      * @param instructions the list of instruction to be written.
400      * @param addOrRemove add or remove the entries.
401      */
402     protected void syncFlow(BigInteger dpId, short tableId, String flowId, int priority, String flowName,
403                           int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase>  matches,
404                           List<InstructionInfo> instructions, int addOrRemove) {
405         if (addOrRemove == NwConstants.DEL_FLOW) {
406             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId,flowId,
407                 priority, flowName , idleTimeOut, hardTimeOut, cookie, matches, null);
408             LOG.trace("Removing Acl Flow DpnId {}, flowId {}", dpId, flowId);
409             mdsalManager.removeFlow(flowEntity);
410         } else {
411             FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, tableId, flowId,
412                 priority, flowName, idleTimeOut, hardTimeOut, cookie, matches, instructions);
413             LOG.trace("Installing DpnId {}, flowId {}", dpId, flowId);
414             mdsalManager.installFlow(flowEntity);
415         }
416     }
417
418     /**
419      * Gets the table miss flow id.
420      *
421      * @param tableId the table id
422      * @return the table miss flow id
423      */
424     private String getTableMissFlowId(short tableId) {
425         return String.valueOf(tableId);
426     }
427
428     /*
429      * (non-Javadoc)
430      *
431      * @see
432      * org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase#
433      * getDataTreeChangeListener()
434      */
435     @Override
436     protected AclNodeListener getDataTreeChangeListener() {
437         return AclNodeListener.this;
438     }
439 }