Merge "Added Security Rule for Custom ICMP"
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / services / EgressAclService.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 java.math.BigInteger;
12 import java.util.List;
13
14 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
15 import org.opendaylight.neutron.spi.NeutronSecurityRule;
16 import org.opendaylight.neutron.spi.Neutron_IPs;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
18 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
19 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
20 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
21 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
22 import org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.Service;
23 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
24 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
25 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
38 import org.osgi.framework.BundleContext;
39 import org.osgi.framework.ServiceReference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import com.google.common.collect.Lists;
44
45 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
46
47     private static final Logger LOG = LoggerFactory.getLogger(EgressAclService.class);
48     private volatile SecurityServicesManager securityServicesManager;
49     private static final int DHCP_SOURCE_PORT = 67;
50     private static final int DHCP_DESTINATION_PORT = 68;
51     private static final String HOST_MASK = "/32";
52
53     public EgressAclService() {
54         super(Service.EGRESS_ACL);
55     }
56
57     public EgressAclService(Service service) {
58         super(service);
59     }
60
61     @Override
62     public void programPortSecurityAcl(Long dpid, String segmentationId, String attachedMac, long localPort,
63                                        NeutronSecurityGroup securityGroup,
64                                        List<Neutron_IPs> srcAddressList, boolean write) {
65
66         LOG.trace("programPortSecurityAcl: neutronSecurityGroup: {} ", securityGroup);
67         if (securityGroup == null || securityGroup.getSecurityRules() == null) {
68             return;
69         }
70
71         List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
72         /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
73         for (NeutronSecurityRule portSecurityRule : portSecurityList) {
74             /**
75              * Neutron Port Security Acl "egress" and "IPv4"
76              * Check that the base conditions for flow based Port Security are true:
77              * Port Security Rule Direction ("egress") and Protocol ("IPv4")
78              * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
79              * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
80              *
81              */
82             if (portSecurityRule.getSecurityRuleEthertype().equals("IPv4")
83                     && portSecurityRule.getSecurityRuleDirection().equals("egress")) {
84                 LOG.debug("programPortSecurityAcl: Acl Rule matching IPv4 and ingress is: {} ", portSecurityRule);
85                 if (null == portSecurityRule.getSecurityRuleProtocol()) {
86                     /* TODO Rework on the priority values */
87                     egressAclIPv4(dpid, segmentationId, attachedMac,
88                                   write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
89                 } else if (null != portSecurityRule.getSecurityRemoteGroupID()) {
90                   //Remote Security group is selected
91                     List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
92                             .getVmListForSecurityGroup(srcAddressList,portSecurityRule.getSecurityRemoteGroupID());
93                     if (null != remoteSrcAddressList) {
94                         for (Neutron_IPs vmIp :remoteSrcAddressList ) {
95                             switch (portSecurityRule.getSecurityRuleProtocol()) {
96                             case MatchUtils.TCP:
97                                 egressAclTcp(dpid, segmentationId, attachedMac,
98                                              portSecurityRule,vmIp.getIpAddress(), write,
99                                              Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
100                                 break;
101                             case MatchUtils.UDP:
102                                 egressAclUdp(dpid, segmentationId, attachedMac,
103                                              portSecurityRule,vmIp.getIpAddress(), write,
104                                              Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
105                                 break;
106                             case MatchUtils.ICMP:
107                                 egressAclIcmp(dpid, segmentationId, attachedMac,
108                                                portSecurityRule, vmIp.getIpAddress(),write,
109                                                Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
110                                 break;
111                             default:
112                                 LOG.error("programPortSecurityAcl: Protocol not supported", portSecurityRule);
113                                 break;
114                             }
115                         }
116                     }
117                 } else {
118                     //CIDR is selected
119                     switch (portSecurityRule.getSecurityRuleProtocol()) {
120                     case MatchUtils.TCP:
121                         egressAclTcp(dpid, segmentationId, attachedMac,
122                                      portSecurityRule, null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
123                         break;
124                     case MatchUtils.UDP:
125                         egressAclUdp(dpid, segmentationId, attachedMac,
126                                      portSecurityRule, null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
127                         break;
128                     case MatchUtils.ICMP:
129                         egressAclIcmp(dpid, segmentationId, attachedMac,
130                                        portSecurityRule, null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
131                         break;
132                     default:
133                         LOG.error("programPortSecurityAcl: Protocol not supported", portSecurityRule);
134                     }
135                 }
136             }
137             /*
138              * Code is refactored to handle all the protocols. More
139              * protocols  will be added incrementrally
140              * TODO Connection tracking will be used to track active TCP connections This code
141              * may be reused then.
142              */
143             /* if (portSecurityRule.getSecurityRuleEthertype().equalsIgnoreCase("IPv4") &&
144                 portSecurityRule.getSecurityRuleDirection().equalsIgnoreCase("egress")) {
145                 LOG.debug("Egress IPV4 ACL  Port Security Rule: {} ", portSecurityRule);
146                 // ToDo: Implement Port Range
147
148              *//**
149              * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (True)
150              *//*
151                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
152                     !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
153                     !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
154                     (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
155                      !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
156                              .equalsIgnoreCase("0.0.0.0/0"))) {
157                     LOG.debug(
158                             "Rule #1 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
159                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
160                             portSecurityRule.getSecurityRulePortMax(),
161                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
162                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
163                                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
164                                             true);
165                     egressACLTcpPortWithPrefix(dpid, segmentationId,
166                                                attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
167                                                portSecurityRule.getSecurityRuleRemoteIpPrefix(),
168                                                Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
169                     continue;
170                 }
171               *//**
172               * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (True)
173               *//*
174                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
175                     !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
176                     String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
177                     (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
178                      !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
179                              .equalsIgnoreCase("0.0.0.0/0"))) {
180                     LOG.debug(
181                             "Rule #2 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
182                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
183                             portSecurityRule.getSecurityRulePortMax(),
184                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
185                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
186                                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
187                                             true);
188                     egressACLTcpPortWithPrefix(dpid, segmentationId,
189                                                attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
190                                                portSecurityRule.getSecurityRuleRemoteIpPrefix(),
191                                                Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
192                     continue;
193                 }
194                *//**
195                * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
196                *//*
197                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
198                     String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
199                     String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
200                     !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
201                     LOG.debug(
202                             "Rule #3 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
203                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
204                             portSecurityRule.getSecurityRulePortMax(),
205                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
206                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PREFIX_MATCH_PRIORITY_DROP,
207                                             true);
208                     egressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
209                                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PREFIX_MATCH_PRIORITY);
210                     continue;
211                 }
212                 *//**
213                 * TCP Proto (False), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
214                 *//*
215                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("null") &&
216                     String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
217                     String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
218                     (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
219                      !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
220                              .equalsIgnoreCase("0.0.0.0/0"))) {
221                     LOG.debug(
222                             "Rule #4 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
223                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
224                             portSecurityRule.getSecurityRulePortMax(),
225                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
226                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PREFIX_MATCH_PRIORITY_DROP, true);
227                     egressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
228                                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PREFIX_MATCH_PRIORITY);
229                     continue;
230                 }
231                  *//**
232                  * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (False)
233                  *//*
234                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
235                     !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
236                     !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
237                     String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
238                     LOG.debug(
239                             "Rule #5 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
240                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
241                             portSecurityRule.getSecurityRulePortMax(),
242                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
243                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PORT_MATCH_PRIORITY_DROP,
244                                             true);
245                     egressACLTcpSyn(dpid, segmentationId,
246                                     attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
247                                     Constants.PROTO_PORT_MATCH_PRIORITY);
248                     continue;
249                 }
250                   *//**
251                   * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (False)
252                   *//*
253                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
254                     !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
255                     String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
256                     String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
257                     LOG.debug(
258                             "Rule #6 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
259                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
260                             portSecurityRule.getSecurityRulePortMax(),
261                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
262                     egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
263                                             Constants.PROTO_PORT_MATCH_PRIORITY_DROP, true);
264                     egressACLTcpSyn(dpid, segmentationId, attachedMac, true,
265                                     portSecurityRule.getSecurityRulePortMin(), Constants.PROTO_PORT_MATCH_PRIORITY);
266                     continue;
267                 }
268                    *//**
269                    * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (False or 0.0.0.0/0)
270                    *//*
271                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
272                     String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
273                     String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
274                     ((String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) ||
275                      String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
276                              .equalsIgnoreCase("0.0.0.0/0"))) {
277                     LOG.debug(
278                             "Rule #7 egress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
279                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
280                             portSecurityRule.getSecurityRulePortMax(),
281                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
282                     // No need to drop until UDP/ICMP are implemented
283                     // egressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, PROTO_MATCH_PRIORITY_DROP, true);
284                     egressAllowProto(dpid, segmentationId, attachedMac, true,
285                                      portSecurityRule.getSecurityRuleProtocol(), Constants.PROTO_MATCH_PRIORITY);
286                     continue;
287                 }
288                 LOG.debug("ACL Match combination not found for rule: {}", portSecurityRule);
289             }*/
290         }
291     }
292
293     @Override
294     public void programFixedSecurityAcl(Long dpid, String segmentationId, String attachedMac,
295                                         long localPort, List<Neutron_IPs> srcAddressList,
296                                         boolean isLastPortinBridge, boolean isComputePort ,boolean write) {
297         // If it is the only port in the bridge add the rule to allow any DHCP client traffic
298         if (isLastPortinBridge) {
299             egressAclDhcpAllowClientTrafficFromVm(dpid, write, Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
300         }
301         if (isComputePort) {
302             // add rule to drop the DHCP server traffic originating from the vm.
303             egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
304                                                  Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
305             //Adds rule to check legitimate ip/mac pair for each packet from the vm
306             for (Neutron_IPs srcAddress : srcAddressList) {
307                 String addressWithPrefix = srcAddress.getIpAddress() + HOST_MASK;
308                 egressAclAllowTrafficFromVmIpMacPair(dpid, localPort, attachedMac, addressWithPrefix,
309                                                      Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
310             }
311         }
312     }
313
314     /**
315      * Allows IPv4 packet egress from the src mac address.
316      * @param dpidLong the dpid
317      * @param segmentationId the segementation id
318      * @param srcMac the src mac address
319      * @param write add or remove
320      * @param protoPortMatchPriority the protocol match priority.
321      */
322     private void egressAclIPv4(Long dpidLong, String segmentationId, String srcMac,
323                                boolean write, Integer protoPortMatchPriority ) {
324         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
325         MatchBuilder matchBuilder = new MatchBuilder();
326         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
327         String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
328         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
329         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
330     }
331
332     /**
333      * Creates a egress match with src macaddress. If dest address is specified
334      * destination specific match will be created. Otherwise a match with a
335      * CIDR will be created.
336      * @param dpidLong the dpid
337      * @param segmentationId the segmentation id
338      * @param srcMac the source mac address.
339      * @param portSecurityRule the security rule in the SG
340      * @param dstAddress the destination IP address
341      * @param write add or delete
342      * @param protoPortMatchPriority the protocol match priroty
343      */
344     private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
345                               NeutronSecurityRule portSecurityRule, String dstAddress,
346                               boolean write, Integer protoPortMatchPriority) {
347         MatchBuilder matchBuilder = new MatchBuilder();
348         String flowId = "Egress_Custom_Tcp" + segmentationId + "_" + srcMac + "_";
349         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
350         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
351             flowId = flowId + portSecurityRule.getSecurityRulePortMin();
352             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
353                                                      portSecurityRule.getSecurityRulePortMin());
354         } else {
355             /*TODO TCP PortRange Match*/
356
357         }
358
359         if (null != dstAddress) {
360             flowId = flowId + dstAddress;
361             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
362                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
363
364         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
365             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
366             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
367                                                         new Ipv4Prefix(portSecurityRule
368                                                                        .getSecurityRuleRemoteIpPrefix()));
369         }
370         flowId = flowId + "_Permit_";
371         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
372         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
373         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
374
375     }
376
377     /**
378      * Creates a egress match with src macaddress. If dest address is specified
379      * destination specific match will be created. Otherwise a match with a
380      * CIDR will be created.
381      * @param dpidLong the dpid
382      * @param segmentationId the segmentation id
383      * @param srcMac the source mac address.
384      * @param portSecurityRule the security rule in the SG
385      * @param dstAddress the source IP address
386      * @param write add or delete
387      * @param protoPortMatchPriority the protocol match priority
388      */
389     private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
390                                NeutronSecurityRule portSecurityRule, String dstAddress,
391                                boolean write, Integer protoPortMatchPriority) {
392         MatchBuilder matchBuilder = new MatchBuilder();
393         String flowId = "Egress_ICMP" + segmentationId + "_" + srcMac + "_";
394         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
395         matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
396                                                     portSecurityRule.getSecurityRulePortMin().shortValue(),
397                                                     portSecurityRule.getSecurityRulePortMax().shortValue());
398         if (null != dstAddress) {
399             flowId = flowId + dstAddress;
400             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
401                     MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
402         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
403             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
404             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
405                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
406         }
407         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
408         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
409         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
410
411     }
412
413     /**
414      * Creates a egress match with src macaddress. If dest address is specified
415      * destination specific match will be created. Otherwise a match with a
416      * CIDR will be created.
417      * @param dpidLong the dpid
418      * @param segmentationId the segmentation id
419      * @param srcMac the source mac address.
420      * @param portSecurityRule the security rule in the SG
421      * @param dstAddress the source IP address
422      * @param write add or delete
423      * @param protoPortMatchPriority the protocol match priroty
424      */
425     private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
426                               NeutronSecurityRule portSecurityRule, String dstAddress,
427                               boolean write, Integer protoPortMatchPriority) {
428
429         MatchBuilder matchBuilder = new MatchBuilder();
430         String flowId = "Eress_UDP" + segmentationId + "_" + srcMac + "_";
431         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
432         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
433             flowId = flowId + portSecurityRule.getSecurityRulePortMin();
434             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
435                                                      portSecurityRule.getSecurityRulePortMin());
436         } else {
437             /*TODO UDP PortRange Match*/
438
439         }
440
441         if (null != dstAddress) {
442             flowId = flowId + dstAddress;
443             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
444                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
445
446         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
447             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
448             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
449                                                         new Ipv4Prefix(portSecurityRule
450                                                                        .getSecurityRuleRemoteIpPrefix()));
451         }
452         flowId = flowId + "_Permit_";
453         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
454         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
455         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
456
457     }
458     public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
459                                         int priority, boolean write) {
460
461         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
462         MatchBuilder matchBuilder = new MatchBuilder();
463         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
464         FlowBuilder flowBuilder = new FlowBuilder();
465
466         flowBuilder.setMatch(MatchUtils.createSmacTcpPortWithFlagMatch(matchBuilder,
467                                                                        attachedMac, Constants.TCP_SYN, segmentationId).build());
468         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
469
470         String flowId = "TCP_Syn_Egress_Default_Drop_" + segmentationId + "_" + attachedMac;
471         flowBuilder.setId(new FlowId(flowId));
472         FlowKey key = new FlowKey(new FlowId(flowId));
473         flowBuilder.setStrict(false);
474         flowBuilder.setPriority(priority);
475         flowBuilder.setBarrier(true);
476         flowBuilder.setTableId(this.getTable());
477         flowBuilder.setKey(key);
478         flowBuilder.setFlowName(flowId);
479         flowBuilder.setHardTimeout(0);
480         flowBuilder.setIdleTimeout(0);
481
482         if (write) {
483             // Instantiate the Builders for the OF Actions and Instructions
484             InstructionBuilder ib = new InstructionBuilder();
485             InstructionsBuilder isb = new InstructionsBuilder();
486             List<Instruction> instructions = Lists.newArrayList();
487
488             InstructionUtils.createDropInstructions(ib);
489             ib.setOrder(0);
490             ib.setKey(new InstructionKey(0));
491             instructions.add(ib.build());
492             // Add InstructionBuilder to the Instruction(s)Builder List
493             isb.setInstruction(instructions);
494
495             LOG.debug("Instructions contain: {}", ib.getInstruction());
496             // Add InstructionsBuilder to FlowBuilder
497             flowBuilder.setInstructions(isb.build());
498             writeFlow(flowBuilder, nodeBuilder);
499         } else {
500             removeFlow(flowBuilder, nodeBuilder);
501         }
502     }
503
504     public void egressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac, boolean write,
505                                            Integer securityRulePortMin, String securityRuleIpPrefix, Integer protoPortPrefixMatchPriority) {
506
507         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
508         PortNumber tcpPort = new PortNumber(securityRulePortMin);
509         MatchBuilder matchBuilder = new MatchBuilder();
510         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
511         FlowBuilder flowBuilder = new FlowBuilder();
512         Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
513
514         flowBuilder.setMatch(MatchUtils
515                              .createSmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
516                                                                  tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix).build());
517
518         LOG.debug(" MatchBuilder contains:  {}", flowBuilder.getMatch());
519         String flowId = "UcastEgress_" + segmentationId + "_" + attachedMac +
520                 securityRulePortMin + securityRuleIpPrefix;
521         // Add Flow Attributes
522         flowBuilder.setId(new FlowId(flowId));
523         FlowKey key = new FlowKey(new FlowId(flowId));
524         flowBuilder.setStrict(false);
525         flowBuilder.setPriority(protoPortPrefixMatchPriority);
526         flowBuilder.setBarrier(true);
527         flowBuilder.setTableId(this.getTable());
528         flowBuilder.setKey(key);
529         flowBuilder.setFlowName(flowId);
530         flowBuilder.setHardTimeout(0);
531         flowBuilder.setIdleTimeout(0);
532
533         if (write) {
534             // Instantiate the Builders for the OF Actions and Instructions
535             InstructionsBuilder isb = new InstructionsBuilder();
536             List<Instruction> instructionsList = Lists.newArrayList();
537
538             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
539             ib.setOrder(0);
540             ib.setKey(new InstructionKey(0));
541             instructionsList.add(ib.build());
542             isb.setInstruction(instructionsList);
543
544             LOG.debug("Instructions contain: {}", ib.getInstruction());
545             // Add InstructionsBuilder to FlowBuilder
546             flowBuilder.setInstructions(isb.build());
547             writeFlow(flowBuilder, nodeBuilder);
548         } else {
549             removeFlow(flowBuilder, nodeBuilder);
550         }
551     }
552
553
554
555     public void egressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
556                                  String securityRuleProtcol, Integer protoMatchPriority) {
557
558         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
559         MatchBuilder matchBuilder = new MatchBuilder();
560         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
561         FlowBuilder flowBuilder = new FlowBuilder();
562
563         flowBuilder.setMatch(MatchUtils
564                              .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null).build());
565         flowBuilder.setMatch(MatchUtils
566                              .createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
567
568         LOG.debug("MatchBuilder contains:  {}", flowBuilder.getMatch());
569         String flowId = "EgressAllProto_" + segmentationId + "_" +
570                 attachedMac + "_AllowEgressTCPSyn_" + securityRuleProtcol;
571         // Add Flow Attributes
572         flowBuilder.setId(new FlowId(flowId));
573         FlowKey key = new FlowKey(new FlowId(flowId));
574         flowBuilder.setStrict(false);
575         flowBuilder.setPriority(protoMatchPriority);
576         flowBuilder.setBarrier(true);
577         flowBuilder.setTableId(this.getTable());
578         flowBuilder.setKey(key);
579         flowBuilder.setFlowName(flowId);
580         flowBuilder.setHardTimeout(0);
581         flowBuilder.setIdleTimeout(0);
582
583         if (write) {
584             // Instantiate the Builders for the OF Actions and Instructions
585             InstructionsBuilder isb = new InstructionsBuilder();
586             List<Instruction> instructionsList = Lists.newArrayList();
587
588             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
589             ib.setOrder(0);
590             ib.setKey(new InstructionKey(0));
591             instructionsList.add(ib.build());
592             isb.setInstruction(instructionsList);
593
594             LOG.debug("Instructions contain: {}", ib.getInstruction());
595             // Add InstructionsBuilder to FlowBuilder
596             flowBuilder.setInstructions(isb.build());
597             writeFlow(flowBuilder, nodeBuilder);
598         } else {
599             removeFlow(flowBuilder, nodeBuilder);
600         }
601     }
602
603     public void egressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
604                                         boolean write, String securityRuleIpPrefix, Integer protoPortMatchPriority) {
605
606         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
607         MatchBuilder matchBuilder = new MatchBuilder();
608         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
609         FlowBuilder flowBuilder = new FlowBuilder();
610
611         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId))
612                              .build());
613         if (securityRuleIpPrefix != null) {
614             Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
615             flowBuilder.setMatch(MatchUtils
616                                  .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix)
617                                  .build());
618         } else {
619             flowBuilder.setMatch(MatchUtils
620                                  .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null)
621                                  .build());
622         }
623         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
624         String flowId = "Egress_Proto_ACL" + segmentationId + "_" +
625                 attachedMac + "_Permit_" + securityRuleIpPrefix;
626         // Add Flow Attributes
627         flowBuilder.setId(new FlowId(flowId));
628         FlowKey key = new FlowKey(new FlowId(flowId));
629         flowBuilder.setStrict(false);
630         flowBuilder.setPriority(protoPortMatchPriority);
631         flowBuilder.setBarrier(true);
632         flowBuilder.setTableId(this.getTable());
633         flowBuilder.setKey(key);
634         flowBuilder.setFlowName(flowId);
635         flowBuilder.setHardTimeout(0);
636         flowBuilder.setIdleTimeout(0);
637
638         if (write) {
639             // Instantiate the Builders for the OF Actions and Instructions
640             InstructionsBuilder isb = new InstructionsBuilder();
641             List<Instruction> instructionsList = Lists.newArrayList();
642
643             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
644             ib.setOrder(0);
645             ib.setKey(new InstructionKey(0));
646             instructionsList.add(ib.build());
647             isb.setInstruction(instructionsList);
648
649             LOG.debug("Instructions contain: {}", ib.getInstruction());
650             // Add InstructionsBuilder to FlowBuilder
651             flowBuilder.setInstructions(isb.build());
652             writeFlow(flowBuilder, nodeBuilder);
653         } else {
654             removeFlow(flowBuilder, nodeBuilder);
655         }
656     }
657
658
659     public void egressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
660                                 Integer securityRulePortMin, Integer protoPortMatchPriority) {
661
662         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
663         PortNumber tcpPort = new PortNumber(securityRulePortMin);
664         MatchBuilder matchBuilder = new MatchBuilder();
665         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
666         FlowBuilder flowBuilder = new FlowBuilder();
667
668         flowBuilder.setMatch(MatchUtils.createSmacTcpSyn(matchBuilder, attachedMac, tcpPort,
669                                                          Constants.TCP_SYN, segmentationId).build());
670
671         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
672         String flowId = "Ucast_this.getTable()" + segmentationId + "_" + attachedMac + securityRulePortMin;
673         // Add Flow Attributes
674         flowBuilder.setId(new FlowId(flowId));
675         FlowKey key = new FlowKey(new FlowId(flowId));
676         flowBuilder.setStrict(false);
677         flowBuilder.setPriority(protoPortMatchPriority);
678         flowBuilder.setBarrier(true);
679         flowBuilder.setTableId(this.getTable());
680         flowBuilder.setKey(key);
681         flowBuilder.setFlowName(flowId);
682         flowBuilder.setHardTimeout(0);
683         flowBuilder.setIdleTimeout(0);
684
685         if (write) {
686             // Instantiate the Builders for the OF Actions and Instructions
687             InstructionsBuilder isb = new InstructionsBuilder();
688             List<Instruction> instructionsList = Lists.newArrayList();
689
690             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
691             ib.setOrder(0);
692             ib.setKey(new InstructionKey(0));
693             instructionsList.add(ib.build());
694             isb.setInstruction(instructionsList);
695
696             LOG.debug("Instructions contain: {}", ib.getInstruction());
697             // Add InstructionsBuilder to FlowBuilder
698             flowBuilder.setInstructions(isb.build());
699             writeFlow(flowBuilder, nodeBuilder);
700         } else {
701             removeFlow(flowBuilder, nodeBuilder);
702         }
703     }
704
705     /**
706      * Adds flow to allow any DHCP client traffic.
707      *
708      * @param dpidLong the dpid
709      * @param write whether to write or delete the flow
710      * @param protoPortMatchPriority the priority
711      */
712     private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
713                                                        boolean write, Integer protoPortMatchPriority) {
714
715         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
716         MatchBuilder matchBuilder = new MatchBuilder();
717         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
718
719         MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT).build();
720         LOG.debug("egressAclDHCPAllowClientTrafficFromVm: MatchBuilder contains: {}", matchBuilder);
721         String flowId = "Egress_DHCP_Client"  + "_Permit_";
722         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
723     }
724
725     /**
726      * Adds rule to prevent DHCP spoofing by the vm attached to the port.
727      *
728      * @param dpidLong the dpid
729      * @param localPort the local port
730      * @param write is write or delete
731      * @param protoPortMatchPriority  the priority
732      */
733     private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
734                                                       boolean write, Integer protoPortMatchPriority) {
735
736         MatchBuilder matchBuilder = new MatchBuilder();
737         //FlowBuilder flowBuilder = new FlowBuilder();
738         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
739         MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT).build();
740         LOG.debug("egressAclDHCPDropServerTrafficfromVM: MatchBuilder contains: {}", matchBuilder);
741         String flowId = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
742         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
743         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
744         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, true);
745
746     }
747
748     /**
749      * Adds rule to check legitimate ip/mac pair for each packet from the vm.
750      *
751      * @param dpidLong the dpid
752      * @param localPort the local port
753      * @param srcIp the vm ip address
754      * @param attachedMac the vm mac address
755      * @param protoPortMatchPriority  the priority
756      * @param write is write or delete
757      */
758     private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
759                                                       String attachedMac, String srcIp,
760                                                       Integer protoPortMatchPriority, boolean write) {
761         MatchBuilder matchBuilder = new MatchBuilder();
762         MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
763         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
764         LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
765         String flowId = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
766         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
767         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
768         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
769
770     }
771
772     /**
773      * Add or remove flow to the node.
774      *
775      * @param flowId the the flow id
776      * @param nodeBuilder the node builder
777      * @param matchBuilder the matchbuilder
778      * @param protoPortMatchPriority the protocol priority
779      * @param write whether it is a write
780      * @param drop whether it is a drop or forward
781      */
782     private void syncFlow(String flowId, NodeBuilder nodeBuilder,
783                           MatchBuilder matchBuilder,Integer protoPortMatchPriority,
784                           boolean write,boolean drop) {
785         FlowBuilder flowBuilder = new FlowBuilder();
786         flowBuilder.setMatch(matchBuilder.build());
787         flowBuilder.setId(new FlowId(flowId));
788         FlowKey key = new FlowKey(new FlowId(flowId));
789         flowBuilder.setStrict(false);
790         flowBuilder.setPriority(protoPortMatchPriority);
791         flowBuilder.setBarrier(true);
792         flowBuilder.setTableId(this.getTable());
793         flowBuilder.setKey(key);
794         flowBuilder.setFlowName(flowId);
795         flowBuilder.setHardTimeout(0);
796         flowBuilder.setIdleTimeout(0);
797
798         if (write) {
799             // Instantiate the Builders for the OF Actions and Instructions
800
801             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
802             if (drop) {
803                 InstructionUtils.createDropInstructions(ib);
804             }
805             ib.setOrder(0);
806             ib.setKey(new InstructionKey(0));
807             InstructionsBuilder isb = new InstructionsBuilder();
808             List<Instruction> instructionsList = Lists.newArrayList();
809             instructionsList.add(ib.build());
810             isb.setInstruction(instructionsList);
811             flowBuilder.setInstructions(isb.build());
812             writeFlow(flowBuilder, nodeBuilder);
813         } else {
814             removeFlow(flowBuilder, nodeBuilder);
815         }
816
817     }
818
819
820
821     @Override
822     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
823         super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
824         securityServicesManager =
825                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
826     }
827
828     @Override
829     public void setDependencies(Object impl) {}
830 }