Merge "Fix checkstyle issues in netvirtsfc"
[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 ("IPv4".equals(portSecurityRule.getSecurityRuleEthertype())
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                     + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
395                     + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
396         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
397         matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
398                                                     portSecurityRule.getSecurityRulePortMin().shortValue(),
399                                                     portSecurityRule.getSecurityRulePortMax().shortValue());
400         if (null != dstAddress) {
401             flowId = flowId + dstAddress;
402             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
403                     MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
404         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
405             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
406             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
407                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
408         }
409         flowId = flowId + "_Permit";
410         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
411         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
412         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
413
414     }
415
416     /**
417      * Creates a egress match with src macaddress. If dest address is specified
418      * destination specific match will be created. Otherwise a match with a
419      * CIDR will be created.
420      * @param dpidLong the dpid
421      * @param segmentationId the segmentation id
422      * @param srcMac the source mac address.
423      * @param portSecurityRule the security rule in the SG
424      * @param dstAddress the source IP address
425      * @param write add or delete
426      * @param protoPortMatchPriority the protocol match priroty
427      */
428     private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
429                               NeutronSecurityRule portSecurityRule, String dstAddress,
430                               boolean write, Integer protoPortMatchPriority) {
431
432         MatchBuilder matchBuilder = new MatchBuilder();
433         String flowId = "Eress_UDP" + segmentationId + "_" + srcMac + "_";
434         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
435         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
436             flowId = flowId + portSecurityRule.getSecurityRulePortMin();
437             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
438                                                      portSecurityRule.getSecurityRulePortMin());
439         } else {
440             /*TODO UDP PortRange Match*/
441
442         }
443
444         if (null != dstAddress) {
445             flowId = flowId + dstAddress;
446             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
447                                                         MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
448
449         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
450             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
451             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
452                                                         new Ipv4Prefix(portSecurityRule
453                                                                        .getSecurityRuleRemoteIpPrefix()));
454         }
455         flowId = flowId + "_Permit_";
456         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
457         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
458         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
459
460     }
461     public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
462                                         int priority, boolean write) {
463
464         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
465         MatchBuilder matchBuilder = new MatchBuilder();
466         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
467         FlowBuilder flowBuilder = new FlowBuilder();
468
469         flowBuilder.setMatch(MatchUtils.createSmacTcpPortWithFlagMatch(matchBuilder,
470                                                                        attachedMac, Constants.TCP_SYN, segmentationId).build());
471         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
472
473         String flowId = "TCP_Syn_Egress_Default_Drop_" + segmentationId + "_" + attachedMac;
474         flowBuilder.setId(new FlowId(flowId));
475         FlowKey key = new FlowKey(new FlowId(flowId));
476         flowBuilder.setStrict(false);
477         flowBuilder.setPriority(priority);
478         flowBuilder.setBarrier(true);
479         flowBuilder.setTableId(this.getTable());
480         flowBuilder.setKey(key);
481         flowBuilder.setFlowName(flowId);
482         flowBuilder.setHardTimeout(0);
483         flowBuilder.setIdleTimeout(0);
484
485         if (write) {
486             // Instantiate the Builders for the OF Actions and Instructions
487             InstructionBuilder ib = new InstructionBuilder();
488             InstructionsBuilder isb = new InstructionsBuilder();
489             List<Instruction> instructions = Lists.newArrayList();
490
491             InstructionUtils.createDropInstructions(ib);
492             ib.setOrder(0);
493             ib.setKey(new InstructionKey(0));
494             instructions.add(ib.build());
495             // Add InstructionBuilder to the Instruction(s)Builder List
496             isb.setInstruction(instructions);
497
498             LOG.debug("Instructions contain: {}", ib.getInstruction());
499             // Add InstructionsBuilder to FlowBuilder
500             flowBuilder.setInstructions(isb.build());
501             writeFlow(flowBuilder, nodeBuilder);
502         } else {
503             removeFlow(flowBuilder, nodeBuilder);
504         }
505     }
506
507     public void egressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac, boolean write,
508                                            Integer securityRulePortMin, String securityRuleIpPrefix, Integer protoPortPrefixMatchPriority) {
509
510         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
511         PortNumber tcpPort = new PortNumber(securityRulePortMin);
512         MatchBuilder matchBuilder = new MatchBuilder();
513         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
514         FlowBuilder flowBuilder = new FlowBuilder();
515         Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
516
517         flowBuilder.setMatch(MatchUtils
518                              .createSmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
519                                                                  tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix).build());
520
521         LOG.debug(" MatchBuilder contains:  {}", flowBuilder.getMatch());
522         String flowId = "UcastEgress_" + segmentationId + "_" + attachedMac +
523                 securityRulePortMin + securityRuleIpPrefix;
524         // Add Flow Attributes
525         flowBuilder.setId(new FlowId(flowId));
526         FlowKey key = new FlowKey(new FlowId(flowId));
527         flowBuilder.setStrict(false);
528         flowBuilder.setPriority(protoPortPrefixMatchPriority);
529         flowBuilder.setBarrier(true);
530         flowBuilder.setTableId(this.getTable());
531         flowBuilder.setKey(key);
532         flowBuilder.setFlowName(flowId);
533         flowBuilder.setHardTimeout(0);
534         flowBuilder.setIdleTimeout(0);
535
536         if (write) {
537             // Instantiate the Builders for the OF Actions and Instructions
538             InstructionsBuilder isb = new InstructionsBuilder();
539             List<Instruction> instructionsList = Lists.newArrayList();
540
541             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
542             ib.setOrder(0);
543             ib.setKey(new InstructionKey(0));
544             instructionsList.add(ib.build());
545             isb.setInstruction(instructionsList);
546
547             LOG.debug("Instructions contain: {}", ib.getInstruction());
548             // Add InstructionsBuilder to FlowBuilder
549             flowBuilder.setInstructions(isb.build());
550             writeFlow(flowBuilder, nodeBuilder);
551         } else {
552             removeFlow(flowBuilder, nodeBuilder);
553         }
554     }
555
556
557
558     public void egressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
559                                  String securityRuleProtcol, Integer protoMatchPriority) {
560
561         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
562         MatchBuilder matchBuilder = new MatchBuilder();
563         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
564         FlowBuilder flowBuilder = new FlowBuilder();
565
566         flowBuilder.setMatch(MatchUtils
567                              .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null).build());
568         flowBuilder.setMatch(MatchUtils
569                              .createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
570
571         LOG.debug("MatchBuilder contains:  {}", flowBuilder.getMatch());
572         String flowId = "EgressAllProto_" + segmentationId + "_" +
573                 attachedMac + "_AllowEgressTCPSyn_" + securityRuleProtcol;
574         // Add Flow Attributes
575         flowBuilder.setId(new FlowId(flowId));
576         FlowKey key = new FlowKey(new FlowId(flowId));
577         flowBuilder.setStrict(false);
578         flowBuilder.setPriority(protoMatchPriority);
579         flowBuilder.setBarrier(true);
580         flowBuilder.setTableId(this.getTable());
581         flowBuilder.setKey(key);
582         flowBuilder.setFlowName(flowId);
583         flowBuilder.setHardTimeout(0);
584         flowBuilder.setIdleTimeout(0);
585
586         if (write) {
587             // Instantiate the Builders for the OF Actions and Instructions
588             InstructionsBuilder isb = new InstructionsBuilder();
589             List<Instruction> instructionsList = Lists.newArrayList();
590
591             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
592             ib.setOrder(0);
593             ib.setKey(new InstructionKey(0));
594             instructionsList.add(ib.build());
595             isb.setInstruction(instructionsList);
596
597             LOG.debug("Instructions contain: {}", ib.getInstruction());
598             // Add InstructionsBuilder to FlowBuilder
599             flowBuilder.setInstructions(isb.build());
600             writeFlow(flowBuilder, nodeBuilder);
601         } else {
602             removeFlow(flowBuilder, nodeBuilder);
603         }
604     }
605
606     public void egressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
607                                         boolean write, String securityRuleIpPrefix, Integer protoPortMatchPriority) {
608
609         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
610         MatchBuilder matchBuilder = new MatchBuilder();
611         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
612         FlowBuilder flowBuilder = new FlowBuilder();
613
614         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId))
615                              .build());
616         if (securityRuleIpPrefix != null) {
617             Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
618             flowBuilder.setMatch(MatchUtils
619                                  .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix)
620                                  .build());
621         } else {
622             flowBuilder.setMatch(MatchUtils
623                                  .createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null)
624                                  .build());
625         }
626         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
627         String flowId = "Egress_Proto_ACL" + segmentationId + "_" +
628                 attachedMac + "_Permit_" + securityRuleIpPrefix;
629         // Add Flow Attributes
630         flowBuilder.setId(new FlowId(flowId));
631         FlowKey key = new FlowKey(new FlowId(flowId));
632         flowBuilder.setStrict(false);
633         flowBuilder.setPriority(protoPortMatchPriority);
634         flowBuilder.setBarrier(true);
635         flowBuilder.setTableId(this.getTable());
636         flowBuilder.setKey(key);
637         flowBuilder.setFlowName(flowId);
638         flowBuilder.setHardTimeout(0);
639         flowBuilder.setIdleTimeout(0);
640
641         if (write) {
642             // Instantiate the Builders for the OF Actions and Instructions
643             InstructionsBuilder isb = new InstructionsBuilder();
644             List<Instruction> instructionsList = Lists.newArrayList();
645
646             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
647             ib.setOrder(0);
648             ib.setKey(new InstructionKey(0));
649             instructionsList.add(ib.build());
650             isb.setInstruction(instructionsList);
651
652             LOG.debug("Instructions contain: {}", ib.getInstruction());
653             // Add InstructionsBuilder to FlowBuilder
654             flowBuilder.setInstructions(isb.build());
655             writeFlow(flowBuilder, nodeBuilder);
656         } else {
657             removeFlow(flowBuilder, nodeBuilder);
658         }
659     }
660
661
662     public void egressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
663                                 Integer securityRulePortMin, Integer protoPortMatchPriority) {
664
665         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
666         PortNumber tcpPort = new PortNumber(securityRulePortMin);
667         MatchBuilder matchBuilder = new MatchBuilder();
668         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
669         FlowBuilder flowBuilder = new FlowBuilder();
670
671         flowBuilder.setMatch(MatchUtils.createSmacTcpSyn(matchBuilder, attachedMac, tcpPort,
672                                                          Constants.TCP_SYN, segmentationId).build());
673
674         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
675         String flowId = "Ucast_this.getTable()" + segmentationId + "_" + attachedMac + securityRulePortMin;
676         // Add Flow Attributes
677         flowBuilder.setId(new FlowId(flowId));
678         FlowKey key = new FlowKey(new FlowId(flowId));
679         flowBuilder.setStrict(false);
680         flowBuilder.setPriority(protoPortMatchPriority);
681         flowBuilder.setBarrier(true);
682         flowBuilder.setTableId(this.getTable());
683         flowBuilder.setKey(key);
684         flowBuilder.setFlowName(flowId);
685         flowBuilder.setHardTimeout(0);
686         flowBuilder.setIdleTimeout(0);
687
688         if (write) {
689             // Instantiate the Builders for the OF Actions and Instructions
690             InstructionsBuilder isb = new InstructionsBuilder();
691             List<Instruction> instructionsList = Lists.newArrayList();
692
693             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
694             ib.setOrder(0);
695             ib.setKey(new InstructionKey(0));
696             instructionsList.add(ib.build());
697             isb.setInstruction(instructionsList);
698
699             LOG.debug("Instructions contain: {}", ib.getInstruction());
700             // Add InstructionsBuilder to FlowBuilder
701             flowBuilder.setInstructions(isb.build());
702             writeFlow(flowBuilder, nodeBuilder);
703         } else {
704             removeFlow(flowBuilder, nodeBuilder);
705         }
706     }
707
708     /**
709      * Adds flow to allow any DHCP client traffic.
710      *
711      * @param dpidLong the dpid
712      * @param write whether to write or delete the flow
713      * @param protoPortMatchPriority the priority
714      */
715     private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
716                                                        boolean write, Integer protoPortMatchPriority) {
717
718         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
719         MatchBuilder matchBuilder = new MatchBuilder();
720         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
721
722         MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT).build();
723         LOG.debug("egressAclDHCPAllowClientTrafficFromVm: MatchBuilder contains: {}", matchBuilder);
724         String flowId = "Egress_DHCP_Client"  + "_Permit_";
725         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
726     }
727
728     /**
729      * Adds rule to prevent DHCP spoofing by the vm attached to the port.
730      *
731      * @param dpidLong the dpid
732      * @param localPort the local port
733      * @param write is write or delete
734      * @param protoPortMatchPriority  the priority
735      */
736     private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
737                                                       boolean write, Integer protoPortMatchPriority) {
738
739         MatchBuilder matchBuilder = new MatchBuilder();
740         //FlowBuilder flowBuilder = new FlowBuilder();
741         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
742         MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT).build();
743         LOG.debug("egressAclDHCPDropServerTrafficfromVM: MatchBuilder contains: {}", matchBuilder);
744         String flowId = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
745         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
746         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
747         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, true);
748
749     }
750
751     /**
752      * Adds rule to check legitimate ip/mac pair for each packet from the vm.
753      *
754      * @param dpidLong the dpid
755      * @param localPort the local port
756      * @param srcIp the vm ip address
757      * @param attachedMac the vm mac address
758      * @param protoPortMatchPriority  the priority
759      * @param write is write or delete
760      */
761     private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
762                                                       String attachedMac, String srcIp,
763                                                       Integer protoPortMatchPriority, boolean write) {
764         MatchBuilder matchBuilder = new MatchBuilder();
765         MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
766         MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
767         LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
768         String flowId = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
769         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
770         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
771         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
772
773     }
774
775     /**
776      * Add or remove flow to the node.
777      *
778      * @param flowId the the flow id
779      * @param nodeBuilder the node builder
780      * @param matchBuilder the matchbuilder
781      * @param protoPortMatchPriority the protocol priority
782      * @param write whether it is a write
783      * @param drop whether it is a drop or forward
784      */
785     private void syncFlow(String flowId, NodeBuilder nodeBuilder,
786                           MatchBuilder matchBuilder,Integer protoPortMatchPriority,
787                           boolean write,boolean drop) {
788         FlowBuilder flowBuilder = new FlowBuilder();
789         flowBuilder.setMatch(matchBuilder.build());
790         flowBuilder.setId(new FlowId(flowId));
791         FlowKey key = new FlowKey(new FlowId(flowId));
792         flowBuilder.setStrict(false);
793         flowBuilder.setPriority(protoPortMatchPriority);
794         flowBuilder.setBarrier(true);
795         flowBuilder.setTableId(this.getTable());
796         flowBuilder.setKey(key);
797         flowBuilder.setFlowName(flowId);
798         flowBuilder.setHardTimeout(0);
799         flowBuilder.setIdleTimeout(0);
800
801         if (write) {
802             // Instantiate the Builders for the OF Actions and Instructions
803
804             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
805             if (drop) {
806                 InstructionUtils.createDropInstructions(ib);
807             }
808             ib.setOrder(0);
809             ib.setKey(new InstructionKey(0));
810             InstructionsBuilder isb = new InstructionsBuilder();
811             List<Instruction> instructionsList = Lists.newArrayList();
812             instructionsList.add(ib.build());
813             isb.setInstruction(instructionsList);
814             flowBuilder.setInstructions(isb.build());
815             writeFlow(flowBuilder, nodeBuilder);
816         } else {
817             removeFlow(flowBuilder, nodeBuilder);
818         }
819
820     }
821
822
823
824     @Override
825     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
826         super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
827         securityServicesManager =
828                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
829     }
830
831     @Override
832     public void setDependencies(Object impl) {}
833 }