Bug-7363: Fix for Flows are overlapped when we add custom SG along with ANY rule.
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / netvirt / openstack / netvirt / providers / openflow13 / services / EgressAclService.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 java.math.BigInteger;
12 import java.net.Inet4Address;
13 import java.net.Inet6Address;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
22 import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
23 import org.opendaylight.netvirt.openstack.netvirt.api.LearnConstants;
24 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
25 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
26 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
27 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
28 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
29 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
30 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
31 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
32 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
33 import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
34 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
35 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
36 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
37 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4MatchBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv6MatchBuilder;
51 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
52 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
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 com.google.common.collect.Lists;
59
60 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
61
62     private static final Logger LOG = LoggerFactory.getLogger(EgressAclService.class);
63     private volatile SecurityServicesManager securityServicesManager;
64     private volatile SecurityGroupCacheManger securityGroupCacheManger;
65     private volatile INeutronSecurityRuleCRUD neutronSecurityRule;
66     private static final int DHCP_SOURCE_PORT = 67;
67     private static final int DHCP_DESTINATION_PORT = 68;
68     private static final int DHCPV6_SOURCE_PORT = 547;
69     private static final int DHCPV6_DESTINATION_PORT = 546;
70     private static final String HOST_MASK = "/32";
71     private static final String V6_HOST_MASK = "/128";
72     private static final int PORT_RANGE_MIN = 1;
73     private static final int PORT_RANGE_MAX = 65535;
74
75     public EgressAclService() {
76         super(Service.EGRESS_ACL);
77     }
78
79     public EgressAclService(Service service) {
80         super(service);
81     }
82
83     @Override
84     public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
85                                        NeutronSecurityGroup securityGroup, String portUuid, NodeId nodeId, boolean write) {
86
87         LOG.trace("programPortSecurityGroup: neutronSecurityGroup: {} ", securityGroup);
88         if (securityGroup == null || getSecurityRulesforGroup(securityGroup) == null) {
89             return;
90         }
91
92         List<NeutronSecurityRule> portSecurityList = getSecurityRulesforGroup(securityGroup);
93         /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
94         for (NeutronSecurityRule portSecurityRule : portSecurityList) {
95
96             /**
97              * Neutron Port Security Acl "egress" and "IPv4"
98              * Check that the base conditions for flow based Port Security are true:
99              * Port Security Rule Direction ("egress") and Protocol ("IPv4")
100              * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
101              * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
102              *
103              */
104
105             if (portSecurityRule == null
106                     || portSecurityRule.getSecurityRuleEthertype() == null
107                     || portSecurityRule.getSecurityRuleDirection() == null) {
108                 continue;
109             }
110
111             if (NeutronSecurityRule.DIRECTION_EGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
112                 LOG.debug("programPortSecurityGroup: Acl Rule matching IP and ingress is: {} ", portSecurityRule);
113                 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
114                     //Remote Security group is selected
115                     List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
116                             .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
117                     if (null != remoteSrcAddressList) {
118                         for (Neutron_IPs vmIp :remoteSrcAddressList ) {
119
120                             programPortSecurityRule(dpid, segmentationId, attachedMac,
121                                                     localPort, portSecurityRule, vmIp, write);
122                         }
123                         if (write) {
124                             securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid, nodeId);
125                         } else {
126                             securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
127                                                                      portUuid);
128                         }
129                     }
130                 } else {
131                     programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
132                                             portSecurityRule, null, write);
133                 }
134                 if (write) {
135                     securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
136                 } else {
137                     securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
138                 }
139             }
140         }
141     }
142
143     @Override
144     public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
145                                         long localPort, NeutronSecurityRule portSecurityRule,
146                                         Neutron_IPs vmIp, boolean write) {
147         String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
148         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
149         if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
150             LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
151                 securityRuleEtherType);
152             return;
153         }
154
155
156         String ipaddress = null;
157         if (null != vmIp) {
158             ipaddress = vmIp.getIpAddress();
159             try {
160                 InetAddress address = InetAddress.getByName(ipaddress);
161                 if (isIpv6 && address instanceof Inet4Address || !isIpv6 && address instanceof Inet6Address) {
162                     LOG.debug("programPortSecurityRule: Remote vmIP {} does not match with "
163                             + "SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
164                     return;
165                 }
166             } catch (UnknownHostException e) {
167                 LOG.warn("Invalid IP address {}", ipaddress, e);
168                 return;
169             }
170         }
171         if (null == portSecurityRule.getSecurityRuleProtocol()) {
172             /* TODO Rework on the priority values */
173             egressAclIp(dpid, isIpv6, segmentationId, attachedMac,
174                 portSecurityRule, ipaddress,
175                 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
176             if(!isIpv6) {
177                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.TCP);
178                 portSecurityRule.setSecurityRulePortMin(PORT_RANGE_MIN);
179                 portSecurityRule.setSecurityRulePortMax(PORT_RANGE_MAX);
180                 egressAclTcp(dpid, segmentationId, attachedMac,
181                         portSecurityRule,ipaddress, write,
182                         Constants.PROTO_PORT_MATCH_PRIORITY, false);
183                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.UDP);
184                 egressAclUdp(dpid, segmentationId, attachedMac,
185                         portSecurityRule, ipaddress, write,
186                         Constants.PROTO_PORT_MATCH_PRIORITY, false);
187                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.ICMP);
188                 portSecurityRule.setSecurityRulePortMin(null);
189                 portSecurityRule.setSecurityRulePortMax(null);
190                 egressAclIcmp(dpid, segmentationId, attachedMac,
191                         portSecurityRule, ipaddress,write,
192                         Constants.PROTO_PORT_MATCH_PRIORITY, false);
193                 portSecurityRule.setSecurityRuleProtocol(null);
194             }
195         } else {
196             switch (portSecurityRule.getSecurityRuleProtocol() == null ? "" : portSecurityRule.getSecurityRuleProtocol()) {
197                 case MatchUtils.TCP:
198                     LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
199                     egressAclTcp(dpid, segmentationId, attachedMac,
200                         portSecurityRule,ipaddress, write,
201                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
202                     break;
203                 case MatchUtils.UDP:
204                     LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
205                     egressAclUdp(dpid, segmentationId, attachedMac,
206                         portSecurityRule, ipaddress, write,
207                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
208                     break;
209                 case MatchUtils.ICMP:
210                 case MatchUtils.ICMPV6:
211                     LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
212                     egressAclIcmp(dpid, segmentationId, attachedMac,
213                         portSecurityRule, ipaddress,write,
214                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
215                     break;
216                 default:
217                     LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
218                             + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
219                     egressOtherProtocolAclHandler(dpid, segmentationId, attachedMac,
220                         portSecurityRule, ipaddress, write,
221                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, isIpv6);
222                     break;
223             }
224         }
225     }
226
227     private void egressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String srcMac,
228                                                NeutronSecurityRule portSecurityRule, String dstAddress,
229                                                boolean write, Integer priority, boolean isIpv6) {
230         if(null == portSecurityRule.getSecurityRuleProtocol() || portSecurityRule.getSecurityRuleProtocol().equals(MatchUtils.ANY_PROTOCOL)) {
231             egressAclIp(dpidLong, isIpv6, segmentationId, srcMac,
232                     portSecurityRule, dstAddress,
233                     write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY - 1, true);
234             if(!isIpv6) {
235                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.TCP);
236                 portSecurityRule.setSecurityRulePortMin(PORT_RANGE_MIN);
237                 portSecurityRule.setSecurityRulePortMax(PORT_RANGE_MAX);
238                 egressAclTcp(dpidLong, segmentationId, srcMac,
239                         portSecurityRule,dstAddress, write,
240                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, true);
241                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.UDP);
242                 egressAclUdp(dpidLong, segmentationId, srcMac,
243                         portSecurityRule, dstAddress, write,
244                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, true);
245                 portSecurityRule.setSecurityRulePortMin(null);
246                 portSecurityRule.setSecurityRulePortMax(null);
247                 portSecurityRule.setSecurityRuleProtocol(MatchUtils.ICMP);
248                 egressAclIcmp(dpidLong, segmentationId, srcMac,
249                         portSecurityRule, dstAddress,write,
250                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, true);
251                 portSecurityRule.setSecurityRuleProtocol(null);
252             }
253         } else {
254             if (portSecurityRule.getSecurityRuleProtocol().equals(MatchUtils.TCP_PROTOCOL)) {
255                 portSecurityRule.setSecurityRulePortMin(PORT_RANGE_MIN);
256                 portSecurityRule.setSecurityRulePortMax(PORT_RANGE_MAX);
257                 egressAclTcp(dpidLong, segmentationId, srcMac,
258                         portSecurityRule,dstAddress, write,
259                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
260             } else if (portSecurityRule.getSecurityRuleProtocol().equals(MatchUtils.UDP_PROTOCOL)) {
261                 portSecurityRule.setSecurityRulePortMin(PORT_RANGE_MIN);
262                 portSecurityRule.setSecurityRulePortMax(PORT_RANGE_MAX);
263                 egressAclUdp(dpidLong, segmentationId, srcMac,
264                         portSecurityRule, dstAddress, write,
265                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
266             } else if (portSecurityRule.getSecurityRuleProtocol().equals(MatchUtils.ICMP_PROTOCOL)) {
267                 egressAclIcmp(dpidLong, segmentationId, srcMac,
268                         portSecurityRule, dstAddress,write,
269                         Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY, false);
270             } else {
271                 MatchBuilder matchBuilder = new MatchBuilder();
272                 String flowId = "Egress_Other_" + segmentationId + "_" + srcMac + "_";
273                 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
274                 short proto = 0;
275                 try {
276                     Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
277                     proto = protocol.shortValue();
278                     flowId = flowId + proto;
279                 } catch (NumberFormatException e) {
280                     LOG.error("Protocol vlaue conversion failure", e);
281                 }
282                 matchBuilder = MatchUtils.createIpProtocolAndEthMatch(matchBuilder, proto, srcMac, null);
283                 if (null != dstAddress) {
284                     flowId = flowId + dstAddress;
285                     matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
286                                                                  MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
287                 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
288                     flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
289                     if(isIpv6) {
290                         matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
291                                 new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
292                     } else {
293                         if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
294                             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
295                                 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
296                         }
297                     }
298                 }
299                 flowId = flowId + "_Permit";
300                 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
301                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, priority, matchBuilder, getTable());
302                 addInstructionWithConntrackCommit(flowBuilder, false);
303                 syncFlow(flowBuilder ,nodeBuilder, write);
304             }
305         }
306     }
307
308     @Override
309     public void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac,
310                                           long localPort, List<Neutron_IPs> srcAddressList, boolean write) {
311
312         egressAclDhcpAllowClientTrafficFromVm(dpid, write, localPort,
313                                               Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
314         egressAclDhcpv6AllowClientTrafficFromVm(dpid, write, localPort,
315                                                 Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
316         programArpRule(dpid, segmentationId, localPort, attachedMac, write);
317         if (securityServicesManager.isConntrackEnabled()) {
318             programEgressAclFixedConntrackRule(dpid, segmentationId, localPort, attachedMac, write);
319         } else {
320             egressVMDrop(dpid, segmentationId, attachedMac, write,Constants.PROTO_TCP_SYN_MATCH_PRIORITY_DROP);
321             egressVMRegex(dpid, segmentationId, attachedMac, write,Constants.PROTO_REG6_MATCH_PRIORITY);
322         }
323         egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
324                                              Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
325         egressAclDhcpv6DropServerTrafficfromVm(dpid, localPort, write,
326                                                Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
327     }
328     private void egressVMRegex(Long dpidLong, String segmentationId, String srcMac,
329             boolean write, Integer priority) {
330         String flowName = "Egress_Regx_" + segmentationId + "_" + srcMac;
331         MatchBuilder matchBuilder = new MatchBuilder();
332         matchBuilder = MatchUtils.createV4EtherMatchWithoutType(matchBuilder,srcMac,null);
333         MatchUtils.addNxRegMatch(matchBuilder,
334                 new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL));
335         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
336         addPipelineInstruction(flowBuilder, null, false);
337         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
338         syncFlow(flowBuilder, nodeBuilder, write);
339     }
340
341     private void addTcpSynFlagMatchIpv4Drop(Long dpidLong, String segmentationId, String srcMac,
342                                   boolean write, Integer priority) {
343         String flowName = "Egress_TCP_Ipv4_" + segmentationId + "_" + srcMac + "_DROP";
344         MatchBuilder matchBuilder = new MatchBuilder();
345         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
346         matchBuilder = MatchUtils.addTcpSynMatch(matchBuilder);
347         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
348         addPipelineInstruction(flowBuilder, null, true);
349         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
350         syncFlow(flowBuilder, nodeBuilder, write);
351     }
352     private void egressVMDrop(Long dpidLong, String segmentationId, String srcMac,
353             boolean write, Integer priority) {
354         String flowName = "Egress_Drop_" + segmentationId + "_" + srcMac + "_DROP";
355         MatchBuilder matchBuilder = new MatchBuilder();
356         matchBuilder = MatchUtils.createV4EtherMatchWithoutType(matchBuilder,srcMac,null);
357         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
358         addPipelineInstruction(flowBuilder, null, true);
359         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
360         syncFlow(flowBuilder, nodeBuilder, write);
361     }
362
363     private void addTcpSynFlagMatchIpv6Drop(Long dpidLong, String segmentationId, String srcMac,
364                                         boolean write, Integer priority) {
365         String flowName = "Egress_TCP_Ipv6_" + segmentationId + "_" + srcMac + "_DROP";
366         MatchBuilder matchBuilder = new MatchBuilder();
367         matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
368         matchBuilder = MatchUtils.addTcpSynMatch(matchBuilder);
369         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
370         addPipelineInstruction(flowBuilder, null, true);
371         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
372         syncFlow(flowBuilder, nodeBuilder, write);
373     }
374
375     private void programArpRule(Long dpid, String segmentationId, long localPort, String attachedMac, boolean write) {
376         MatchBuilder matchBuilder = new MatchBuilder();
377         String flowId = "Egress_ARP_" + segmentationId + "_" + localPort + "_";
378         MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
379         MatchUtils.addArpMacMatch(matchBuilder, attachedMac, null);
380         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
381                                                               matchBuilder, getTable());
382         addPipelineInstruction(flowBuilder, null, false);
383         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
384         syncFlow(flowBuilder ,nodeBuilder, write);
385     }
386
387     private void programEgressAclFixedConntrackRule(Long dpid,
388                                              String segmentationId, long localPort, String attachMac, boolean write) {
389         try {
390             programConntrackUntrackRule(dpid, segmentationId, localPort,attachMac,
391                                         Constants.CT_STATE_UNTRACKED_PRIORITY, write );
392             programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort,
393                                                Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
394             programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort,
395                                                Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
396             programConntrackNewDropRule(dpid, segmentationId, localPort,
397                                         Constants.CT_STATE_NEW_PRIORITY_DROP, write );
398             programConntrackInvDropRule(dpid, segmentationId, localPort,
399                                         Constants.CT_STATE_NEW_PRIORITY_DROP, write );
400             LOG.info("programEgressAclFixedConntrackRule :  default connection tracking rule are added.");
401         } catch (Exception e) {
402             LOG.error("Failed to add default conntrack rules : " , e);
403         }
404     }
405
406     private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
407                                              long localPort, String attachMac, Integer priority, boolean write) {
408         MatchBuilder matchBuilder = new MatchBuilder();
409         String flowName = "Egress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
410         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder, attachMac, null,MatchUtils.ETHERTYPE_IPV4);
411         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
412                                              MatchUtils.UNTRACKED_CT_STATE_MASK);
413         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
414         addInstructionWithConntrackRecirc(flowBuilder);
415         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
416         syncFlow(flowBuilder ,nodeBuilder, write);
417     }
418
419     private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
420                                                     long localPort,Integer priority, boolean write) {
421         MatchBuilder matchBuilder = new MatchBuilder();
422         String flowName = "Egress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
423         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
424         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
425                                              MatchUtils.TRACKED_CT_STATE_MASK);
426         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
427         addPipelineInstruction(flowBuilder, null, false);
428         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
429         syncFlow(flowBuilder ,nodeBuilder, write);
430     }
431
432     private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
433                                                     long localPort,Integer priority, boolean write) {
434         MatchBuilder matchBuilder = new MatchBuilder();
435         String flowName = "Egress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
436         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
437         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
438                                              MatchUtils.TRACKED_CT_STATE_MASK);
439         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
440         addPipelineInstruction(flowBuilder, null, false);
441         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
442         syncFlow(flowBuilder ,nodeBuilder, write);
443     }
444
445     private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
446                                              long localPort, Integer priority, boolean write) {
447         MatchBuilder matchBuilder = new MatchBuilder();
448
449         String flowName = "Egress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
450         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
451         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
452                                              MatchUtils.TRACKED_NEW_CT_STATE_MASK);
453         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
454         addPipelineInstruction(flowBuilder, null, true);
455         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
456         syncFlow(flowBuilder ,nodeBuilder, write);
457     }
458
459     private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
460                                              long localPort, Integer priority, boolean write) {
461         MatchBuilder matchBuilder = new MatchBuilder();
462         String flowName = "Egress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
463         matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
464         matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
465                                              MatchUtils.TRACKED_INV_CT_STATE_MASK);
466         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
467         addPipelineInstruction(flowBuilder, null, true);
468         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
469         syncFlow(flowBuilder ,nodeBuilder, write);
470     }
471
472     /**
473      * Allows IPv4/v6 packet egress from the src mac address.
474      * @param dpidLong the dpid
475      * @param isIpv6 whether the rule is for ipv6
476      * @param segmentationId the segementation id
477      * @param srcMac the src mac address
478      * @param write add or remove
479      * @param isRegMatchReq add Reg MAtch or not
480      * @param protoPortMatchPriority the protocol match priority.
481      */
482     private void egressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String srcMac,
483                              NeutronSecurityRule portSecurityRule, String srcAddress,
484                                boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq ) {
485         MatchBuilder matchBuilder = new MatchBuilder();
486         String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
487         if (isIpv6) {
488             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
489         } else {
490             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
491         }
492         if (isRegMatchReq) {
493             flowId = flowId + "_regEx_";
494             MatchUtils.addNxRegMatch(matchBuilder,
495                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
496         }
497         if (null != srcAddress) {
498             flowId = flowId + srcAddress;
499             if (isIpv6) {
500                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
501                         MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
502             } else {
503                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
504                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
505             }
506         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
507             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
508             if (isIpv6) {
509                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
510                         new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
511             } else {
512                 // Fix: Bug 6473
513                 // IP match removed if CIDR created as 0.0.0.0/0 in openstack security rule
514                 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
515                     matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
516                             new Ipv4Prefix(portSecurityRule
517                                            .getSecurityRuleRemoteIpPrefix()));
518                  }
519             }
520         } else {
521             if (isIpv6) {
522                 flowId = flowId + "Ipv6";
523             } else {
524                 flowId = flowId + "Ipv4";
525             }
526         }
527         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
528         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
529         addInstructionWithConntrackCommit(flowBuilder, false);
530         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
531         syncFlow(flowBuilder ,nodeBuilder, write);
532     }
533
534     /**
535      * Creates a egress match with src macaddress. If dest address is specified
536      * destination specific match will be created. Otherwise a match with a
537      * CIDR will be created.
538      * @param dpidLong the dpid
539      * @param segmentationId the segmentation id
540      * @param srcMac the source mac address.
541      * @param portSecurityRule the security rule in the SG
542      * @param dstAddress the destination IP address
543      * @param write add or delete
544      * @param isRegMatchReq add Reg MAtch or not
545      * @param protoPortMatchPriority the protocol match priroty
546      */
547     private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
548                               NeutronSecurityRule portSecurityRule, String dstAddress,
549                               boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq) {
550         boolean portRange = false;
551         MatchBuilder matchBuilder = new MatchBuilder();
552         String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
553         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
554         if (isIpv6) {
555             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
556         } else {
557             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
558         }
559         if (isRegMatchReq) {
560             flowId = flowId + "_regEx_";
561             MatchUtils.addNxRegMatch(matchBuilder,
562                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
563         }
564
565         /* Custom TCP Match */
566         if (portSecurityRule.getSecurityRulePortMin() != null && portSecurityRule.getSecurityRulePortMax() != null) {
567             if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
568                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
569                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
570                         portSecurityRule.getSecurityRulePortMin());
571             } else if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
572                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
573                 /* All TCP Match */
574                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
575                         + portSecurityRule.getSecurityRulePortMax() + "_";
576                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
577             } else {
578                 portRange = true;
579             }
580         }
581         if (null != dstAddress) {
582             flowId = flowId + dstAddress;
583             if (isIpv6) {
584                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
585                         MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
586             } else {
587                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
588                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
589             }
590         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
591             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
592             if (isIpv6) {
593                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
594                         new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
595             } else {
596                 // Fix: Bug 6473
597                 // IP match removed if CIDR created as 0.0.0.0/0 in openstack security rule
598                 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
599                     matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
600                             new Ipv4Prefix(portSecurityRule
601                                            .getSecurityRuleRemoteIpPrefix()));
602                  }
603             }
604         }
605         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
606         if (portRange) {
607             Map<Integer, Integer> portMaskMap = MatchUtils
608                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
609                                            portSecurityRule.getSecurityRulePortMax());
610             for (Integer port: portMaskMap.keySet()) {
611                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
612                 rangeflowId = rangeflowId + "_Permit";
613                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
614                                                   0, port, portMaskMap.get(port));
615                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
616                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
617                                                                       matchBuilder, getTable());
618                 addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, null, null);
619                 syncFlow(flowBuilder ,nodeBuilder, write);
620             }
621         } else {
622             flowId = flowId + "_Permit";
623             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
624             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
625                                                                   matchBuilder, getTable());
626             addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, null, null);
627             syncFlow(flowBuilder ,nodeBuilder, write);
628         }
629     }
630
631     private void addTcpSynMatch(MatchBuilder matchBuilder) {
632         if (!securityServicesManager.isConntrackEnabled()) {
633             MatchUtils.createTcpProtoSynMatch(matchBuilder);
634         }
635     }
636
637     private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
638             NeutronSecurityRule portSecurityRule, String dstAddress,
639             boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq) {
640
641         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
642         if (isIpv6) {
643             egressAclIcmpV6(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
644                             protoPortMatchPriority, isRegMatchReq);
645         } else {
646             egressAclIcmpV4(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
647                             protoPortMatchPriority, isRegMatchReq);
648         }
649     }
650
651     /**
652      * Creates a icmp egress match with src macaddress. If dest address is specified
653      * destination specific match will be created. Otherwise a match with a
654      * CIDR will be created.
655      * @param dpidLong the dpid
656      * @param segmentationId the segmentation id
657      * @param srcMac the source mac address.
658      * @param portSecurityRule the security rule in the SG
659      * @param dstAddress the source IP address
660      * @param write add or delete
661      * @param isRegMatchReq add Reg MAtch or not
662      * @param protoPortMatchPriority the protocol match priority
663      */
664     private void egressAclIcmpV4(Long dpidLong, String segmentationId, String srcMac,
665                                  NeutronSecurityRule portSecurityRule, String dstAddress,
666                                  boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq) {
667
668         MatchBuilder matchBuilder = new MatchBuilder();
669         boolean isIcmpAll = false;
670         String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
671         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
672         /*Custom ICMP Match */
673         if (portSecurityRule.getSecurityRulePortMin() != null
674                 && portSecurityRule.getSecurityRulePortMax() != null) {
675             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
676                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
677             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
678                     portSecurityRule.getSecurityRulePortMin().shortValue(),
679                     portSecurityRule.getSecurityRulePortMax().shortValue());
680         } else {
681             isIcmpAll = true;
682             /* All ICMP Match */ // We are getting from neutron NULL for both min and max
683             flowId = flowId + "all" + "_" ;
684             matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
685         }
686         if (isRegMatchReq) {
687             flowId = flowId + "_regEx_";
688             MatchUtils.addNxRegMatch(matchBuilder,
689                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
690         }
691         if (null != dstAddress) {
692             flowId = flowId + dstAddress;
693             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
694                     MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
695         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
696             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
697             if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
698                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
699                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
700             }
701         }
702         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
703         //matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, portSecurityRule.getSecurityRulePortMin().shortValue(), portSecurityRule.getSecurityRulePortMax().shortValue());
704         if(isIcmpAll)
705         {
706             Map<Integer, String> map = LearnConstants.ICMP_TYPE_MAP;
707             for(Map.Entry<Integer, String> entry : map.entrySet()) {
708                 Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
709                 icmpv4match.setIcmpv4Type(entry.getKey().shortValue());
710                 icmpv4match.setIcmpv4Code((short)0);
711                 matchBuilder.setIcmpv4Match(icmpv4match.build());
712                 String rangeflowId = flowId + "_" + entry.getKey() + "_" + entry.getValue();
713                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
714                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority, matchBuilder, getTable());
715                 addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, entry.getValue(), "0");
716                 syncFlow(flowBuilder ,nodeBuilder, write);
717             }
718             addIcmpFlow(nodeBuilder, portSecurityRule, segmentationId, srcMac, dstAddress, write, isRegMatchReq);
719         } else {
720             flowId = flowId + "_Permit";
721             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
722             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
723              String icmpType = LearnConstants.ICMP_TYPE_MAP.get(portSecurityRule.getSecurityRulePortMin());
724             if (icmpType == null){
725                 icmpType = Integer.toString(portSecurityRule.getSecurityRulePortMin());
726             }
727             addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, icmpType,
728                     Integer.toString(portSecurityRule.getSecurityRulePortMax()));
729             syncFlow(flowBuilder ,nodeBuilder, write);
730         }
731     }
732
733     private void addIcmpFlow(NodeBuilder nodeBuilder, NeutronSecurityRule portSecurityRule, String segmentationId, String srcMac,
734             String dstAddress, boolean write, boolean isRegMatchReq){
735         MatchBuilder matchBuilder = new MatchBuilder();
736         InstructionBuilder instructionBuilder = null;
737         short learnTableId=getTable(Service.ACL_LEARN_SERVICE);
738         short resubmitId=getTable(Service.LOAD_BALANCER);
739         String flowId = "Ingress_ICMP_" + segmentationId + "_" + srcMac + "_";
740         matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
741         flowId = flowId + "all" + "_" ;
742         matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
743         if (null != dstAddress) {
744             flowId = flowId + dstAddress;
745             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
746                     MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
747         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
748             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
749             if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
750                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
751                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
752             }
753         }
754         if (isRegMatchReq) {
755             flowId = flowId + "_regEx_";
756             MatchUtils.addNxRegMatch(matchBuilder,
757                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
758         }
759         Icmpv4MatchBuilder icmpv4match = new Icmpv4MatchBuilder();
760         matchBuilder.setIcmpv4Match(icmpv4match.build());
761         String rangeflowId = flowId;
762         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
763         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, Constants.PROTO_PORT_ICMP_MATCH_PRIORITY, matchBuilder, getTable());
764         addPipelineInstruction(flowBuilder, null, false);
765         syncFlow(flowBuilder ,nodeBuilder, write);
766
767     }
768
769     /**
770      * Creates a icmpv6 egress match with src macaddress. If dest address is specified
771      * destination specific match will be created. Otherwise a match with a
772      * CIDR will be created.
773      * @param dpidLong the dpid
774      * @param segmentationId the segmentation id
775      * @param srcMac the source mac address.
776      * @param portSecurityRule the security rule in the SG
777      * @param dstAddress the source IP address
778      * @param write add or delete
779      * @param isRegMatchReq add Reg MAtch or not
780      * @param protoPortMatchPriority the protocol match priority
781      */
782     private void egressAclIcmpV6(Long dpidLong, String segmentationId, String srcMac,
783                                  NeutronSecurityRule portSecurityRule, String dstAddress,
784                                  boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq) {
785
786         MatchBuilder matchBuilder = new MatchBuilder();
787         String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
788         matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
789
790         /*Custom ICMP Match */
791         if (portSecurityRule.getSecurityRulePortMin() != null
792                 && portSecurityRule.getSecurityRulePortMax() != null) {
793             flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
794                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
795             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
796                     portSecurityRule.getSecurityRulePortMin().shortValue(),
797                     portSecurityRule.getSecurityRulePortMax().shortValue());
798         } else {
799             /* All ICMP Match */ // We are getting from neutron NULL for both min and max
800             flowId = flowId + "all" + "_" ;
801             matchBuilder = MatchUtils.createICMPv6Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
802         }
803         if (isRegMatchReq) {
804             flowId = flowId + "_regEx_";
805             MatchUtils.addNxRegMatch(matchBuilder,
806                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
807         }
808         if (null != dstAddress) {
809             flowId = flowId + dstAddress;
810             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
811                     MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
812         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
813             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
814             matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
815                     new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
816         }
817         flowId = flowId + "_Permit";
818         addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
819         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
820         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
821         addInstructionWithConntrackCommit(flowBuilder, false);
822         syncFlow(flowBuilder ,nodeBuilder, write);
823     }
824
825     /**
826      * Creates a egress match with src macaddress. If dest address is specified
827      * destination specific match will be created. Otherwise a match with a
828      * CIDR will be created.
829      * @param dpidLong the dpid
830      * @param segmentationId the segmentation id
831      * @param srcMac the source mac address.
832      * @param portSecurityRule the security rule in the SG
833      * @param dstAddress the source IP address
834      * @param write add or delete
835      * @param isRegMatchReq add Reg MAtch or not
836      * @param protoPortMatchPriority the protocol match priroty
837      */
838     private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
839                               NeutronSecurityRule portSecurityRule, String dstAddress,
840                               boolean write, Integer protoPortMatchPriority, boolean isRegMatchReq) {
841         boolean portRange = false;
842         MatchBuilder matchBuilder = new MatchBuilder();
843         String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
844         boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
845         if (isIpv6) {
846             matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
847         } else {
848             matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
849         }
850         if (isRegMatchReq) {
851             flowId = flowId + "_regEx_";
852             MatchUtils.addNxRegMatch(matchBuilder,
853                     new MatchUtils.RegMatch(ClassifierService.REG_FIELD_6, ClassifierService.REG_VALUE_FROM_LOCAL_0));
854         }
855
856         /* Custom UDP Match */
857         if (portSecurityRule.getSecurityRulePortMin() != null && portSecurityRule.getSecurityRulePortMax() != null) {
858             if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
859                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
860                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
861                         portSecurityRule.getSecurityRulePortMin());
862             } else if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
863                     && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
864                 /* All UDP Match */
865                 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
866                         + portSecurityRule.getSecurityRulePortMax() + "_";
867                 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
868             } else {
869                 portRange = true;
870             }
871         }
872         if (null != dstAddress) {
873             flowId = flowId + dstAddress;
874             if (isIpv6) {
875                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
876                         MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
877             } else {
878                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
879                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
880             }
881         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
882             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
883             if (isIpv6) {
884                 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder, null,
885                         new Ipv6Prefix(portSecurityRule
886                                        .getSecurityRuleRemoteIpPrefix()));
887             } else {
888                 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
889                 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
890                         new Ipv4Prefix(portSecurityRule
891                                        .getSecurityRuleRemoteIpPrefix()));
892                 }
893             }
894         }
895         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
896         if (portRange) {
897             Map<Integer, Integer> portMaskMap = MatchUtils
898                     .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
899                                            portSecurityRule.getSecurityRulePortMax());
900             for (Integer port: portMaskMap.keySet()) {
901                 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
902                 rangeflowId = rangeflowId + "_Permit";
903                 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
904                                                   0, port, portMaskMap.get(port));
905                 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
906                 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
907                                                                       matchBuilder, getTable());
908                 addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, null, null);
909                 syncFlow(flowBuilder ,nodeBuilder, write);
910             }
911         } else {
912             flowId = flowId + "_Permit";
913             addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
914             FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
915                                                                   matchBuilder, getTable());
916             addInstructionWithLearnConntrackCommit(portSecurityRule, flowBuilder, null, null);
917             syncFlow(flowBuilder ,nodeBuilder, write);
918         }
919     }
920
921     /**
922      * Adds flow to allow any DHCP client traffic.
923      *
924      * @param dpidLong the dpid
925      * @param write whether to write or delete the flow
926      * @param localPort the local port.
927      * @param priority the priority
928      */
929     private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
930                                                        boolean write, long localPort, Integer priority) {
931         String flowName = "Egress_DHCP_Client_"  + localPort + "_Permit_";
932         MatchBuilder matchBuilder = new MatchBuilder();
933         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
934         MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT);
935         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
936         addPipelineInstruction(flowBuilder, null, false);
937         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
938         syncFlow(flowBuilder ,nodeBuilder, write);
939     }
940
941     /**
942      * Adds flow to allow any DHCP IPv6 client traffic.
943      *
944      * @param dpidLong the dpid
945      * @param write whether to write or delete the flow
946      * @param localPort the local port
947      * @param priority the priority
948      */
949     private void egressAclDhcpv6AllowClientTrafficFromVm(Long dpidLong,
950                                                          boolean write, long localPort, Integer priority) {
951         String flowName = "Egress_DHCPv6_Client_"  + localPort + "_Permit_";
952         MatchBuilder matchBuilder = new MatchBuilder();
953         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
954         MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_DESTINATION_PORT, DHCPV6_SOURCE_PORT);
955         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
956         addPipelineInstruction(flowBuilder, null, false);
957         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
958         syncFlow(flowBuilder ,nodeBuilder, write);
959     }
960
961     /**
962      * Adds rule to prevent DHCP spoofing by the vm attached to the port.
963      *
964      * @param dpidLong the dpid
965      * @param localPort the local port
966      * @param write is write or delete
967      * @param priority  the priority
968      */
969     private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
970                                                       boolean write, Integer priority) {
971         String flowName = "Egress_DHCP_Server_" + localPort + "_DROP";
972         MatchBuilder matchBuilder = new MatchBuilder();
973         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
974         MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT);
975         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
976         addPipelineInstruction(flowBuilder, null, true);
977         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
978         syncFlow(flowBuilder ,nodeBuilder, write);
979     }
980
981     /**
982      * Adds rule to prevent DHCPv6 spoofing by the vm attached to the port.
983      *
984      * @param dpidLong the dpid
985      * @param localPort the local port
986      * @param write is write or delete
987      * @param priority  the priority
988      */
989     private void egressAclDhcpv6DropServerTrafficfromVm(Long dpidLong, long localPort,
990                                                         boolean write, Integer priority) {
991
992         String flowName = "Egress_DHCPv6_Server_" + "_" + localPort + "_DROP";
993         MatchBuilder matchBuilder = new MatchBuilder();
994         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
995         MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_SOURCE_PORT, DHCPV6_DESTINATION_PORT);
996         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
997         addPipelineInstruction(flowBuilder, null, true);
998         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
999         syncFlow(flowBuilder ,nodeBuilder, write);
1000     }
1001
1002     /**
1003      * Adds rule to check legitimate ip/mac pair for each packet from the vm.
1004      *
1005      * @param dpidLong the dpid
1006      * @param localPort the local port
1007      * @param srcIp the vm ip address
1008      * @param attachedMac the vm mac address
1009      * @param priority  the priority
1010      * @param write is write or delete
1011      */
1012     private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
1013                                                       String attachedMac, String srcIp,
1014                                                       Integer priority, boolean write) {
1015         MatchBuilder matchBuilder = new MatchBuilder();
1016         MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
1017         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
1018         LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
1019         String flowName = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
1020         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
1021         addPipelineInstruction(flowBuilder, null, false);
1022         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1023         syncFlow(flowBuilder ,nodeBuilder, write);
1024     }
1025
1026     /**
1027      * Adds rule to check legitimate ip/mac pair for each packet from the vm.
1028      *
1029      * @param dpidLong the dpid
1030      * @param localPort the local port
1031      * @param srcIp the vm ip address
1032      * @param attachedMac the vm mac address
1033      * @param priority  the priority
1034      * @param write is write or delete
1035      */
1036     private void egressAclAllowTrafficFromVmIpV6MacPair(Long dpidLong, long localPort,
1037                                                         String attachedMac, String srcIp,
1038                                                         Integer priority, boolean write) {
1039         MatchBuilder matchBuilder = new MatchBuilder();
1040         MatchUtils.createSrcL3Ipv6MatchWithMac(matchBuilder, new Ipv6Prefix(srcIp),new MacAddress(attachedMac));
1041         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
1042         LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
1043         String flowName = "Egress_Allow_VM_IPv6_MAC" + "_" + localPort + attachedMac + "_Permit_";
1044         FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
1045         addPipelineInstruction(flowBuilder, null, false);
1046         NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1047         syncFlow(flowBuilder ,nodeBuilder, write);
1048     }
1049
1050     private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
1051         if (securityServicesManager.isConntrackEnabled()) {
1052             MatchUtils.addCtState(matchBuilder, state, mask );
1053         }
1054
1055     }
1056
1057     private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
1058         InstructionBuilder instructionBuilder = null;
1059         if (securityServicesManager.isConntrackEnabled()) {
1060             Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
1061             instructionBuilder = InstructionUtils
1062                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
1063         }
1064         return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
1065     }
1066     private FlowBuilder addInstructionWithLearnConntrackCommit(NeutronSecurityRule portSecurityRule, FlowBuilder flowBuilder, String icmpType, String icmpCode) {
1067         InstructionBuilder instructionBuilder = null;
1068         short learnTableId=getTable(Service.ACL_LEARN_SERVICE);
1069         short resubmitId=getTable(Service.LOAD_BALANCER);
1070         if (securityServicesManager.isConntrackEnabled()) {
1071             Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
1072             instructionBuilder = InstructionUtils
1073                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
1074             return addPipelineInstruction(flowBuilder,instructionBuilder, false);
1075         }
1076         if (portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.TCP) || portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.TCP_PROTOCOL)) {
1077             return EgressAclLearnServiceUtil.programEgressAclLearnRuleForTcp(flowBuilder,instructionBuilder,learnTableId,resubmitId);
1078         } else if (portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.UDP)  || portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.UDP_PROTOCOL)) {
1079             return EgressAclLearnServiceUtil.programEgressAclLearnRuleForUdp(flowBuilder,instructionBuilder,learnTableId,resubmitId);
1080         } else if (portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.ICMP)  || portSecurityRule.getSecurityRuleProtocol().equalsIgnoreCase(MatchUtils.ICMP_PROTOCOL)) {
1081             return EgressAclLearnServiceUtil.programEgressAclLearnRuleForIcmp(flowBuilder,instructionBuilder, icmpType, icmpCode,learnTableId,resubmitId);
1082         }
1083         return flowBuilder;
1084     }
1085
1086     private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
1087         InstructionBuilder instructionBuilder = null;
1088         if (securityServicesManager.isConntrackEnabled()) {
1089             Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
1090
1091             instructionBuilder = InstructionUtils
1092                     .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
1093             List<Instruction> instructionsList = Lists.newArrayList();
1094             instructionsList.add(instructionBuilder.build());
1095             InstructionsBuilder isb = new InstructionsBuilder();
1096             isb.setInstruction(instructionsList);
1097             flowBuilder.setInstructions(isb.build());
1098         }
1099         return flowBuilder;
1100     }
1101
1102     private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder ,
1103                                                 InstructionBuilder instructionBuilder,boolean isDrop) {
1104         InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
1105         List<Instruction> instructionsList = Lists.newArrayList();
1106         instructionsList.add(pipeLineIndstructionBuilder.build());
1107         if (null != instructionBuilder) {
1108             instructionsList.add(instructionBuilder.build());
1109         }
1110         InstructionsBuilder isb = new InstructionsBuilder();
1111         isb.setInstruction(instructionsList);
1112         flowBuilder.setInstructions(isb.build());
1113         return flowBuilder;
1114     }
1115
1116     private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
1117         InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
1118         if (drop) {
1119             InstructionUtils.createDropInstructions(ib);
1120         }
1121         ib.setOrder(0);
1122         List<Instruction> instructionsList = Lists.newArrayList();
1123         ib.setKey(new InstructionKey(0));
1124         instructionsList.add(ib.build());
1125         return ib;
1126     }
1127     /**
1128      * Add or remove flow to the node.
1129      * @param flowBuilder the flow builder
1130      * @param nodeBuilder the node builder
1131      * @param write whether it is a write
1132      */
1133     private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
1134                           boolean write) {
1135         if (write) {
1136             writeFlow(flowBuilder, nodeBuilder);
1137         } else {
1138             removeFlow(flowBuilder, nodeBuilder);
1139         }
1140     }
1141
1142     private List<NeutronSecurityRule> getSecurityRulesforGroup(NeutronSecurityGroup securityGroup) {
1143         List<NeutronSecurityRule> securityRules = new ArrayList<>();
1144         List<NeutronSecurityRule> rules = neutronSecurityRule.getAllNeutronSecurityRules();
1145         for (NeutronSecurityRule securityRule : rules) {
1146             if (securityGroup.getID().equals(securityRule.getSecurityRuleGroupID())) {
1147                 securityRules.add(securityRule);
1148             }
1149         }
1150         return securityRules;
1151     }
1152
1153     @Override
1154     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1155         super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
1156         securityServicesManager =
1157                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1158         securityGroupCacheManger =
1159                 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
1160         neutronSecurityRule = (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, this);
1161     }
1162
1163     @Override
1164     public void setDependencies(Object impl) {}
1165 }