2 * Copyright (c) 2014 - 2016 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.services;
11 import com.google.common.collect.Lists;
13 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.AbstractServiceInstance;
14 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
15 import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
16 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
17 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
18 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
19 import org.opendaylight.netvirt.openstack.netvirt.providers.openflow13.Service;
20 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
21 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
22 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
23 import org.opendaylight.netvirt.utils.mdsal.openflow.ActionUtils;
24 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
25 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
26 import org.opendaylight.netvirt.utils.mdsal.openflow.MatchUtils;
27 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
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.Ipv6Prefix;
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.action.types.rev131112.action.Action;
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.types.rev131026.flow.InstructionsBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
39 import org.osgi.framework.BundleContext;
40 import org.osgi.framework.ServiceReference;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
44 import java.net.Inet4Address;
45 import java.net.Inet6Address;
46 import java.net.InetAddress;
47 import java.net.UnknownHostException;
48 import java.util.List;
51 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
53 private static final Logger LOG = LoggerFactory.getLogger(EgressAclService.class);
54 private volatile SecurityServicesManager securityServicesManager;
55 private volatile SecurityGroupCacheManger securityGroupCacheManger;
56 private static final int DHCP_SOURCE_PORT = 67;
57 private static final int DHCP_DESTINATION_PORT = 68;
58 private static final int DHCPV6_SOURCE_PORT = 547;
59 private static final int DHCPV6_DESTINATION_PORT = 546;
60 private static final String HOST_MASK = "/32";
61 private static final String V6_HOST_MASK = "/128";
62 private static final int PORT_RANGE_MIN = 1;
63 private static final int PORT_RANGE_MAX = 65535;
65 public EgressAclService() {
66 super(Service.EGRESS_ACL);
69 public EgressAclService(Service service) {
74 public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
75 NeutronSecurityGroup securityGroup, String portUuid, boolean write) {
77 LOG.trace("programPortSecurityGroup: neutronSecurityGroup: {} ", securityGroup);
78 if (securityGroup == null || securityGroup.getSecurityRules() == null) {
82 List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
83 /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
84 for (NeutronSecurityRule portSecurityRule : portSecurityList) {
87 * Neutron Port Security Acl "egress" and "IPv4"
88 * Check that the base conditions for flow based Port Security are true:
89 * Port Security Rule Direction ("egress") and Protocol ("IPv4")
90 * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
91 * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
95 if (portSecurityRule == null
96 || portSecurityRule.getSecurityRuleEthertype() == null
97 || portSecurityRule.getSecurityRuleDirection() == null) {
101 if (NeutronSecurityRule.DIRECTION_EGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
102 LOG.debug("programPortSecurityGroup: Acl Rule matching IP and ingress is: {} ", portSecurityRule);
103 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
104 //Remote Security group is selected
105 List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
106 .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
107 if (null != remoteSrcAddressList) {
108 for (Neutron_IPs vmIp :remoteSrcAddressList ) {
110 programPortSecurityRule(dpid, segmentationId, attachedMac,
111 localPort, portSecurityRule, vmIp, write);
114 securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
116 securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
121 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
122 portSecurityRule, null, write);
125 securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
127 securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
134 public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
135 long localPort, NeutronSecurityRule portSecurityRule,
136 Neutron_IPs vmIp, boolean write) {
137 String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
138 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
139 if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
140 LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
141 securityRuleEtherType);
145 if (null == portSecurityRule.getSecurityRuleProtocol()) {
146 /* TODO Rework on the priority values */
147 egressAclIp(dpid, isIpv6, segmentationId, attachedMac,
148 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
150 String ipaddress = null;
152 ipaddress = vmIp.getIpAddress();
154 InetAddress address = InetAddress.getByName(ipaddress);
155 if ((isIpv6 && (address instanceof Inet4Address)) || (!isIpv6 && address instanceof Inet6Address)) {
156 LOG.debug("programPortSecurityRule: Remote vmIP {} does not match with "
157 + "SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
160 } catch (UnknownHostException e) {
161 LOG.warn("Invalid IP address {}", ipaddress, e);
166 switch (portSecurityRule.getSecurityRuleProtocol()) {
168 LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
169 egressAclTcp(dpid, segmentationId, attachedMac,
170 portSecurityRule,ipaddress, write,
171 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
174 LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
175 egressAclUdp(dpid, segmentationId, attachedMac,
176 portSecurityRule, ipaddress, write,
177 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
179 case MatchUtils.ICMP:
180 case MatchUtils.ICMPV6:
181 LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
182 egressAclIcmp(dpid, segmentationId, attachedMac,
183 portSecurityRule, ipaddress,write,
184 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
187 LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
188 + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
189 egressOtherProtocolAclHandler(dpid, segmentationId, attachedMac,
190 portSecurityRule, ipaddress, write,
191 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
197 private void egressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String srcMac,
198 NeutronSecurityRule portSecurityRule, String dstAddress,
199 boolean write, Integer priority) {
200 MatchBuilder matchBuilder = new MatchBuilder();
201 String flowId = "Egress_Other_" + segmentationId + "_" + srcMac + "_";
202 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
206 Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
207 proto = protocol.shortValue();
208 flowId = flowId + proto;
209 } catch (NumberFormatException e) {
210 LOG.error("Protocol vlaue conversion failure", e);
212 matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
214 if (null != dstAddress) {
215 flowId = flowId + dstAddress;
216 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
217 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
219 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
220 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
221 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
222 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
224 flowId = flowId + "_Permit";
225 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
226 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, priority, matchBuilder, getTable());
227 addInstructionWithConntrackCommit(flowBuilder, false);
228 syncFlow(flowBuilder ,nodeBuilder, write);
232 public void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac,
233 long localPort, List<Neutron_IPs> srcAddressList, boolean write) {
235 egressAclDhcpAllowClientTrafficFromVm(dpid, write, localPort,
236 Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
237 egressAclDhcpv6AllowClientTrafficFromVm(dpid, write, localPort,
238 Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
239 programArpRule(dpid, segmentationId, localPort, attachedMac, write);
240 if (securityServicesManager.isConntrackEnabled()) {
241 programEgressAclFixedConntrackRule(dpid, segmentationId, localPort, attachedMac, write);
243 // add rule to drop the DHCP server traffic originating from the vm.
244 egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
245 Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
246 egressAclDhcpv6DropServerTrafficfromVm(dpid, localPort, write,
247 Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
248 //Adds rule to check legitimate ip/mac pair for each packet from the vm
249 for (Neutron_IPs srcAddress : srcAddressList) {
251 InetAddress address = InetAddress.getByName(srcAddress.getIpAddress());
252 if (address instanceof Inet4Address) {
253 String addressWithPrefix = srcAddress.getIpAddress() + HOST_MASK;
254 egressAclAllowTrafficFromVmIpMacPair(dpid, localPort, attachedMac, addressWithPrefix,
255 Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
256 } else if (address instanceof Inet6Address) {
257 String addressWithPrefix = srcAddress.getIpAddress() + V6_HOST_MASK;
258 egressAclAllowTrafficFromVmIpV6MacPair(dpid, localPort, attachedMac, addressWithPrefix,
259 Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
261 } catch (UnknownHostException e) {
262 LOG.warn("Invalid IP address {}", srcAddress.getIpAddress(), e);
268 private void programArpRule(Long dpid, String segmentationId, long localPort, String attachedMac, boolean write) {
269 MatchBuilder matchBuilder = new MatchBuilder();
270 String flowId = "Egress_ARP_" + segmentationId + "_" + localPort + "_";
271 MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
272 MatchUtils.addArpMacMatch(matchBuilder, attachedMac, null);
273 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
274 matchBuilder, getTable());
275 addPipelineInstruction(flowBuilder, null, false);
276 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
277 syncFlow(flowBuilder ,nodeBuilder, write);
280 private void programEgressAclFixedConntrackRule(Long dpid,
281 String segmentationId, long localPort, String attachMac, boolean write) {
283 programConntrackUntrackRule(dpid, segmentationId, localPort,attachMac,
284 Constants.CT_STATE_UNTRACKED_PRIORITY, write );
285 programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort,
286 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
287 programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort,
288 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
289 programConntrackNewDropRule(dpid, segmentationId, localPort,
290 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
291 programConntrackInvDropRule(dpid, segmentationId, localPort,
292 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
293 LOG.info("programEgressAclFixedConntrackRule : default connection tracking rule are added.");
294 } catch (Exception e) {
295 LOG.error("Failed to add default conntrack rules : " , e);
299 private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
300 long localPort, String attachMac, Integer priority, boolean write) {
301 MatchBuilder matchBuilder = new MatchBuilder();
302 String flowName = "Egress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
303 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder, attachMac, null,MatchUtils.ETHERTYPE_IPV4);
304 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
305 MatchUtils.UNTRACKED_CT_STATE_MASK);
306 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
307 addInstructionWithConntrackRecirc(flowBuilder);
308 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
309 syncFlow(flowBuilder ,nodeBuilder, write);
312 private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
313 long localPort,Integer priority, boolean write) {
314 MatchBuilder matchBuilder = new MatchBuilder();
315 String flowName = "Egress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
316 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
317 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
318 MatchUtils.TRACKED_CT_STATE_MASK);
319 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
320 addPipelineInstruction(flowBuilder, null, false);
321 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
322 syncFlow(flowBuilder ,nodeBuilder, write);
325 private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
326 long localPort,Integer priority, boolean write) {
327 MatchBuilder matchBuilder = new MatchBuilder();
328 String flowName = "Egress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
329 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
330 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
331 MatchUtils.TRACKED_CT_STATE_MASK);
332 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
333 addPipelineInstruction(flowBuilder, null, false);
334 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
335 syncFlow(flowBuilder ,nodeBuilder, write);
338 private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
339 long localPort, Integer priority, boolean write) {
340 MatchBuilder matchBuilder = new MatchBuilder();
342 String flowName = "Egress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
343 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
344 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
345 MatchUtils.TRACKED_NEW_CT_STATE_MASK);
346 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
347 addPipelineInstruction(flowBuilder, null, true);
348 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
349 syncFlow(flowBuilder ,nodeBuilder, write);
352 private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
353 long localPort, Integer priority, boolean write) {
354 MatchBuilder matchBuilder = new MatchBuilder();
355 String flowName = "Egress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
356 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
357 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
358 MatchUtils.TRACKED_INV_CT_STATE_MASK);
359 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
360 addPipelineInstruction(flowBuilder, null, true);
361 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
362 syncFlow(flowBuilder ,nodeBuilder, write);
366 * Allows IPv4/v6 packet egress from the src mac address.
367 * @param dpidLong the dpid
368 * @param isIpv6 whether the rule is for ipv6
369 * @param segmentationId the segementation id
370 * @param srcMac the src mac address
371 * @param write add or remove
372 * @param protoPortMatchPriority the protocol match priority.
374 private void egressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String srcMac,
375 boolean write, Integer protoPortMatchPriority ) {
376 MatchBuilder matchBuilder = new MatchBuilder();
377 String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
379 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
381 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
383 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
384 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
385 addInstructionWithConntrackCommit(flowBuilder, false);
386 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
387 syncFlow(flowBuilder ,nodeBuilder, write);
391 * Creates a egress match with src macaddress. If dest address is specified
392 * destination specific match will be created. Otherwise a match with a
393 * CIDR will be created.
394 * @param dpidLong the dpid
395 * @param segmentationId the segmentation id
396 * @param srcMac the source mac address.
397 * @param portSecurityRule the security rule in the SG
398 * @param dstAddress the destination IP address
399 * @param write add or delete
400 * @param protoPortMatchPriority the protocol match priroty
402 private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
403 NeutronSecurityRule portSecurityRule, String dstAddress,
404 boolean write, Integer protoPortMatchPriority) {
405 boolean portRange = false;
406 MatchBuilder matchBuilder = new MatchBuilder();
407 String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
408 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
410 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
412 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
415 /* Custom TCP Match */
416 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
417 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
418 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
419 portSecurityRule.getSecurityRulePortMin());
422 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
423 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
424 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
425 + portSecurityRule.getSecurityRulePortMax() + "_";
426 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
431 if (null != dstAddress) {
432 flowId = flowId + dstAddress;
434 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
435 MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
437 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
438 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
440 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
441 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
443 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
444 new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
446 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
447 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
450 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
452 Map<Integer, Integer> portMaskMap = MatchUtils
453 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
454 portSecurityRule.getSecurityRulePortMax());
455 for (Integer port: portMaskMap.keySet()) {
456 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
457 rangeflowId = rangeflowId + "_Permit";
458 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
459 0, port, portMaskMap.get(port));
460 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
461 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
462 matchBuilder, getTable());
463 addInstructionWithConntrackCommit(flowBuilder, false);
464 syncFlow(flowBuilder ,nodeBuilder, write);
467 flowId = flowId + "_Permit";
468 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
469 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
470 matchBuilder, getTable());
471 addInstructionWithConntrackCommit(flowBuilder, false);
472 syncFlow(flowBuilder ,nodeBuilder, write);
476 private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
477 NeutronSecurityRule portSecurityRule, String dstAddress,
478 boolean write, Integer protoPortMatchPriority) {
480 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
482 egressAclIcmpV6(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
483 protoPortMatchPriority);
485 egressAclIcmpV4(dpidLong, segmentationId, srcMac, portSecurityRule, dstAddress, write,
486 protoPortMatchPriority);
491 * Creates a icmp egress match with src macaddress. If dest address is specified
492 * destination specific match will be created. Otherwise a match with a
493 * CIDR will be created.
494 * @param dpidLong the dpid
495 * @param segmentationId the segmentation id
496 * @param srcMac the source mac address.
497 * @param portSecurityRule the security rule in the SG
498 * @param dstAddress the source IP address
499 * @param write add or delete
500 * @param protoPortMatchPriority the protocol match priority
502 private void egressAclIcmpV4(Long dpidLong, String segmentationId, String srcMac,
503 NeutronSecurityRule portSecurityRule, String dstAddress,
504 boolean write, Integer protoPortMatchPriority) {
506 MatchBuilder matchBuilder = new MatchBuilder();
507 String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
508 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
509 /*Custom ICMP Match */
510 if (portSecurityRule.getSecurityRulePortMin() != null
511 && portSecurityRule.getSecurityRulePortMax() != null) {
512 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
513 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
514 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
515 portSecurityRule.getSecurityRulePortMin().shortValue(),
516 portSecurityRule.getSecurityRulePortMax().shortValue());
518 /* All ICMP Match */ // We are getting from neutron NULL for both min and max
519 flowId = flowId + "all" + "_" ;
520 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
522 if (null != dstAddress) {
523 flowId = flowId + dstAddress;
524 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
525 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
526 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
527 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
528 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
529 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
530 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
533 flowId = flowId + "_Permit";
534 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
535 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
536 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
537 addInstructionWithConntrackCommit(flowBuilder, false);
538 syncFlow(flowBuilder ,nodeBuilder, write);
542 * Creates a icmpv6 egress match with src macaddress. If dest address is specified
543 * destination specific match will be created. Otherwise a match with a
544 * CIDR will be created.
545 * @param dpidLong the dpid
546 * @param segmentationId the segmentation id
547 * @param srcMac the source mac address.
548 * @param portSecurityRule the security rule in the SG
549 * @param dstAddress the source IP address
550 * @param write add or delete
551 * @param protoPortMatchPriority the protocol match priority
553 private void egressAclIcmpV6(Long dpidLong, String segmentationId, String srcMac,
554 NeutronSecurityRule portSecurityRule, String dstAddress,
555 boolean write, Integer protoPortMatchPriority) {
557 MatchBuilder matchBuilder = new MatchBuilder();
558 String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
559 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
561 /*Custom ICMP Match */
562 if (portSecurityRule.getSecurityRulePortMin() != null
563 && portSecurityRule.getSecurityRulePortMax() != null) {
564 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
565 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
566 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
567 portSecurityRule.getSecurityRulePortMin().shortValue(),
568 portSecurityRule.getSecurityRulePortMax().shortValue());
570 /* All ICMP Match */ // We are getting from neutron NULL for both min and max
571 flowId = flowId + "all" + "_" ;
572 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
574 if (null != dstAddress) {
575 flowId = flowId + dstAddress;
576 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
577 MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
578 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
579 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
580 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
581 new Ipv6Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
583 flowId = flowId + "_Permit";
584 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
585 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
586 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
587 addInstructionWithConntrackCommit(flowBuilder, false);
588 syncFlow(flowBuilder ,nodeBuilder, write);
592 * Creates a egress match with src macaddress. If dest address is specified
593 * destination specific match will be created. Otherwise a match with a
594 * CIDR will be created.
595 * @param dpidLong the dpid
596 * @param segmentationId the segmentation id
597 * @param srcMac the source mac address.
598 * @param portSecurityRule the security rule in the SG
599 * @param dstAddress the source IP address
600 * @param write add or delete
601 * @param protoPortMatchPriority the protocol match priroty
603 private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
604 NeutronSecurityRule portSecurityRule, String dstAddress,
605 boolean write, Integer protoPortMatchPriority) {
606 boolean portRange = false;
607 MatchBuilder matchBuilder = new MatchBuilder();
608 String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
609 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
611 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,srcMac,null);
613 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,srcMac,null,MatchUtils.ETHERTYPE_IPV4);
616 /* Custom UDP Match */
617 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
618 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
619 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
620 portSecurityRule.getSecurityRulePortMin());
623 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
624 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
625 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
626 + portSecurityRule.getSecurityRulePortMax() + "_";
627 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
632 if (null != dstAddress) {
633 flowId = flowId + dstAddress;
635 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,null,
636 MatchUtils.iPv6PrefixFromIPv6Address(dstAddress));
638 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
639 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
641 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
642 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
644 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder, null,
645 new Ipv6Prefix(portSecurityRule
646 .getSecurityRuleRemoteIpPrefix()));
648 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
649 new Ipv4Prefix(portSecurityRule
650 .getSecurityRuleRemoteIpPrefix()));
653 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
655 Map<Integer, Integer> portMaskMap = MatchUtils
656 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
657 portSecurityRule.getSecurityRulePortMax());
658 for (Integer port: portMaskMap.keySet()) {
659 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
660 rangeflowId = rangeflowId + "_Permit";
661 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
662 0, port, portMaskMap.get(port));
663 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
664 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
665 matchBuilder, getTable());
666 addInstructionWithConntrackCommit(flowBuilder, false);
667 syncFlow(flowBuilder ,nodeBuilder, write);
670 flowId = flowId + "_Permit";
671 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
672 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
673 matchBuilder, getTable());
674 addInstructionWithConntrackCommit(flowBuilder, false);
675 syncFlow(flowBuilder ,nodeBuilder, write);
680 * Adds flow to allow any DHCP client traffic.
682 * @param dpidLong the dpid
683 * @param write whether to write or delete the flow
684 * @param localPort the local port.
685 * @param priority the priority
687 private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
688 boolean write, long localPort, Integer priority) {
689 String flowName = "Egress_DHCP_Client" + "_Permit_";
690 MatchBuilder matchBuilder = new MatchBuilder();
691 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
692 MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT);
693 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
694 addPipelineInstruction(flowBuilder, null, false);
695 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
696 syncFlow(flowBuilder ,nodeBuilder, write);
700 * Adds flow to allow any DHCP IPv6 client traffic.
702 * @param dpidLong the dpid
703 * @param write whether to write or delete the flow
704 * @param localPort the local port
705 * @param priority the priority
707 private void egressAclDhcpv6AllowClientTrafficFromVm(Long dpidLong,
708 boolean write, long localPort, Integer priority) {
709 String flowName = "Egress_DHCPv6_Client" + "_Permit_";
710 MatchBuilder matchBuilder = new MatchBuilder();
711 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
712 MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_DESTINATION_PORT, DHCPV6_SOURCE_PORT);
713 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
714 addPipelineInstruction(flowBuilder, null, false);
715 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
716 syncFlow(flowBuilder ,nodeBuilder, write);
720 * Adds rule to prevent DHCP spoofing by the vm attached to the port.
722 * @param dpidLong the dpid
723 * @param localPort the local port
724 * @param write is write or delete
725 * @param priority the priority
727 private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
728 boolean write, Integer priority) {
729 String flowName = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
730 MatchBuilder matchBuilder = new MatchBuilder();
731 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
732 MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT);
733 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
734 addPipelineInstruction(flowBuilder, null, true);
735 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
736 syncFlow(flowBuilder ,nodeBuilder, write);
740 * Adds rule to prevent DHCPv6 spoofing by the vm attached to the port.
742 * @param dpidLong the dpid
743 * @param localPort the local port
744 * @param write is write or delete
745 * @param priority the priority
747 private void egressAclDhcpv6DropServerTrafficfromVm(Long dpidLong, long localPort,
748 boolean write, Integer priority) {
750 String flowName = "Egress_DHCPv6_Server" + "_" + localPort + "_DROP_";
751 MatchBuilder matchBuilder = new MatchBuilder();
752 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
753 MatchUtils.createDhcpv6Match(matchBuilder, DHCPV6_SOURCE_PORT, DHCPV6_DESTINATION_PORT);
754 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
755 addPipelineInstruction(flowBuilder, null, true);
756 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
757 syncFlow(flowBuilder ,nodeBuilder, write);
761 * Adds rule to check legitimate ip/mac pair for each packet from the vm.
763 * @param dpidLong the dpid
764 * @param localPort the local port
765 * @param srcIp the vm ip address
766 * @param attachedMac the vm mac address
767 * @param priority the priority
768 * @param write is write or delete
770 private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
771 String attachedMac, String srcIp,
772 Integer priority, boolean write) {
773 MatchBuilder matchBuilder = new MatchBuilder();
774 MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
775 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
776 LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
777 String flowName = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
778 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
779 addPipelineInstruction(flowBuilder, null, false);
780 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
781 syncFlow(flowBuilder ,nodeBuilder, write);
785 * Adds rule to check legitimate ip/mac pair for each packet from the vm.
787 * @param dpidLong the dpid
788 * @param localPort the local port
789 * @param srcIp the vm ip address
790 * @param attachedMac the vm mac address
791 * @param priority the priority
792 * @param write is write or delete
794 private void egressAclAllowTrafficFromVmIpV6MacPair(Long dpidLong, long localPort,
795 String attachedMac, String srcIp,
796 Integer priority, boolean write) {
797 MatchBuilder matchBuilder = new MatchBuilder();
798 MatchUtils.createSrcL3Ipv6MatchWithMac(matchBuilder, new Ipv6Prefix(srcIp),new MacAddress(attachedMac));
799 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
800 LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
801 String flowName = "Egress_Allow_VM_IPv6_MAC" + "_" + localPort + attachedMac + "_Permit_";
802 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
803 addPipelineInstruction(flowBuilder, null, false);
804 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
805 syncFlow(flowBuilder ,nodeBuilder, write);
808 private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
809 if (securityServicesManager.isConntrackEnabled()) {
810 MatchUtils.addCtState(matchBuilder, state, mask );
815 private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
816 InstructionBuilder instructionBuilder = null;
817 if (securityServicesManager.isConntrackEnabled()) {
818 Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
819 instructionBuilder = InstructionUtils
820 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
822 return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
825 private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
826 InstructionBuilder instructionBuilder = null;
827 if (securityServicesManager.isConntrackEnabled()) {
828 Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
830 instructionBuilder = InstructionUtils
831 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
832 List<Instruction> instructionsList = Lists.newArrayList();
833 instructionsList.add(instructionBuilder.build());
834 InstructionsBuilder isb = new InstructionsBuilder();
835 isb.setInstruction(instructionsList);
836 flowBuilder.setInstructions(isb.build());
841 private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder ,
842 InstructionBuilder instructionBuilder,boolean isDrop) {
843 InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
844 List<Instruction> instructionsList = Lists.newArrayList();
845 instructionsList.add(pipeLineIndstructionBuilder.build());
846 if (null != instructionBuilder) {
847 instructionsList.add(instructionBuilder.build());
849 InstructionsBuilder isb = new InstructionsBuilder();
850 isb.setInstruction(instructionsList);
851 flowBuilder.setInstructions(isb.build());
855 private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
856 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
858 InstructionUtils.createDropInstructions(ib);
861 List<Instruction> instructionsList = Lists.newArrayList();
862 ib.setKey(new InstructionKey(0));
863 instructionsList.add(ib.build());
867 * Add or remove flow to the node.
868 * @param flowBuilder the flow builder
869 * @param nodeBuilder the node builder
870 * @param write whether it is a write
872 private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
875 writeFlow(flowBuilder, nodeBuilder);
877 removeFlow(flowBuilder, nodeBuilder);
883 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
884 super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
885 securityServicesManager =
886 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
887 securityGroupCacheManger =
888 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
892 public void setDependencies(Object impl) {}