Merge "Auto-creation of bridges in vpnservice"
[netvirt.git] / vpnservice / aclservice / impl / src / main / java / org / opendaylight / netvirt / aclservice / EgressAclServiceImpl.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
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.genius.mdsalutil.ActionInfo;
16 import org.opendaylight.genius.mdsalutil.ActionType;
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.MatchFieldType;
21 import org.opendaylight.genius.mdsalutil.MatchInfo;
22 import org.opendaylight.genius.mdsalutil.MatchInfoBase;
23 import org.opendaylight.genius.mdsalutil.NwConstants;
24 import org.opendaylight.genius.mdsalutil.NxMatchFieldType;
25 import org.opendaylight.genius.mdsalutil.NxMatchInfo;
26 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
27 import org.opendaylight.netvirt.aclservice.api.AclServiceListener;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 public class EgressAclServiceImpl implements AclServiceListener {
34
35     private static final Logger logger = LoggerFactory.getLogger(EgressAclServiceImpl.class);
36
37     private IMdsalApiManager mdsalUtil;
38     short tableIdInstall = 22;
39     short tableIdNext = 23;
40     private OdlInterfaceRpcService interfaceManager;
41     private DataBroker dataBroker;
42
43     /**
44      * Intilaze the member variables.
45      * @param dataBroker the data broker instance.
46      * @param interfaceManager the interface manager instance.
47      * @param mdsalUtil the mdsal util instance.
48      */
49     public EgressAclServiceImpl(DataBroker dataBroker, OdlInterfaceRpcService interfaceManager,
50                                 IMdsalApiManager mdsalUtil) {
51         this.dataBroker = dataBroker;
52         this.interfaceManager = interfaceManager;
53         this.mdsalUtil = mdsalUtil;
54     }
55
56     @Override
57     public boolean applyAcl(Interface port) {
58
59         if (!AclServiceUtils.isPortSecurityEnabled(port, dataBroker)) {
60             return false;
61         }
62         BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
63         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
64             interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
65         String attachMac = interfaceState.getPhysAddress().getValue();
66         programFixedSecurityGroup(dpId, "", attachMac, NwConstants.ADD_FLOW);
67         return true;
68     }
69
70     @Override
71     public boolean updateAcl(Interface port) {
72         return false;
73     }
74
75     @Override
76     public boolean removeAcl(Interface port) {
77         if (!AclServiceUtils.isPortSecurityEnabled(port, dataBroker)) {
78             return false;
79         }
80         BigInteger dpId = AclServiceUtils.getDpnForInterface(interfaceManager, port.getName());
81         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface
82             interfaceState = AclServiceUtils.getInterfaceStateFromOperDS(dataBroker, port.getName());
83         String attachMac = interfaceState.getPhysAddress().getValue();
84         programFixedSecurityGroup(dpId, "", attachMac, NwConstants.DEL_FLOW);
85         return true;
86     }
87
88     /**
89      * Program the default anti-spoofing rule and the conntrack rules.
90      * @param dpid the dpid
91      * @param dhcpMacAddress the dhcp mac address.
92      * @param attachMac The vm mac address
93      * @param addOrRemove addorRemove
94      */
95     private void programFixedSecurityGroup(BigInteger dpid, String dhcpMacAddress,
96                                            String attachMac, int addOrRemove) {
97         logger.info("programFixedSecurityGroup :  adding default security group rules.");
98         egressAclDhcpAllowClientTraffic(dpid, dhcpMacAddress, attachMac, addOrRemove);
99         egressAclDhcpv6AllowClientTraffic(dpid, dhcpMacAddress, attachMac, addOrRemove);
100         egressAclDhcpDropServerTraffic(dpid, dhcpMacAddress, attachMac, addOrRemove);
101         egressAclDhcpv6DropServerTraffic(dpid, dhcpMacAddress, attachMac, addOrRemove);
102
103         //if (securityServicesManager.isConntrackEnabled()) {
104         programEgressAclFixedConntrackRule(dpid, attachMac, addOrRemove);
105         //}
106         programArpRule(dpid,attachMac, addOrRemove);
107     }
108
109     /**
110      * Anti-spoofing rule to block the Ipv4 DHCP server traffic from the port.
111      * @param dpId the dpId
112      * @param dhcpMacAddress the Dhcp mac address
113      * @param attachMac the attached mac address
114      * @param addOrRemove add/remove the flow.
115      */
116     private void egressAclDhcpDropServerTraffic(BigInteger dpId, String dhcpMacAddress,
117             String attachMac, int addOrRemove) {
118         List<MatchInfoBase> matches = AclServiceUtils.programDhcpMatches(AclServiceUtils.dhcpServerPort_IpV4,
119             AclServiceUtils.dhcpClientPort_IpV4);
120         matches.add(new MatchInfo(MatchFieldType.eth_src,
121             new String[] { attachMac }));
122         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state,
123             new long[] { AclServiceUtils.TRACKED_NEW_CT_STATE, AclServiceUtils.TRACKED_NEW_CT_STATE_MASK}));
124
125         List<InstructionInfo> instructions = new ArrayList<>();
126
127         List<ActionInfo> actionsInfos = new ArrayList<>();
128
129         actionsInfos.add(new ActionInfo(ActionType.drop_action,
130             new String[] {}));
131         String flowName = "Egress_DHCP_Server_v4" + dpId + "_" + attachMac + "_" + dhcpMacAddress + "_Drop_";
132         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
133             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
134     }
135
136     /**
137      * Anti-spoofing rule to block the Ipv6 DHCP server traffic from the port.
138      * @param dpId the dpId
139      * @param dhcpMacAddress the Dhcp mac address
140      * @param attachMac the attached mac address
141      * @param addOrRemove add/remove the flow.
142      */
143     private void egressAclDhcpv6DropServerTraffic(BigInteger dpId, String dhcpMacAddress,
144                                                   String attachMac, int addOrRemove) {
145         List<MatchInfoBase> matches = AclServiceUtils.programDhcpMatches(AclServiceUtils.dhcpServerPort_Ipv6,
146             AclServiceUtils.dhcpClientPort_IpV6);
147         matches.add(new MatchInfo(MatchFieldType.eth_src,
148             new String[] { attachMac }));
149         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state,
150             new long[] { AclServiceUtils.TRACKED_NEW_CT_STATE, AclServiceUtils.TRACKED_NEW_CT_STATE_MASK}));
151
152         List<InstructionInfo> instructions = new ArrayList<>();
153
154         List<ActionInfo> actionsInfos = new ArrayList<>();
155
156         actionsInfos.add(new ActionInfo(ActionType.drop_action,
157             new String[] {}));
158         String flowName = "Egress_DHCP_Server_v4" + "_" + dpId + "_" + attachMac + "_" + dhcpMacAddress + "_Drop_";
159         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
160             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
161     }
162
163     /**
164      * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
165      *
166      * @param dpidLong the dpid
167      * @param segmentationId the segmentation id
168      * @param dhcpMacAddress the DHCP server mac address
169      * @param attachMac the mac address of  the port
170      * @param write is write or delete
171      * @param protoPortMatchPriority the priority
172      */
173     private void egressAclDhcpAllowClientTraffic(BigInteger dpId, String dhcpMacAddress,
174                                                  String attachMac, int addOrRemove) {
175         List<MatchInfoBase> matches = AclServiceUtils.programDhcpMatches(AclServiceUtils.dhcpClientPort_IpV4,
176             AclServiceUtils.dhcpServerPort_IpV4);
177         matches.add(new MatchInfo(MatchFieldType.eth_src,
178             new String[] { attachMac }));
179         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state,
180             new long[] { AclServiceUtils.TRACKED_NEW_CT_STATE, AclServiceUtils.TRACKED_NEW_CT_STATE_MASK}));
181
182         List<InstructionInfo> instructions = new ArrayList<>();
183
184         List<ActionInfo> actionsInfos = new ArrayList<>();
185
186         actionsInfos.add(new ActionInfo(ActionType.nx_conntrack,
187             new String[] {"1", "0", "0", "255"}, 2));
188         instructions.add(new InstructionInfo(InstructionType.apply_actions,
189             actionsInfos));
190
191
192         instructions.add(new InstructionInfo(InstructionType.goto_table,
193             new long[] { tableIdNext }));
194         String flowName = "Egress_DHCP_Client_v4" + dpId + "_" + attachMac + "_" + dhcpMacAddress + "_Permit_";
195         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
196             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
197     }
198
199     /**
200      * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
201      *
202      * @param dpidLong the dpid
203      * @param segmentationId the segmentation id
204      * @param dhcpMacAddress the DHCP server mac address
205      * @param attachMac the mac address of  the port
206      * @param write is write or delete
207      * @param protoPortMatchPriority the priority
208      */
209     private void egressAclDhcpv6AllowClientTraffic(BigInteger dpId, String dhcpMacAddress,
210                                                    String attachMac, int addOrRemove) {
211         List<MatchInfoBase> matches = AclServiceUtils.programDhcpMatches(AclServiceUtils.dhcpClientPort_IpV6,
212             AclServiceUtils.dhcpServerPort_Ipv6);
213         matches.add(new MatchInfo(MatchFieldType.eth_src,
214             new String[] { attachMac }));
215         matches.add(new NxMatchInfo(NxMatchFieldType.ct_state,
216             new long[] { AclServiceUtils.TRACKED_NEW_CT_STATE, AclServiceUtils.TRACKED_NEW_CT_STATE_MASK}));
217
218         List<InstructionInfo> instructions = new ArrayList<>();
219
220         List<ActionInfo> actionsInfos = new ArrayList<>();
221
222         actionsInfos.add(new ActionInfo(ActionType.nx_conntrack,
223             new String[] {"1", "0", "0", "255"}, 2));
224         instructions.add(new InstructionInfo(InstructionType.apply_actions,
225             actionsInfos));
226
227         instructions.add(new InstructionInfo(InstructionType.goto_table,
228             new long[] { tableIdNext }));
229         String flowName = "Egress_DHCP_Client_v4" + "_" + dpId + "_" + attachMac + "_" + dhcpMacAddress + "_Permit_";
230         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
231             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
232     }
233
234     /**
235      * Adds the rule to send the packet to the netfilter to check whether it is a known packet.
236      * @param dpId the dpId
237      * @param attachMac the attached mac address
238      * @param priority the priority of the flow
239      * @param flowId the flowId
240      * @param conntrackState the conntrack state of the packets thats should be send
241      * @param conntrackMask the conntrack mask
242      * @param addOrRemove whether to add or remove the flow
243      */
244     private void programConntrackRecircRule(BigInteger dpId, String attachMac, Integer priority, String flowId,
245                                              int conntrackState, int conntrackMask, int addOrRemove) {
246         List<MatchInfoBase> matches = new ArrayList<>();
247         matches.add((MatchInfoBase)new MatchInfo(MatchFieldType.eth_type,
248             new long[] { NwConstants.ETHTYPE_IPV4 }));
249         matches.add((MatchInfoBase)new NxMatchInfo(NxMatchFieldType.ct_state,
250             new long[] {conntrackState, conntrackMask}));
251         matches.add(new MatchInfo(MatchFieldType.eth_src,
252             new String[] { attachMac }));
253         List<InstructionInfo> instructions = new ArrayList<>();
254
255         List<ActionInfo> actionsInfos = new ArrayList<>();
256
257         actionsInfos.add(new ActionInfo(ActionType.nx_conntrack,
258             new String[] {"0", "0", "0", Short.toString(tableIdInstall)}, 2));
259         instructions.add(new InstructionInfo(InstructionType.apply_actions,
260             actionsInfos));
261         String flowName = "Egress_Fixed_Conntrk_Untrk_" + dpId + "_" + attachMac + "_" + flowId;
262         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
263             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
264     }
265
266     /**
267      * Adds  the rule to forward the packets known packets .
268      * @param dpId the dpId
269      * @param attachMac the attached mac address
270      * @param priority the priority of the flow
271      * @param flowId the flowId
272      * @param conntrackState the conntrack state of the packets thats should be send
273      * @param conntrackMask the conntrack mask
274      * @param addOrRemove whether to add or remove the flow
275      */
276     private void programConntrackForwardRule(BigInteger dpId, String attachMac, Integer priority, String flowId,
277                                              int conntrackState, int conntrackMask, int addOrRemove) {
278         List<MatchInfoBase> matches = new ArrayList<>();
279         matches.add((MatchInfoBase)new MatchInfo(MatchFieldType.eth_type,
280             new long[] { NwConstants.ETHTYPE_IPV4 }));
281         matches.add((MatchInfoBase)new NxMatchInfo(NxMatchFieldType.ct_state,
282             new long[] {conntrackState, conntrackMask}));
283         matches.add(new MatchInfo(MatchFieldType.eth_src,
284             new String[] { attachMac }));
285         List<InstructionInfo> instructions = new ArrayList<>();
286
287         List<ActionInfo> actionsInfos = new ArrayList<>();
288
289         actionsInfos.add(new ActionInfo(ActionType.goto_table,
290             new String[] {}));
291
292         instructions.add(new InstructionInfo(InstructionType.goto_table,
293             new long[] { tableIdNext }));
294         String flowName = "Egress_Fixed_Conntrk_Untrk_" + dpId + "_" + attachMac + "_" + flowId;
295         syncFlow(dpId, tableIdInstall, flowName, priority, "ACL", 0, 0,
296             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
297     }
298
299     /**
300      * Adds  the rule to drop the unknown/invalid packets .
301      * @param dpId the dpId
302      * @param attachMac the attached mac address
303      * @param priority the priority of the flow
304      * @param flowId the flowId
305      * @param conntrackState the conntrack state of the packets thats should be send
306      * @param conntrackMask the conntrack mask
307      * @param addOrRemove whether to add or remove the flow
308      */
309     private void programConntrackDropRule(BigInteger dpId, String attachMac, Integer priority, String flowId,
310                                           int conntrackState, int conntrackMask, int addOrRemove) {
311         List<MatchInfoBase> matches = new ArrayList<>();
312         matches.add((MatchInfoBase)new MatchInfo(MatchFieldType.eth_type,
313             new long[] { NwConstants.ETHTYPE_IPV4 }));
314         matches.add((MatchInfoBase)new NxMatchInfo(NxMatchFieldType.ct_state,
315             new long[] { conntrackState, conntrackMask}));
316         matches.add(new MatchInfo(MatchFieldType.eth_src,
317             new String[] { attachMac }));
318         List<InstructionInfo> instructions = new ArrayList<>();
319
320         List<ActionInfo> actionsInfos = new ArrayList<>();
321
322         actionsInfos.add(new ActionInfo(ActionType.drop_action,
323             new String[] {}));
324         String flowName = "Egress_Fixed_Conntrk_NewDrop_" + dpId + "_" + attachMac + "_" + flowId;
325         syncFlow(dpId, tableIdInstall, flowName, priority, "ACL", 0, 0,
326             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
327     }
328
329     /**
330      * Adds  the rule to allow arp packets.
331      * @param dpId the dpId
332      * @param attachMac the attached mac address
333      * @param addOrRemove whether to add or remove the flow
334      */
335     private void programArpRule(BigInteger dpId, String attachMac, int addOrRemove) {
336         List<MatchInfo> matches = new ArrayList<>();
337         matches.add(new MatchInfo(MatchFieldType.eth_type,
338             new long[] { NwConstants.ETHTYPE_IPV4 }));
339         matches.add(new MatchInfo(MatchFieldType.arp_tpa,
340             new String[] { attachMac }));
341
342         List<InstructionInfo> instructions = new ArrayList<>();
343
344         List<ActionInfo> actionsInfos = new ArrayList<>();
345
346         actionsInfos.add(new ActionInfo(ActionType.goto_table,
347                 new String[] {}));
348
349         instructions.add(new InstructionInfo(InstructionType.goto_table,
350             new long[] { tableIdNext }));
351         String flowName = "Egress_ARP_" + dpId + "_" + attachMac ;
352         syncFlow(dpId, tableIdInstall, flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
353             AclServiceUtils.COOKIE_ACL_BASE, matches, instructions, addOrRemove);
354     }
355
356     /**
357      * Writes/remove the flow to/from the datastore.
358      * @param dpId the dpId
359      * @param tableId the tableId
360      * @param flowId the flowId
361      * @param priority the priority
362      * @param flowName the flow name
363      * @param idleTimeOut the idle timeout
364      * @param hardTimeOut the hard timeout
365      * @param cookie the cookie
366      * @param matches the list of matches to be writted
367      * @param instructions the list of instruction to be written.
368      * @param addOrRemove add or remove the entries.
369      */
370     private void syncFlow(BigInteger dpId, short tableId, String flowId, int priority, String flowName,
371                           int idleTimeOut, int hardTimeOut, BigInteger cookie, List<? extends MatchInfoBase>  matches,
372                           List<InstructionInfo> instructions, int addOrRemove) {
373         if (addOrRemove == NwConstants.DEL_FLOW) {
374             MDSALUtil.buildFlowEntity(dpId, tableIdInstall,
375                 flowName, AclServiceUtils.PROTO_MATCH_PRIORITY, "ACL", 0, 0,
376                 AclServiceUtils.COOKIE_ACL_BASE, matches, null);
377             logger.trace("Removing Acl Flow DpId {}, vmMacAddress {}", dpId, flowId);
378             // TODO Need to be done as a part of genius integration
379             //mdsalUtil.removeFlow(flowEntity);
380         } else {
381             MDSALUtil.buildFlowEntity(dpId, tableId,
382                 flowId ,priority, flowName, 0, 0, cookie, matches, instructions);
383             logger.trace("Installing  DpId {}, flowId {}", dpId, flowId);
384             // TODO Need to be done as a part of genius integration
385             //mdsalUtil.installFlow(flowEntity);
386         }
387     }
388
389     /**
390      * Programs the default connection tracking rules.
391      * @param dpid the dp id
392      * @param attachMac the attached mac address
393      * @param write whether to add or remove the flow.
394      */
395     private void programEgressAclFixedConntrackRule(BigInteger dpid, String attachMac, int write) {
396         programConntrackRecircRule(dpid, attachMac,AclServiceUtils.CT_STATE_UNTRACKED_PRIORITY,
397             "Untracked",AclServiceUtils.UNTRACKED_CT_STATE,AclServiceUtils.UNTRACKED_CT_STATE_MASK, write );
398         programConntrackForwardRule(dpid, attachMac, AclServiceUtils.CT_STATE_TRACKED_EXIST_PRIORITY,
399             "Tracked_Established", AclServiceUtils.TRACKED_EST_CT_STATE, AclServiceUtils.TRACKED_CT_STATE_MASK,
400             write );
401         programConntrackForwardRule(dpid, attachMac, AclServiceUtils.CT_STATE_TRACKED_EXIST_PRIORITY,
402             "Tracked_Related", AclServiceUtils.TRACKED_REL_CT_STATE, AclServiceUtils.TRACKED_CT_STATE_MASK, write );
403         programConntrackDropRule(dpid, attachMac, AclServiceUtils.CT_STATE_NEW_PRIORITY_DROP,
404             "Tracked_New", AclServiceUtils.TRACKED_NEW_CT_STATE, AclServiceUtils.TRACKED_NEW_CT_STATE_MASK, write );
405         programConntrackForwardRule(dpid, attachMac, AclServiceUtils.CT_STATE_NEW_PRIORITY_DROP,
406             "Tracked_Invalid",AclServiceUtils.TRACKED_INV_CT_STATE, AclServiceUtils.TRACKED_INV_CT_STATE_MASK,
407             write );
408         logger.info("programEgressAclFixedConntrackRule :  default connection tracking rule are added.");
409     }
410 }