Merge "Remove ovsdb related in resources"
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / netvirt / openstack / netvirt / providers / openflow13 / services / IngressAclService.java
1 /*
2  * Copyright (c) 2014 - 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
9 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services;
10
11 import com.google.common.collect.Lists;
12
13 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
14 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
15 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
16 import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
17 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
18 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
19 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
20 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
21 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
22 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
23 import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
24 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
25 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
26 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
27 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv6Prefix;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
38 import org.osgi.framework.BundleContext;
39 import org.osgi.framework.ServiceReference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import java.net.Inet4Address;
44 import java.net.Inet6Address;
45 import java.net.InetAddress;
46 import java.net.UnknownHostException;
47 import java.util.List;
48 import java.util.Map;
49
50 public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
51     private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
52     private volatile SecurityServicesManager securityServicesManager;
53     private volatile SecurityGroupCacheManger securityGroupCacheManger;
54     private static final int PORT_RANGE_MIN = 1;
55     private static final int PORT_RANGE_MAX = 65535;
56
57     public IngressAclService() {
58         super(Service.INGRESS_ACL);
59     }
60
61     public IngressAclService(Service service) {
62         super(service);
63     }
64
65     @Override
66     public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
67                                        long localPort, NeutronSecurityGroup securityGroup,
68                                        String portUuid, boolean write) {
69
70         LOG.trace("programPortSecurityGroup neutronSecurityGroup: {} ", securityGroup);
71         if (securityGroup == null || securityGroup.getSecurityRules() == null) {
72             return;
73         }
74
75         List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
76         /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
77         for (NeutronSecurityRule portSecurityRule : portSecurityList) {
78
79             /**
80              * Neutron Port Security Acl "ingress" and "IPv4"
81              * Check that the base conditions for flow based Port Security are true:
82              * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
83              * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
84              * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
85              *
86              */
87
88             if (portSecurityRule == null
89                     || portSecurityRule.getSecurityRuleEthertype() == null
90                     || portSecurityRule.getSecurityRuleDirection() == null) {
91                 continue;
92             }
93
94             if (NeutronSecurityRule.DIRECTION_INGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
95                 LOG.debug("programPortSecurityGroup: Rule matching IP and ingress is: {} ", portSecurityRule);
96                 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
97                     //Remote Security group is selected
98                     List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
99                             .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
100                     if (null != remoteSrcAddressList) {
101                         for (Neutron_IPs vmIp :remoteSrcAddressList ) {
102                             programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
103                                                     portSecurityRule, vmIp, write);
104                         }
105                         if (write) {
106                             securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
107                         } else {
108                             securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
109                                                                      portUuid);
110                         }
111                     }
112                 } else {
113                     programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
114                                             portSecurityRule, null, write);
115                 }
116                 if (write) {
117                     securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
118                 } else {
119                     securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
120                 }
121             }
122         }
123     }
124
125     @Override
126     public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
127                                         long localPort, NeutronSecurityRule portSecurityRule,
128                                         Neutron_IPs vmIp, boolean write) {
129         String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
130         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
131         if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
132             LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
133                       securityRuleEtherType);
134             return;
135         }
136
137         if (null == portSecurityRule.getSecurityRuleProtocol()) {
138             ingressAclIp(dpid, isIpv6, segmentationId, attachedMac,
139                          write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
140         } else {
141             String ipaddress = null;
142             if (null != vmIp) {
143                 ipaddress = vmIp.getIpAddress();
144                 try {
145                     InetAddress address = InetAddress.getByName(vmIp.getIpAddress());
146                     if ((isIpv6 && (address instanceof Inet4Address)) || (!isIpv6 && address instanceof Inet6Address)) {
147                         LOG.debug("programPortSecurityRule: Remote vmIP {} does not match "
148                                 + "with SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
149                         return;
150                     }
151                 } catch (UnknownHostException e) {
152                     LOG.warn("Invalid IP address {}", ipaddress, e);
153                     return;
154                 }
155             }
156
157             switch (portSecurityRule.getSecurityRuleProtocol()) {
158                 case MatchUtils.TCP:
159                     LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
160                     ingressAclTcp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
161                               write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
162                     break;
163                 case MatchUtils.UDP:
164                     LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
165                     ingressAclUdp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
166                                 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
167                     break;
168                 case MatchUtils.ICMP:
169                 case MatchUtils.ICMPV6:
170                     LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
171                     ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
172                                  write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
173                     break;
174                 default:
175                     LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
176                             + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
177                     ingressOtherProtocolAclHandler(dpid, segmentationId, attachedMac, portSecurityRule,
178                               null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
179                     break;
180             }
181         }
182     }
183
184     private void ingressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String dstMac,
185           NeutronSecurityRule portSecurityRule, String srcAddress,
186           boolean write, Integer protoPortMatchPriority) {
187         MatchBuilder matchBuilder = new MatchBuilder();
188         String flowId = "Ingress_Other_" + segmentationId + "_" + dstMac + "_";
189         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
190         short proto = 0;
191         try {
192             Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
193             proto = protocol.shortValue();
194             flowId = flowId + proto;
195         } catch (NumberFormatException e) {
196             LOG.error("Protocol vlaue conversion failure", e);
197         }
198         matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
199         if (null != srcAddress) {
200             flowId = flowId + srcAddress;
201             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
202                                                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
203         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
204             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
205             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
206                                            new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
207         }
208         flowId = flowId + "_Permit";
209         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
210         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
211                                                               matchBuilder, getTable());
212         addInstructionWithConntrackCommit(flowBuilder, false);
213         syncFlow(flowBuilder ,nodeBuilder, write);
214     }
215
216     @Override
217     public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
218                                         long localPort, String attachMac, boolean write) {
219
220         ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
221                                          write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
222         ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
223                                            write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
224
225         if (securityServicesManager.isConntrackEnabled()) {
226             programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
227         }
228         programArpRule(dpid, segmentationId, localPort, attachMac, write);
229     }
230
231     private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
232         MatchBuilder matchBuilder = new MatchBuilder();
233         String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
234         MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
235         MatchUtils.addArpMacMatch(matchBuilder, null, attachMac);
236         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
237                                                               matchBuilder, getTable());
238         addPipelineInstruction(flowBuilder, null, false);
239         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
240         syncFlow(flowBuilder ,nodeBuilder, write);
241     }
242
243     private void programIngressAclFixedConntrackRule(Long dpid,
244            String segmentationId, String attachMac, long localPort, boolean write) {
245         try {
246             String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
247             programConntrackUntrackRule(dpid, segmentationId, localPort, attachMac,
248                                         Constants.CT_STATE_UNTRACKED_PRIORITY, write );
249             programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort, attachMac,
250                                         Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
251             programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort, attachMac,
252                                                Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
253             programConntrackInvDropRule(dpid, segmentationId, localPort, attachMac,
254                                         Constants.CT_STATE_NEW_PRIORITY_DROP, write );
255             programConntrackNewDropRule(dpid, segmentationId, localPort, attachMac,
256                                              Constants.CT_STATE_NEW_PRIORITY_DROP, write );
257             LOG.info("programIngressAclFixedConntrackRule :  default connection tracking rule are added.");
258         } catch (Exception e) {
259             LOG.error("Failed to add default conntrack rules : " , e);
260         }
261     }
262
263     private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
264                                              long localPort, String attachMac, Integer priority, boolean write) {
265         MatchBuilder matchBuilder = new MatchBuilder();
266         String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
267         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
268         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
269                                              MatchUtils.UNTRACKED_CT_STATE_MASK);
270         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
271         addInstructionWithConntrackRecirc(flowBuilder);
272         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
273         syncFlow(flowBuilder ,nodeBuilder, write);
274     }
275
276     private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
277                                                   long localPort, String attachMac,Integer priority, boolean write) {
278         MatchBuilder matchBuilder = new MatchBuilder();
279         String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
280         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
281         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
282                                              MatchUtils.TRACKED_CT_STATE_MASK);
283         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
284         addPipelineInstruction(flowBuilder, null, false);
285         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
286         syncFlow(flowBuilder ,nodeBuilder, write);
287     }
288
289     private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
290                                                     long localPort, String attachMac,Integer priority, boolean write) {
291         MatchBuilder matchBuilder = new MatchBuilder();
292         String flowName = "Ingress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
293         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
294         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
295                                              MatchUtils.TRACKED_CT_STATE_MASK);
296         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
297         addPipelineInstruction(flowBuilder, null, false);
298         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
299         syncFlow(flowBuilder ,nodeBuilder, write);
300     }
301
302     private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
303                                              long localPort, String attachMac, Integer priority, boolean write) {
304         MatchBuilder matchBuilder = new MatchBuilder();
305
306         String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
307         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,0x0800L);
308         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
309                                              MatchUtils.TRACKED_NEW_CT_STATE_MASK);
310         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
311         addPipelineInstruction(flowBuilder, null, true);
312         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
313         syncFlow(flowBuilder ,nodeBuilder, write);
314     }
315
316     private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
317                                              long localPort, String attachMac, Integer priority, boolean write) {
318         MatchBuilder matchBuilder = new MatchBuilder();
319         String flowName = "Ingress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
320         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac, MatchUtils.ETHERTYPE_IPV4);
321         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
322                                              MatchUtils.TRACKED_INV_CT_STATE_MASK);
323         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
324         addPipelineInstruction(flowBuilder, null, true);
325         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
326         syncFlow(flowBuilder ,nodeBuilder, write);
327     }
328
329     /**
330      * Allows an IPv4/v6 packet ingress to the destination mac address.
331      * @param dpidLong the dpid
332      * @param isIpv6 indicates whether this is an Ipv
333      * @param segmentationId the segementation id
334      * @param dstMac the destination mac address
335      * @param write add or remove
336      * @param protoPortMatchPriority the protocol match priority.
337      */
338     private void ingressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
339                               boolean write, Integer protoPortMatchPriority ) {
340         MatchBuilder matchBuilder = new MatchBuilder();
341         String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
342         if (isIpv6) {
343             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
344         } else {
345             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
346         }
347         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
348         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
349         addInstructionWithConntrackCommit(flowBuilder, false);
350         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
351         syncFlow(flowBuilder ,nodeBuilder, write);
352     }
353
354     /**
355      * Creates a ingress match to the dst macaddress. If src address is specified
356      * source specific match will be created. Otherwise a match with a CIDR will
357      * be created.
358      * @param dpidLong the dpid
359      * @param segmentationId the segmentation id
360      * @param dstMac the destination mac address.
361      * @param portSecurityRule the security rule in the SG
362      * @param srcAddress the destination IP address
363      * @param write add or delete
364      * @param protoPortMatchPriority the protocol match priroty
365      */
366     private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
367                                NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
368                                Integer protoPortMatchPriority ) {
369         boolean portRange = false;
370         MatchBuilder matchBuilder = new MatchBuilder();
371         String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
372         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
373         if (isIpv6) {
374             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
375         } else {
376             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
377         }
378
379         /* Custom TCP Match*/
380         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
381             flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
382             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
383                                                      portSecurityRule.getSecurityRulePortMin());
384         } else {
385             /* All TCP Match */
386             if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
387                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
388                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
389                     + portSecurityRule.getSecurityRulePortMax() + "_";
390                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
391             } else {
392                 portRange = true;
393             }
394         }
395         if (null != srcAddress) {
396             flowId = flowId + srcAddress;
397             if (isIpv6) {
398                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
399                         MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
400             } else {
401                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
402                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
403             }
404         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
405             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
406             if (isIpv6) {
407                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
408                         new Ipv6Prefix(portSecurityRule
409                                        .getSecurityRuleRemoteIpPrefix()),null);
410             } else {
411                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
412                         new Ipv4Prefix(portSecurityRule
413                                        .getSecurityRuleRemoteIpPrefix()),null);
414             }
415         }
416         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
417         if (portRange) {
418             Map<Integer, Integer> portMaskMap = MatchUtils
419                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
420                                            portSecurityRule.getSecurityRulePortMax());
421             for (Integer port: portMaskMap.keySet()) {
422                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
423                 rangeflowId = rangeflowId + "_Permit";
424                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
425                                                   0, port, portMaskMap.get(port));
426                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
427                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
428                                                                       matchBuilder, getTable());
429                 addInstructionWithConntrackCommit(flowBuilder, false);
430                 syncFlow(flowBuilder ,nodeBuilder, write);
431             }
432         } else {
433             flowId = flowId + "_Permit";
434             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
435             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
436                                                                   matchBuilder, getTable());
437             addInstructionWithConntrackCommit(flowBuilder, false);
438             syncFlow(flowBuilder ,nodeBuilder, write);
439         }
440     }
441
442     /**
443      * Creates a ingress match to the dst macaddress. If src address is specified
444      * source specific match will be created. Otherwise a match with a CIDR will
445      * be created.
446      * @param dpidLong the dpid
447      * @param segmentationId the segmentation id
448      * @param dstMac the destination mac address.
449      * @param portSecurityRule the security rule in the SG
450      * @param srcAddress the destination IP address
451      * @param write add or delete
452      * @param protoPortMatchPriority the protocol match priroty
453      */
454     private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
455                                NeutronSecurityRule portSecurityRule, String srcAddress,
456                                boolean write, Integer protoPortMatchPriority ) {
457         boolean portRange = false;
458         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
459         MatchBuilder matchBuilder = new MatchBuilder();
460         String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
461         if (isIpv6)  {
462             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
463         } else {
464             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
465         }
466
467         /* Custom UDP Match */
468         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
469             flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
470             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
471                                                      portSecurityRule.getSecurityRulePortMin());
472         } else {
473             /* All UDP Match */
474             if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
475                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
476                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
477                     + portSecurityRule.getSecurityRulePortMax() + "_";
478                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
479             } else {
480                 portRange = true;
481             }
482         }
483         if (null != srcAddress) {
484             flowId = flowId + srcAddress;
485             if (isIpv6) {
486                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
487                         MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
488             } else {
489                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
490                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
491             }
492         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
493             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
494             if (isIpv6) {
495                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
496                         new Ipv6Prefix(portSecurityRule
497                                        .getSecurityRuleRemoteIpPrefix()),null);
498             } else {
499                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
500                         new Ipv4Prefix(portSecurityRule
501                                        .getSecurityRuleRemoteIpPrefix()),null);
502             }
503         }
504         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
505         if (portRange) {
506             Map<Integer, Integer> portMaskMap = MatchUtils
507                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
508                                            portSecurityRule.getSecurityRulePortMax());
509             for (Integer port: portMaskMap.keySet()) {
510                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
511                 rangeflowId = rangeflowId + "_Permit";
512                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
513                                                    0, port, portMaskMap.get(port));
514                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
515                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
516                                                                       matchBuilder, getTable());
517                 addInstructionWithConntrackCommit(flowBuilder, false);
518                 syncFlow(flowBuilder ,nodeBuilder, write);
519             }
520         } else {
521             flowId = flowId + "_Permit";
522             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
523             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
524                                                                   matchBuilder, getTable());
525             addInstructionWithConntrackCommit(flowBuilder, false);
526             syncFlow(flowBuilder ,nodeBuilder, write);
527         }
528     }
529
530     private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
531             NeutronSecurityRule portSecurityRule, String srcAddress,
532             boolean write, Integer protoPortMatchPriority) {
533
534         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
535         if (isIpv6) {
536             ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
537                              write, protoPortMatchPriority);
538         } else {
539             ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
540                              write, protoPortMatchPriority);
541         }
542     }
543
544     /**
545      * Creates a ingress icmp match to the dst macaddress. If src address is specified
546      * source specific match will be created. Otherwise a match with a CIDR will
547      * be created.
548      * @param dpidLong the dpid
549      * @param segmentationId the segmentation id
550      * @param dstMac the destination mac address.
551      * @param portSecurityRule the security rule in the SG
552      * @param srcAddress the destination IP address
553      * @param write add or delete
554      * @param protoPortMatchPriority the protocol match priority
555      */
556     private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
557                                   NeutronSecurityRule portSecurityRule, String srcAddress,
558                                   boolean write, Integer protoPortMatchPriority) {
559
560         MatchBuilder matchBuilder = new MatchBuilder();
561         String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
562         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
563
564         /* Custom ICMP Match */
565         if (portSecurityRule.getSecurityRulePortMin() != null
566                 && portSecurityRule.getSecurityRulePortMax() != null) {
567             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
568                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
569             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
570                     portSecurityRule.getSecurityRulePortMin().shortValue(),
571                     portSecurityRule.getSecurityRulePortMax().shortValue());
572         } else {
573             /* All ICMP Match */
574             flowId = flowId + "all" + "_";
575             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
576         }
577         if (null != srcAddress) {
578             flowId = flowId + srcAddress;
579             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
580                    MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
581         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
582             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
583             if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
584                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
585                                          new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
586             }
587         }
588         flowId = flowId + "_Permit";
589         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
590         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
591         addInstructionWithConntrackCommit(flowBuilder, false);
592         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
593         syncFlow(flowBuilder ,nodeBuilder, write);
594     }
595
596     /**
597      * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
598      * source specific match will be created. Otherwise a match with a CIDR will
599      * be created.
600      * @param dpidLong the dpid
601      * @param segmentationId the segmentation id
602      * @param dstMac the destination mac address.
603      * @param portSecurityRule the security rule in the SG
604      * @param srcAddress the destination IP address
605      * @param write add or delete
606      * @param protoPortMatchPriority the protocol match priority
607      */
608     private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
609                                   NeutronSecurityRule portSecurityRule, String srcAddress,
610                                   boolean write, Integer protoPortMatchPriority) {
611
612         MatchBuilder matchBuilder = new MatchBuilder();
613         String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
614         matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
615
616         /* Custom ICMP Match */
617         if (portSecurityRule.getSecurityRulePortMin() != null
618                 && portSecurityRule.getSecurityRulePortMax() != null) {
619             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
620                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
621             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
622                     portSecurityRule.getSecurityRulePortMin().shortValue(),
623                     portSecurityRule.getSecurityRulePortMax().shortValue());
624         } else {
625             /* All ICMP Match */
626             flowId = flowId + "all" + "_";
627             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
628         }
629         if (null != srcAddress) {
630             flowId = flowId + srcAddress;
631             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
632                     MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
633         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
634             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
635             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
636                     new Ipv6Prefix(portSecurityRule
637                                    .getSecurityRuleRemoteIpPrefix()),null);
638         }
639         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
640         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
641         flowId = flowId + "_Permit";
642         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
643         addInstructionWithConntrackCommit(flowBuilder, false);
644         syncFlow(flowBuilder ,nodeBuilder, write);
645     }
646
647     /**
648      * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
649      *
650      * @param dpidLong the dpid
651      * @param segmentationId the segmentation id
652      * @param dhcpMacAddress the DHCP server mac address
653      * @param attachMac the mac address of  the port
654      * @param write is write or delete
655      * @param protoPortMatchPriority the priority
656      */
657     private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
658                                                   String attachMac, boolean write, Integer protoPortMatchPriority) {
659
660         MatchBuilder matchBuilder = new MatchBuilder();
661         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
662                                                              MatchUtils.ETHERTYPE_IPV4);
663         MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 67, 68);
664         String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
665         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
666         addPipelineInstruction(flowBuilder, null, false);
667         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
668         syncFlow(flowBuilder ,nodeBuilder, write);
669     }
670
671     /**
672      * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
673      *
674      * @param dpidLong the dpid
675      * @param segmentationId the segmentation id
676      * @param dhcpMacAddress the DHCP server mac address
677      * @param attachMac the mac address of  the port
678      * @param write is write or delete
679      * @param protoPortMatchPriority the priority
680      */
681     private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
682                                                     String attachMac, boolean write, Integer protoPortMatchPriority) {
683
684         MatchBuilder matchBuilder = new MatchBuilder();
685         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
686                                                              MatchUtils.ETHERTYPE_IPV6);
687         MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 547, 546);
688         String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
689         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
690         addPipelineInstruction(flowBuilder, null, false);
691         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
692         syncFlow(flowBuilder ,nodeBuilder, write);
693     }
694
695     private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
696         if (securityServicesManager.isConntrackEnabled()) {
697             MatchUtils.addCtState(matchBuilder, state, mask );
698         }
699
700     }
701
702     private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
703         InstructionBuilder instructionBuilder = null;
704         if (securityServicesManager.isConntrackEnabled()) {
705             Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
706             instructionBuilder = InstructionUtils
707                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
708         }
709         return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
710     }
711
712     private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
713         InstructionBuilder instructionBuilder = null;
714         if (securityServicesManager.isConntrackEnabled()) {
715             Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
716             instructionBuilder = InstructionUtils
717                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
718             List<Instruction> instructionsList = Lists.newArrayList();
719             instructionsList.add(instructionBuilder.build());
720             InstructionsBuilder isb = new InstructionsBuilder();
721             isb.setInstruction(instructionsList);
722             flowBuilder.setInstructions(isb.build());
723         }
724         return flowBuilder;
725     }
726
727     private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder , InstructionBuilder instructionBuilder,
728                                                 boolean isDrop) {
729         InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
730         List<Instruction> instructionsList = Lists.newArrayList();
731         instructionsList.add(pipeLineIndstructionBuilder.build());
732         if (null != instructionBuilder) {
733             instructionsList.add(instructionBuilder.build());
734         }
735         InstructionsBuilder isb = new InstructionsBuilder();
736         isb.setInstruction(instructionsList);
737         flowBuilder.setInstructions(isb.build());
738         return flowBuilder;
739     }
740
741     private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
742         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
743         if (drop) {
744             InstructionUtils.createDropInstructions(ib);
745         }
746         ib.setOrder(0);
747         List<Instruction> instructionsList = Lists.newArrayList();
748         ib.setKey(new InstructionKey(0));
749         instructionsList.add(ib.build());
750         return ib;
751     }
752     /**
753      * Add or remove flow to the node.
754      * @param flowBuilder the flow builder
755      * @param nodeBuilder the node builder
756      * @param write whether it is a write
757      */
758     private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
759                           boolean write) {
760         if (write) {
761             writeFlow(flowBuilder, nodeBuilder);
762         } else {
763             removeFlow(flowBuilder, nodeBuilder);
764         }
765     }
766
767     @Override
768     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
769         super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
770         securityServicesManager =
771                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
772         securityGroupCacheManger =
773                 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
774     }
775
776     @Override
777     public void setDependencies(Object impl) {
778
779     }
780 }