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