Added Security Rule for Custom ICMP
[ovsdb.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / services / IngressAclService.java
1 /*
2  * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13.services;
10
11 import 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.IngressAclProvider;
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 IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
46
47     private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
48     private volatile SecurityServicesManager securityServicesManager;
49
50     public IngressAclService() {
51         super(Service.INGRESS_ACL);
52     }
53
54     public IngressAclService(Service service) {
55         super(service);
56     }
57
58     @Override
59     public void programPortSecurityAcl(Long dpid, String segmentationId, String attachedMac,
60                                        long localPort, NeutronSecurityGroup securityGroup,
61                                        List<Neutron_IPs> srcAddressList, boolean write) {
62
63         LOG.trace("programLocalBridgeRulesWithSec neutronSecurityGroup: {} ", securityGroup);
64         List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
65         /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
66         for (NeutronSecurityRule portSecurityRule : portSecurityList) {
67             /**
68              * Neutron Port Security Acl "ingress" and "IPv4"
69              * Check that the base conditions for flow based Port Security are true:
70              * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
71              * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
72              * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
73              *
74              */
75
76             if ("IPv4".equals(portSecurityRule.getSecurityRuleEthertype())
77                     && "ingress".equals(portSecurityRule.getSecurityRuleDirection())) {
78                 LOG.debug("Acl Rule matching IPv4 and ingress is: {} ", portSecurityRule);
79                 if (null == portSecurityRule.getSecurityRuleProtocol()) {
80                     ingressAclIPv4(dpid, segmentationId, attachedMac,
81                                    write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
82                 } else if (null != portSecurityRule.getSecurityRemoteGroupID()) {
83                     //Remote Security group is selected
84                     List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
85                             .getVmListForSecurityGroup(srcAddressList,portSecurityRule.getSecurityRemoteGroupID());
86                     if (null != remoteSrcAddressList) {
87                         for (Neutron_IPs vmIp :remoteSrcAddressList ) {
88                             switch (portSecurityRule.getSecurityRuleProtocol()) {
89                             case MatchUtils.TCP:
90                                 ingressAclTcp(dpid, segmentationId, attachedMac, portSecurityRule,vmIp.getIpAddress(),
91                                               write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
92                                 break;
93                             case MatchUtils.UDP:
94                                 ingressAclUdp(dpid, segmentationId, attachedMac, portSecurityRule,vmIp.getIpAddress(),
95                                               write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
96                                 break;
97                             case MatchUtils.ICMP:
98                                 ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, vmIp.getIpAddress(),
99                                                write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
100                                 break;
101                             default:
102                                 LOG.error("programPortSecurityAcl: Protocol not supported", portSecurityRule);
103                                 break;
104                             }
105                         }
106                     }
107                 } else {
108                     //CIDR is selected
109                     switch (portSecurityRule.getSecurityRuleProtocol()) {
110                     case MatchUtils.TCP:
111                         ingressAclTcp(dpid, segmentationId, attachedMac,
112                                       portSecurityRule, null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
113                         break;
114                     case MatchUtils.UDP:
115                         ingressAclUdp(dpid, segmentationId, attachedMac,
116                                       portSecurityRule, null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
117                         break;
118                     case MatchUtils.ICMP:
119                         ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, null,
120                                        write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
121                         break;
122                     default:
123                         LOG.error("programPortSecurityAcl: Protocol not supported", portSecurityRule);
124                     }
125                 }
126
127                 /**
128                  * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (True)
129                  * TODO Some part of the code will be  used when conntrack is supported
130
131                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
132                         !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
133                         !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
134                         (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
135                                 !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
136                                         .equalsIgnoreCase("0.0.0.0/0"))) {
137                     LOG.debug("Rule #1 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
138                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
139                             portSecurityRule.getSecurityRulePortMax(),
140                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
141                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
142                             Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
143                             true);
144                     ingressACLTcpPortWithPrefix(dpid, segmentationId,
145                             attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
146                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
147                     continue;
148                 }
149                 /**
150                  * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (True)
151                  */
152                 /*if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
153                         !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
154                         String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
155                         (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
156                                 !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
157                                         .equalsIgnoreCase("0.0.0.0/0"))) {
158                     LOG.debug("Rule #2 ingress 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                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
163                                              Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY_DROP,
164                             true);
165                     ingressACLTcpPortWithPrefix(dpid, segmentationId,
166                             attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
167                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
168                     continue;
169                 }
170                  *//**
171                  * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
172                  *//*
173                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
174                         String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
175                         String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
176                         !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
177                     LOG.debug("Rule #3 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
178                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
179                             portSecurityRule.getSecurityRulePortMax(),
180                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
181                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PREFIX_MATCH_PRIORITY_DROP,
182                             true);
183                     ingressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
184                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PROTO_PREFIX_MATCH_PRIORITY);
185                     continue;
186                 }
187                   *//**
188                   * TCP Proto (False), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (True)
189                   *//*
190                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("null") &&
191                         String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
192                         String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
193                         (!String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null") &&
194                                 !String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
195                                         .equalsIgnoreCase("0.0.0.0/0"))) {
196                     LOG.debug("Rule #4 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
197                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
198                             portSecurityRule.getSecurityRulePortMax(),
199                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
200                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PREFIX_MATCH_PRIORITY_DROP, true);
201                     ingressACLPermitAllProto(dpid, segmentationId, attachedMac, true,
202                             portSecurityRule.getSecurityRuleRemoteIpPrefix(), Constants.PREFIX_MATCH_PRIORITY);
203                     continue;
204                 }
205                    *//**
206                    * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (True), IP Prefix (False)
207                    *//*
208                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
209                         !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
210                         !String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
211                         String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
212                     LOG.debug("Rule #5 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
213                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
214                             portSecurityRule.getSecurityRulePortMax(),
215                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
216                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, Constants.PROTO_PORT_MATCH_PRIORITY_DROP,
217                             true);
218                     ingressACLTcpSyn(dpid, segmentationId,
219                             attachedMac, true, portSecurityRule.getSecurityRulePortMin(),
220                             Constants.PREFIX_PORT_MATCH_PRIORITY_DROP);
221                     continue;
222                 }
223                     *//**
224                     * TCP Proto (True), TCP Port Minimum (True), TCP Port Max (False), IP Prefix (False)
225                     *//*
226                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
227                         !String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
228                         String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
229                         String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) {
230                     LOG.debug("Rule #6 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
231                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
232                             portSecurityRule.getSecurityRulePortMax(),
233                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
234                     ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac,
235                                              Constants.PROTO_PORT_MATCH_PRIORITY_DROP, true);
236                     ingressACLTcpSyn(dpid, segmentationId, attachedMac, true,
237                             portSecurityRule.getSecurityRulePortMin(), Constants.PROTO_PORT_MATCH_PRIORITY);
238                     continue;
239                 }
240                      *//**
241                      * TCP Proto (True), TCP Port Minimum (False), TCP Port Max (False), IP Prefix (False or 0.0.0.0/0)
242                      *//*
243                 if (String.valueOf(portSecurityRule.getSecurityRuleProtocol()).equalsIgnoreCase("tcp") &&
244                         String.valueOf(portSecurityRule.getSecurityRulePortMin()).equalsIgnoreCase("null") &&
245                         String.valueOf(portSecurityRule.getSecurityRulePortMax()).equalsIgnoreCase("null") &&
246                         ((String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix()).equalsIgnoreCase("null")) ||
247                                 String.valueOf(portSecurityRule.getSecurityRuleRemoteIpPrefix())
248                                         .equalsIgnoreCase("0.0.0.0/0"))) {
249                     LOG.debug("Rule #7 ingress PortSec Rule Matches -> TCP Protocol: {}, TCP Port Min: {}, TCP Port Max: {}, IP Prefix: {}",
250                             portSecurityRule.getSecurityRuleProtocol(), portSecurityRule.getSecurityRulePortMin(),
251                             portSecurityRule.getSecurityRulePortMax(),
252                             portSecurityRule.getSecurityRuleRemoteIpPrefix());
253                     // No need to drop until UDP/ICMP are implemented
254                     // ingressACLDefaultTcpDrop(dpid, segmentationId, attachedMac, PROTO_MATCH_PRIORITY_DROP, true);
255                     handleIngressAllowProto(dpid, segmentationId, attachedMac, true,
256                             portSecurityRule.getSecurityRuleProtocol(), Constants.PROTO_MATCH_PRIORITY);
257                     continue;
258                 }*/
259                 LOG.debug("Ingress Acl Match combination not found for rule: {}", portSecurityRule);
260             }
261         }
262     }
263
264     @Override
265     public void programFixedSecurityAcl(Long dpid, String segmentationId, String dhcpMacAddress,
266                                         long localPort, boolean isLastPortinSubnet,
267                                         boolean isComputePort, boolean write) {
268         //If this port is the only port in the compute node add the DHCP server rule.
269         if (isLastPortinSubnet && isComputePort ) {
270             ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
271                                              write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
272         }
273     }
274
275     /**
276      * Allows IPv4 packet ingress to the destination mac address.
277      * @param dpidLong the dpid
278      * @param segmentationId the segementation id
279      * @param dstMac the destination mac address
280      * @param write add or remove
281      * @param protoPortMatchPriority the protocol match priority.
282      */
283     private void ingressAclIPv4(Long dpidLong, String segmentationId, String dstMac,
284                                boolean write, Integer protoPortMatchPriority ) {
285         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
286         MatchBuilder matchBuilder = new MatchBuilder();
287         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
288         String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
289         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
290         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
291
292     }
293     /**
294      * Creates a ingress match to the dst macaddress. If src address is specified
295      * source specific match will be created. Otherwise a match with a CIDR will
296      * be created.
297      * @param dpidLong the dpid
298      * @param segmentationId the segmentation id
299      * @param dstMac the destination mac address.
300      * @param portSecurityRule the security rule in the SG
301      * @param srcAddress the destination IP address
302      * @param write add or delete
303      * @param protoPortMatchPriority the protocol match priroty
304      */
305     private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
306                               NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
307                               Integer protoPortMatchPriority ) {
308
309         MatchBuilder matchBuilder = new MatchBuilder();
310         FlowBuilder flowBuilder = new FlowBuilder();
311         String flowId = "Ingress_Custom_Tcp" + segmentationId + "_" + dstMac + "_";
312         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
313         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
314             flowId = flowId + portSecurityRule.getSecurityRulePortMin();
315             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
316                                                     portSecurityRule.getSecurityRulePortMin());
317         } else {
318             /*TODO TCP PortRange Match*/
319
320         }
321
322         if (null != srcAddress) {
323             flowId = flowId + srcAddress;
324             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
325                                                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
326
327         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
328             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
329             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
330                                                         new Ipv4Prefix(portSecurityRule
331                                                                        .getSecurityRuleRemoteIpPrefix()),null);
332         }
333         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
334         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
335         flowId = flowId + "_Permit_";
336         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
337
338     }
339
340     /**
341      * Creates a ingress match to the dst macaddress. If src address is specified
342      * source specific match will be created. Otherwise a match with a CIDR will
343      * be created.
344      * @param dpidLong the dpid
345      * @param segmentationId the segmentation id
346      * @param dstMac the destination mac address.
347      * @param portSecurityRule the security rule in the SG
348      * @param srcAddress the destination IP address
349      * @param write add or delete
350      * @param protoPortMatchPriority the protocol match priroty
351      */
352     private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
353                               NeutronSecurityRule portSecurityRule, String srcAddress,
354                               boolean write, Integer protoPortMatchPriority ) {
355         MatchBuilder matchBuilder = new MatchBuilder();
356         String flowId = "ingressAclUDP" + segmentationId + "_" + dstMac + "_";
357         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
358         if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
359             flowId = flowId + portSecurityRule.getSecurityRulePortMin();
360             matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
361                                                     portSecurityRule.getSecurityRulePortMin());
362         } else {
363             /*TODO TCP PortRange Match*/
364
365         }
366
367         if (null != srcAddress) {
368             flowId = flowId + srcAddress;
369             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
370                                                         MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
371
372         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
373             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
374             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
375                                       new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
376         }
377         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
378         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
379         flowId = flowId + "_Permit_";
380         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
381
382     }
383
384     /**
385      * Creates a ingress match to the dst macaddress. If src address is specified
386      * source specific match will be created. Otherwise a match with a CIDR will
387      * be created.
388      * @param dpidLong the dpid
389      * @param segmentationId the segmentation id
390      * @param dstMac the destination mac address.
391      * @param portSecurityRule the security rule in the SG
392      * @param srcAddress the destination IP address
393      * @param write add or delete
394      * @param protoPortMatchPriority the protocol match priority
395      */
396     private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
397                                 NeutronSecurityRule portSecurityRule, String srcAddress,
398                                 boolean write, Integer protoPortMatchPriority) {
399
400         MatchBuilder matchBuilder = new MatchBuilder();
401         FlowBuilder flowBuilder = new FlowBuilder();
402         String flowId = "ingressAclICMP" + segmentationId + "_" + dstMac;
403         matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,null,dstMac);
404         matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
405                         portSecurityRule.getSecurityRulePortMin().shortValue(),
406                         portSecurityRule.getSecurityRulePortMax().shortValue());
407         if (null != srcAddress) {
408             flowId = flowId + srcAddress;
409             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
410                     MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
411
412         } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
413             flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
414             matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
415                     new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
416         }
417         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
418         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
419         flowId = flowId + "_Permit_";
420         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
421     }
422
423     public void ingressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
424                                  Integer securityRulePortMin, Integer protoPortMatchPriority) {
425
426         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
427         PortNumber tcpPort = new PortNumber(securityRulePortMin);
428         MatchBuilder matchBuilder = new MatchBuilder();
429         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
430         FlowBuilder flowBuilder = new FlowBuilder();
431
432         flowBuilder.setMatch(MatchUtils.createDmacTcpSynMatch(matchBuilder, attachedMac, tcpPort,
433                                                               Constants.TCP_SYN, segmentationId).build());
434
435         LOG.debug("ingressACLTcpSyn MatchBuilder contains:  {}", flowBuilder.getMatch());
436         String flowId = "UcastOut_ACL2_" + segmentationId + "_" + attachedMac + securityRulePortMin;
437         // Add Flow Attributes
438         flowBuilder.setId(new FlowId(flowId));
439         FlowKey key = new FlowKey(new FlowId(flowId));
440         flowBuilder.setStrict(false);
441         flowBuilder.setPriority(protoPortMatchPriority);
442         flowBuilder.setBarrier(true);
443         flowBuilder.setTableId(this.getTable());
444         flowBuilder.setKey(key);
445         flowBuilder.setFlowName(flowId);
446         flowBuilder.setHardTimeout(0);
447         flowBuilder.setIdleTimeout(0);
448
449         if (write) {
450             // Instantiate the Builders for the OF Actions and Instructions
451             InstructionsBuilder isb = new InstructionsBuilder();
452             List<Instruction> instructionsList = Lists.newArrayList();
453
454             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
455             ib.setOrder(0);
456             ib.setKey(new InstructionKey(0));
457             instructionsList.add(ib.build());
458             isb.setInstruction(instructionsList);
459
460             LOG.debug("Instructions are: {}", ib.getInstruction());
461             // Add InstructionsBuilder to FlowBuilder
462             flowBuilder.setInstructions(isb.build());
463             writeFlow(flowBuilder, nodeBuilder);
464         } else {
465             removeFlow(flowBuilder, nodeBuilder);
466         }
467     }
468
469     public void ingressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac,
470                                             boolean write, Integer securityRulePortMin, String securityRuleIpPrefix,
471                                             Integer protoPortPrefixMatchPriority) {
472
473         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
474         PortNumber tcpPort = new PortNumber(securityRulePortMin);
475
476         MatchBuilder matchBuilder = new MatchBuilder();
477         NodeBuilder nodeBuilder = this.createNodeBuilder(nodeName);
478         FlowBuilder flowBuilder = new FlowBuilder();
479         Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
480
481         flowBuilder.setMatch(MatchUtils
482                              .createDmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
483                                                                  tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix).build());
484
485         LOG.debug(" MatchBuilder contains:  {}", flowBuilder.getMatch());
486         String flowId = "UcastOut2_" + segmentationId + "_" + attachedMac +
487                 securityRulePortMin + securityRuleIpPrefix;
488         // Add Flow Attributes
489         flowBuilder.setId(new FlowId(flowId));
490         FlowKey key = new FlowKey(new FlowId(flowId));
491         flowBuilder.setStrict(false);
492         flowBuilder.setPriority(protoPortPrefixMatchPriority);
493         flowBuilder.setBarrier(true);
494         flowBuilder.setTableId(this.getTable());
495         flowBuilder.setKey(key);
496         flowBuilder.setFlowName(flowId);
497         flowBuilder.setHardTimeout(0);
498         flowBuilder.setIdleTimeout(0);
499
500         if (write) {
501             // Instantiate the Builders for the OF Actions and Instructions
502             InstructionsBuilder isb = new InstructionsBuilder();
503
504             List<Instruction> instructionsList = Lists.newArrayList();
505             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
506             ib.setOrder(0);
507             ib.setKey(new InstructionKey(0));
508             instructionsList.add(ib.build());
509             isb.setInstruction(instructionsList);
510
511             LOG.debug("Instructions contain: {}", ib.getInstruction());
512             // Add InstructionsBuilder to FlowBuilder
513             flowBuilder.setInstructions(isb.build());
514             writeFlow(flowBuilder, nodeBuilder);
515         } else {
516             removeFlow(flowBuilder, nodeBuilder);
517         }
518     }
519
520     public void handleIngressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
521                                         String securityRuleProtcol, Integer protoMatchPriority) {
522
523         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
524
525         MatchBuilder matchBuilder = new MatchBuilder();
526         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
527         FlowBuilder flowBuilder = new FlowBuilder();
528
529         flowBuilder.setMatch(MatchUtils
530                              .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null).build());
531         flowBuilder.setMatch(MatchUtils
532                              .createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
533         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
534
535         String flowId = "UcastOut_" + segmentationId + "_" +
536                 attachedMac + "_AllowTCPSynPrefix_" + securityRuleProtcol;
537         // Add Flow Attributes
538         flowBuilder.setId(new FlowId(flowId));
539         FlowKey key = new FlowKey(new FlowId(flowId));
540         flowBuilder.setStrict(false);
541         flowBuilder.setPriority(protoMatchPriority);
542         flowBuilder.setBarrier(true);
543         flowBuilder.setTableId(this.getTable());
544         flowBuilder.setKey(key);
545         flowBuilder.setFlowName(flowId);
546         flowBuilder.setHardTimeout(0);
547         flowBuilder.setIdleTimeout(0);
548
549         if (write) {
550             // Instantiate the Builders for the OF Actions and Instructions
551             InstructionsBuilder isb = new InstructionsBuilder();
552             List<Instruction> instructionsList = Lists.newArrayList();
553
554             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
555             ib.setOrder(1);
556             ib.setKey(new InstructionKey(1));
557             instructionsList.add(ib.build());
558             isb.setInstruction(instructionsList);
559             LOG.debug("Instructions contain: {}", ib.getInstruction());
560
561             // Add InstructionsBuilder to FlowBuilder
562             flowBuilder.setInstructions(isb.build());
563             writeFlow(flowBuilder, nodeBuilder);
564         } else {
565             removeFlow(flowBuilder, nodeBuilder);
566         }
567     }
568
569
570     public void ingressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
571                                          int priority, boolean write) {
572
573         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
574         MatchBuilder matchBuilder = new MatchBuilder();
575         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
576         FlowBuilder flowBuilder = new FlowBuilder();
577
578         flowBuilder.setMatch(MatchUtils.createDmacTcpPortWithFlagMatch(matchBuilder,
579                                                                        attachedMac, Constants.TCP_SYN, segmentationId).build());
580
581         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
582         String flowId = "PortSec_TCP_Syn_Default_Drop_" + segmentationId + "_" + attachedMac;
583         flowBuilder.setId(new FlowId(flowId));
584         FlowKey key = new FlowKey(new FlowId(flowId));
585         flowBuilder.setStrict(false);
586         flowBuilder.setPriority(priority);
587         flowBuilder.setBarrier(true);
588         flowBuilder.setTableId(this.getTable());
589         flowBuilder.setKey(key);
590         flowBuilder.setFlowName(flowId);
591         flowBuilder.setHardTimeout(0);
592         flowBuilder.setIdleTimeout(0);
593
594         if (write) {
595             // Instantiate the Builders for the OF Actions and Instructions
596             InstructionBuilder ib = new InstructionBuilder();
597             InstructionsBuilder isb = new InstructionsBuilder();
598
599             // Instructions List Stores Individual Instructions
600             List<Instruction> instructions = Lists.newArrayList();
601
602             // Set the Output Port/Iface
603             InstructionUtils.createDropInstructions(ib);
604             ib.setOrder(0);
605             ib.setKey(new InstructionKey(0));
606             instructions.add(ib.build());
607
608             // Add InstructionBuilder to the Instruction(s)Builder List
609             isb.setInstruction(instructions);
610             LOG.debug("Instructions contain: {}", ib.getInstruction());
611             // Add InstructionsBuilder to FlowBuilder
612             flowBuilder.setInstructions(isb.build());
613             writeFlow(flowBuilder, nodeBuilder);
614         } else {
615             removeFlow(flowBuilder, nodeBuilder);
616         }
617     }
618
619     public void ingressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
620                                          boolean write, String securityRuleIpPrefix, Integer protoPortMatchPriority) {
621         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
622         Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
623         MatchBuilder matchBuilder = new MatchBuilder();
624         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
625         FlowBuilder flowBuilder = new FlowBuilder();
626
627         flowBuilder.setMatch(MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId))
628                              .build());
629         if (securityRuleIpPrefix != null) {
630             flowBuilder.setMatch(MatchUtils
631                                  .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix)
632                                  .build());
633         } else {
634             flowBuilder.setMatch(MatchUtils
635                                  .createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null)
636                                  .build());
637         }
638
639         LOG.debug("MatchBuilder contains: {}", flowBuilder.getMatch());
640         String flowId = "IngressProto_ACL_" + segmentationId + "_" +
641                 attachedMac + "_Permit_" + securityRuleIpPrefix;
642         // Add Flow Attributes
643         flowBuilder.setId(new FlowId(flowId));
644         FlowKey key = new FlowKey(new FlowId(flowId));
645         flowBuilder.setStrict(false);
646         flowBuilder.setPriority(protoPortMatchPriority);
647         flowBuilder.setBarrier(true);
648         flowBuilder.setTableId(this.getTable());
649         flowBuilder.setKey(key);
650         flowBuilder.setFlowName(flowId);
651         flowBuilder.setHardTimeout(0);
652         flowBuilder.setIdleTimeout(0);
653
654         if (write) {
655             // Instantiate the Builders for the OF Actions and Instructions
656             InstructionBuilder ib = new InstructionBuilder();
657             InstructionsBuilder isb = new InstructionsBuilder();
658             List<Instruction> instructionsList = Lists.newArrayList();
659
660             ib = this.getMutablePipelineInstructionBuilder();
661             ib.setOrder(1);
662             ib.setKey(new InstructionKey(0));
663             instructionsList.add(ib.build());
664             isb.setInstruction(instructionsList);
665
666             LOG.debug("Instructions contain: {}", ib.getInstruction());
667             // Add InstructionsBuilder to FlowBuilder
668             flowBuilder.setInstructions(isb.build());
669             writeFlow(flowBuilder, nodeBuilder);
670         } else {
671             removeFlow(flowBuilder, nodeBuilder);
672         }
673     }
674
675     /**
676      * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
677      *
678      * @param dpidLong the dpid
679      * @param segmentationId the segmentation id
680      * @param dhcpMacAddress the DHCP server mac address
681      * @param write is write or delete
682      * @param protoPortMatchPriority the priority
683      */
684     private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
685                                                   boolean write, Integer protoPortMatchPriority) {
686
687         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
688         MatchBuilder matchBuilder = new MatchBuilder();
689         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
690         MatchUtils.createDhcpServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build();
691         LOG.debug("ingressAclDHCPAllowServerTraffic: MatchBuilder contains: {}", matchBuilder);
692         String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
693         syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false);
694     }
695
696     /**
697      * Add or remove flow to the node.
698      *
699      * @param flowId the the flow id
700      * @param nodeBuilder the node builder
701      * @param matchBuilder the matchbuilder
702      * @param protoPortMatchPriority the protocol priority
703      * @param write whether it is a write
704      * @param drop whether it is a drop or forward
705      */
706     private void syncFlow(String flowId, NodeBuilder nodeBuilder,
707                           MatchBuilder matchBuilder,Integer protoPortMatchPriority,
708                           boolean write,boolean drop) {
709         FlowBuilder flowBuilder = new FlowBuilder();
710         flowBuilder.setMatch(matchBuilder.build());
711         flowBuilder.setId(new FlowId(flowId));
712         FlowKey key = new FlowKey(new FlowId(flowId));
713         flowBuilder.setStrict(false);
714         flowBuilder.setPriority(protoPortMatchPriority);
715         flowBuilder.setBarrier(true);
716         flowBuilder.setTableId(this.getTable());
717         flowBuilder.setKey(key);
718         flowBuilder.setFlowName(flowId);
719         flowBuilder.setHardTimeout(0);
720         flowBuilder.setIdleTimeout(0);
721
722         if (write) {
723             // Instantiate the Builders for the OF Actions and Instructions
724             InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
725             if (drop) {
726                 InstructionUtils.createDropInstructions(ib);
727             }
728             ib.setOrder(0);
729             InstructionsBuilder isb = new InstructionsBuilder();
730             List<Instruction> instructionsList = Lists.newArrayList();
731             ib.setKey(new InstructionKey(0));
732             instructionsList.add(ib.build());
733             isb.setInstruction(instructionsList);
734             flowBuilder.setInstructions(isb.build());
735             writeFlow(flowBuilder, nodeBuilder);
736         } else {
737             removeFlow(flowBuilder, nodeBuilder);
738         }
739
740     }
741
742     @Override
743     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
744         super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
745         securityServicesManager =
746                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
747     }
748
749     @Override
750     public void setDependencies(Object impl) {
751
752     }
753 }