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