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