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