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, boolean isLastPortinSubnet,
219                                         boolean isComputePort, String attachMac, boolean write) {
220         //If this port is the only port in the compute node add the DHCP server rule.
221         if (isLastPortinSubnet && isComputePort ) {
222             ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
223                                              write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
224             ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
225                                                write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
226         }
227         if (isComputePort) {
228             if (securityServicesManager.isConntrackEnabled()) {
229                 programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
230             }
231             programArpRule(dpid, segmentationId, localPort, attachMac, write);
232         }
233     }
234
235     private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
236         MatchBuilder matchBuilder = new MatchBuilder();
237         String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
238         MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
239         MatchUtils.addArpMacMatch(matchBuilder, null, attachMac);
240         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
241                                                               matchBuilder, getTable());
242         addPipelineInstruction(flowBuilder, null, false);
243         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
244         syncFlow(flowBuilder ,nodeBuilder, write);
245     }
246
247     private void programIngressAclFixedConntrackRule(Long dpid,
248            String segmentationId, String attachMac, long localPort, boolean write) {
249         try {
250             String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
251             programConntrackUntrackRule(dpid, segmentationId, localPort, attachMac,
252                                         Constants.CT_STATE_UNTRACKED_PRIORITY, write );
253             programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort, attachMac,
254                                         Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
255             programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort, attachMac,
256                                                Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
257             programConntrackInvDropRule(dpid, segmentationId, localPort, attachMac,
258                                         Constants.CT_STATE_NEW_PRIORITY_DROP, write );
259             programConntrackNewDropRule(dpid, segmentationId, localPort, attachMac,
260                                              Constants.CT_STATE_NEW_PRIORITY_DROP, write );
261             LOG.info("programIngressAclFixedConntrackRule :  default connection tracking rule are added.");
262         } catch (Exception e) {
263             LOG.error("Failed to add default conntrack rules : " , e);
264         }
265     }
266
267     private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
268                                              long localPort, String attachMac, Integer priority, boolean write) {
269         MatchBuilder matchBuilder = new MatchBuilder();
270         String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
271         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
272         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
273                                              MatchUtils.UNTRACKED_CT_STATE_MASK);
274         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
275         addInstructionWithConntrackRecirc(flowBuilder);
276         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
277         syncFlow(flowBuilder ,nodeBuilder, write);
278     }
279
280     private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
281                                                   long localPort, String attachMac,Integer priority, boolean write) {
282         MatchBuilder matchBuilder = new MatchBuilder();
283         String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
284         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
285         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
286                                              MatchUtils.TRACKED_CT_STATE_MASK);
287         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
288         addPipelineInstruction(flowBuilder, null, false);
289         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
290         syncFlow(flowBuilder ,nodeBuilder, write);
291     }
292
293     private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
294                                                     long localPort, String attachMac,Integer priority, boolean write) {
295         MatchBuilder matchBuilder = new MatchBuilder();
296         String flowName = "Ingress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
297         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
298         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
299                                              MatchUtils.TRACKED_CT_STATE_MASK);
300         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
301         addPipelineInstruction(flowBuilder, null, false);
302         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
303         syncFlow(flowBuilder ,nodeBuilder, write);
304     }
305
306     private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
307                                              long localPort, String attachMac, Integer priority, boolean write) {
308         MatchBuilder matchBuilder = new MatchBuilder();
309
310         String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
311         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,0x0800L);
312         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
313                                              MatchUtils.TRACKED_NEW_CT_STATE_MASK);
314         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
315         addPipelineInstruction(flowBuilder, null, true);
316         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
317         syncFlow(flowBuilder ,nodeBuilder, write);
318     }
319
320     private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
321                                              long localPort, String attachMac, Integer priority, boolean write) {
322         MatchBuilder matchBuilder = new MatchBuilder();
323         String flowName = "Ingress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
324         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac, MatchUtils.ETHERTYPE_IPV4);
325         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
326                                              MatchUtils.TRACKED_INV_CT_STATE_MASK);
327         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
328         addPipelineInstruction(flowBuilder, null, true);
329         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
330         syncFlow(flowBuilder ,nodeBuilder, write);
331     }
332
333     /**
334      * Allows an IPv4/v6 packet ingress to the destination mac address.
335      * @param dpidLong the dpid
336      * @param isIpv6 indicates whether this is an Ipv
337      * @param segmentationId the segementation id
338      * @param dstMac the destination mac address
339      * @param write add or remove
340      * @param protoPortMatchPriority the protocol match priority.
341      */
342     private void ingressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
343                               boolean write, Integer protoPortMatchPriority ) {
344         MatchBuilder matchBuilder = new MatchBuilder();
345         String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
346         if (isIpv6) {
347             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
348         } else {
349             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
350         }
351         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
352         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
353         addInstructionWithConntrackCommit(flowBuilder, false);
354         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
355         syncFlow(flowBuilder ,nodeBuilder, write);
356     }
357
358     /**
359      * Creates a ingress match to the dst macaddress. If src address is specified
360      * source specific match will be created. Otherwise a match with a CIDR will
361      * be created.
362      * @param dpidLong the dpid
363      * @param segmentationId the segmentation id
364      * @param dstMac the destination mac address.
365      * @param portSecurityRule the security rule in the SG
366      * @param srcAddress the destination IP address
367      * @param write add or delete
368      * @param protoPortMatchPriority the protocol match priroty
369      */
370     private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
371                                NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
372                                Integer protoPortMatchPriority ) {
373         boolean portRange = false;
374         MatchBuilder matchBuilder = new MatchBuilder();
375         String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
376         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
377         if (isIpv6) {
378             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
379         } else {
380             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
381         }
382
383         /* Custom TCP Match*/
384         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
385             flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
386             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
387                                                      portSecurityRule.getSecurityRulePortMin());
388         } else {
389             /* All TCP Match */
390             if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
391                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
392                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
393                     + portSecurityRule.getSecurityRulePortMax() + "_";
394                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
395             } else {
396                 portRange = true;
397             }
398         }
399         if (null != srcAddress) {
400             flowId = flowId + srcAddress;
401             if (isIpv6) {
402                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
403                         MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
404             } else {
405                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
406                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
407             }
408         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
409             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
410             if (isIpv6) {
411                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
412                         new Ipv6Prefix(portSecurityRule
413                                        .getSecurityRuleRemoteIpPrefix()),null);
414             } else {
415                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
416                         new Ipv4Prefix(portSecurityRule
417                                        .getSecurityRuleRemoteIpPrefix()),null);
418             }
419         }
420         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
421         if (portRange) {
422             Map<Integer, Integer> portMaskMap = MatchUtils
423                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
424                                            portSecurityRule.getSecurityRulePortMax());
425             for (Integer port: portMaskMap.keySet()) {
426                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
427                 rangeflowId = rangeflowId + "_Permit";
428                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
429                                                   0, port, portMaskMap.get(port));
430                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
431                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
432                                                                       matchBuilder, getTable());
433                 addInstructionWithConntrackCommit(flowBuilder, false);
434                 syncFlow(flowBuilder ,nodeBuilder, write);
435             }
436         } else {
437             flowId = flowId + "_Permit";
438             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
439             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
440                                                                   matchBuilder, getTable());
441             addInstructionWithConntrackCommit(flowBuilder, false);
442             syncFlow(flowBuilder ,nodeBuilder, write);
443         }
444     }
445
446     /**
447      * Creates a ingress match to the dst macaddress. If src address is specified
448      * source specific match will be created. Otherwise a match with a CIDR will
449      * be created.
450      * @param dpidLong the dpid
451      * @param segmentationId the segmentation id
452      * @param dstMac the destination mac address.
453      * @param portSecurityRule the security rule in the SG
454      * @param srcAddress the destination IP address
455      * @param write add or delete
456      * @param protoPortMatchPriority the protocol match priroty
457      */
458     private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
459                                NeutronSecurityRule portSecurityRule, String srcAddress,
460                                boolean write, Integer protoPortMatchPriority ) {
461         boolean portRange = false;
462         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
463         MatchBuilder matchBuilder = new MatchBuilder();
464         String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
465         if (isIpv6)  {
466             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
467         } else {
468             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
469         }
470
471         /* Custom UDP Match */
472         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
473             flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
474             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
475                                                      portSecurityRule.getSecurityRulePortMin());
476         } else {
477             /* All UDP Match */
478             if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
479                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
480                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
481                     + portSecurityRule.getSecurityRulePortMax() + "_";
482                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
483             } else {
484                 portRange = true;
485             }
486         }
487         if (null != srcAddress) {
488             flowId = flowId + srcAddress;
489             if (isIpv6) {
490                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
491                         MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
492             } else {
493                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
494                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
495             }
496         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
497             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
498             if (isIpv6) {
499                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
500                         new Ipv6Prefix(portSecurityRule
501                                        .getSecurityRuleRemoteIpPrefix()),null);
502             } else {
503                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
504                         new Ipv4Prefix(portSecurityRule
505                                        .getSecurityRuleRemoteIpPrefix()),null);
506             }
507         }
508         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
509         if (portRange) {
510             Map<Integer, Integer> portMaskMap = MatchUtils
511                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
512                                            portSecurityRule.getSecurityRulePortMax());
513             for (Integer port: portMaskMap.keySet()) {
514                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
515                 rangeflowId = rangeflowId + "_Permit";
516                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
517                                                    0, port, portMaskMap.get(port));
518                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
519                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
520                                                                       matchBuilder, getTable());
521                 addInstructionWithConntrackCommit(flowBuilder, false);
522                 syncFlow(flowBuilder ,nodeBuilder, write);
523             }
524         } else {
525             flowId = flowId + "_Permit";
526             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
527             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
528                                                                   matchBuilder, getTable());
529             addInstructionWithConntrackCommit(flowBuilder, false);
530             syncFlow(flowBuilder ,nodeBuilder, write);
531         }
532     }
533
534     private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
535             NeutronSecurityRule portSecurityRule, String srcAddress,
536             boolean write, Integer protoPortMatchPriority) {
537
538         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
539         if (isIpv6) {
540             ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
541                              write, protoPortMatchPriority);
542         } else {
543             ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
544                              write, protoPortMatchPriority);
545         }
546     }
547
548     /**
549      * Creates a ingress icmp match to the dst macaddress. If src address is specified
550      * source specific match will be created. Otherwise a match with a CIDR will
551      * be created.
552      * @param dpidLong the dpid
553      * @param segmentationId the segmentation id
554      * @param dstMac the destination mac address.
555      * @param portSecurityRule the security rule in the SG
556      * @param srcAddress the destination IP address
557      * @param write add or delete
558      * @param protoPortMatchPriority the protocol match priority
559      */
560     private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
561                                   NeutronSecurityRule portSecurityRule, String srcAddress,
562                                   boolean write, Integer protoPortMatchPriority) {
563
564         MatchBuilder matchBuilder = new MatchBuilder();
565         String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
566         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
567
568         /* Custom ICMP Match */
569         if (portSecurityRule.getSecurityRulePortMin() != null
570                 && portSecurityRule.getSecurityRulePortMax() != null) {
571             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
572                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
573             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
574                     portSecurityRule.getSecurityRulePortMin().shortValue(),
575                     portSecurityRule.getSecurityRulePortMax().shortValue());
576         } else {
577             /* All ICMP Match */
578             flowId = flowId + "all" + "_";
579             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
580         }
581         if (null != srcAddress) {
582             flowId = flowId + srcAddress;
583             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
584                    MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
585         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
586             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
587             if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
588                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
589                                          new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
590             }
591         }
592         flowId = flowId + "_Permit";
593         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
594         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
595         addInstructionWithConntrackCommit(flowBuilder, false);
596         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
597         syncFlow(flowBuilder ,nodeBuilder, write);
598     }
599
600     /**
601      * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
602      * source specific match will be created. Otherwise a match with a CIDR will
603      * be created.
604      * @param dpidLong the dpid
605      * @param segmentationId the segmentation id
606      * @param dstMac the destination mac address.
607      * @param portSecurityRule the security rule in the SG
608      * @param srcAddress the destination IP address
609      * @param write add or delete
610      * @param protoPortMatchPriority the protocol match priority
611      */
612     private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
613                                   NeutronSecurityRule portSecurityRule, String srcAddress,
614                                   boolean write, Integer protoPortMatchPriority) {
615
616         MatchBuilder matchBuilder = new MatchBuilder();
617         String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
618         matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
619
620         /* Custom ICMP Match */
621         if (portSecurityRule.getSecurityRulePortMin() != null
622                 && portSecurityRule.getSecurityRulePortMax() != null) {
623             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
624                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
625             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
626                     portSecurityRule.getSecurityRulePortMin().shortValue(),
627                     portSecurityRule.getSecurityRulePortMax().shortValue());
628         } else {
629             /* All ICMP Match */
630             flowId = flowId + "all" + "_";
631             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
632         }
633         if (null != srcAddress) {
634             flowId = flowId + srcAddress;
635             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
636                     MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
637         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
638             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
639             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
640                     new Ipv6Prefix(portSecurityRule
641                                    .getSecurityRuleRemoteIpPrefix()),null);
642         }
643         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
644         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
645         flowId = flowId + "_Permit";
646         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
647         addInstructionWithConntrackCommit(flowBuilder, false);
648         syncFlow(flowBuilder ,nodeBuilder, write);
649     }
650
651     /**
652      * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
653      *
654      * @param dpidLong the dpid
655      * @param segmentationId the segmentation id
656      * @param dhcpMacAddress the DHCP server mac address
657      * @param write is write or delete
658      * @param protoPortMatchPriority the priority
659      */
660     private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
661                                                   boolean write, Integer protoPortMatchPriority) {
662
663         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
664         MatchBuilder matchBuilder = new MatchBuilder();
665         MatchUtils.createDhcpServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build();
666         String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
667         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
668         addPipelineInstruction(flowBuilder, null, false);
669         syncFlow(flowBuilder ,nodeBuilder, write);
670     }
671
672     /**
673      * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
674      *
675      * @param dpidLong the dpid
676      * @param segmentationId the segmentation id
677      * @param dhcpMacAddress the DHCP server mac address
678      * @param write is write or delete
679      * @param protoPortMatchPriority the priority
680      */
681     private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
682                                                     boolean write, Integer protoPortMatchPriority) {
683
684         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
685         MatchBuilder matchBuilder = new MatchBuilder();
686         MatchUtils.createDhcpv6ServerMatch(matchBuilder, dhcpMacAddress, 547, 546).build();
687         String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
688         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
689         addPipelineInstruction(flowBuilder, null, false);
690         syncFlow(flowBuilder ,nodeBuilder, write);
691     }
692
693     private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
694         if (securityServicesManager.isConntrackEnabled()) {
695             MatchUtils.addCtState(matchBuilder, state, mask );
696         }
697
698     }
699
700     private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
701         InstructionBuilder instructionBuilder = null;
702         if (securityServicesManager.isConntrackEnabled()) {
703             Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
704             instructionBuilder = InstructionUtils
705                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
706         }
707         return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
708     }
709
710     private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
711         InstructionBuilder instructionBuilder = null;
712         if (securityServicesManager.isConntrackEnabled()) {
713             Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
714             instructionBuilder = InstructionUtils
715                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
716             List<Instruction> instructionsList = Lists.newArrayList();
717             instructionsList.add(instructionBuilder.build());
718             InstructionsBuilder isb = new InstructionsBuilder();
719             isb.setInstruction(instructionsList);
720             flowBuilder.setInstructions(isb.build());
721         }
722         return flowBuilder;
723     }
724
725     private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder , InstructionBuilder instructionBuilder,
726                                                 boolean isDrop) {
727         InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
728         List<Instruction> instructionsList = Lists.newArrayList();
729         instructionsList.add(pipeLineIndstructionBuilder.build());
730         if (null != instructionBuilder) {
731             instructionsList.add(instructionBuilder.build());
732         }
733         InstructionsBuilder isb = new InstructionsBuilder();
734         isb.setInstruction(instructionsList);
735         flowBuilder.setInstructions(isb.build());
736         return flowBuilder;
737     }
738
739     private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
740         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
741         if (drop) {
742             InstructionUtils.createDropInstructions(ib);
743         }
744         ib.setOrder(0);
745         List<Instruction> instructionsList = Lists.newArrayList();
746         ib.setKey(new InstructionKey(0));
747         instructionsList.add(ib.build());
748         return ib;
749     }
750     /**
751      * Add or remove flow to the node.
752      * @param flowBuilder the flow builder
753      * @param nodeBuilder the node builder
754      * @param write whether it is a write
755      */
756     private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
757                           boolean write) {
758         if (write) {
759             writeFlow(flowBuilder, nodeBuilder);
760         } else {
761             removeFlow(flowBuilder, nodeBuilder);
762         }
763     }
764
765     @Override
766     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
767         super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
768         securityServicesManager =
769                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
770         securityGroupCacheManger =
771                 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
772     }
773
774     @Override
775     public void setDependencies(Object impl) {
776
777     }
778 }