2 * Copyright (c) 2014, 2015 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.ovsdb.openstack.netvirt.providers.openflow13.services;
11 import com.google.common.collect.Lists;
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.ActionUtils;
24 import org.opendaylight.ovsdb.utils.mdsal.openflow.FlowUtils;
25 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
26 import org.opendaylight.ovsdb.utils.mdsal.openflow.MatchUtils;
27 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefix;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpPrefixBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpSourceHardwareAddressBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
52 import org.osgi.framework.BundleContext;
53 import org.osgi.framework.ServiceReference;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
57 import java.math.BigInteger;
58 import java.net.Inet4Address;
59 import java.net.Inet6Address;
60 import java.net.InetAddress;
61 import java.net.UnknownHostException;
62 import java.util.List;
65 public class EgressAclService extends AbstractServiceInstance implements EgressAclProvider, ConfigInterface {
67 private static final Logger LOG = LoggerFactory.getLogger(EgressAclService.class);
68 private volatile SecurityServicesManager securityServicesManager;
69 private volatile SecurityGroupCacheManger securityGroupCacheManger;
70 private static final int DHCP_SOURCE_PORT = 67;
71 private static final int DHCP_DESTINATION_PORT = 68;
72 private static final String HOST_MASK = "/32";
73 private static final int PORT_RANGE_MIN = 1;
74 private static final int PORT_RANGE_MAX = 65535;
76 public EgressAclService() {
77 super(Service.EGRESS_ACL);
80 public EgressAclService(Service service) {
85 public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac, long localPort,
86 NeutronSecurityGroup securityGroup, String portUuid, boolean write) {
88 LOG.trace("programPortSecurityGroup: neutronSecurityGroup: {} ", securityGroup);
89 if (securityGroup == null || securityGroup.getSecurityRules() == null) {
93 List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
94 /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
95 for (NeutronSecurityRule portSecurityRule : portSecurityList) {
98 * Neutron Port Security Acl "egress" and "IPv4"
99 * Check that the base conditions for flow based Port Security are true:
100 * Port Security Rule Direction ("egress") and Protocol ("IPv4")
101 * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
102 * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
106 if (portSecurityRule == null ||
107 portSecurityRule.getSecurityRuleEthertype() == null ||
108 portSecurityRule.getSecurityRuleDirection() == null) {
112 if ("IPv4".equals(portSecurityRule.getSecurityRuleEthertype())
113 && portSecurityRule.getSecurityRuleDirection().equals("egress")) {
114 LOG.debug("programPortSecurityGroup: Acl Rule matching IPv4 and ingress is: {} ", portSecurityRule);
115 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
116 //Remote Security group is selected
117 List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
118 .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
119 if (null != remoteSrcAddressList) {
120 for (Neutron_IPs vmIp :remoteSrcAddressList ) {
122 programPortSecurityRule(dpid, segmentationId, attachedMac,
123 localPort, portSecurityRule, vmIp, write);
126 securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
128 securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
133 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
134 portSecurityRule, null, write);
137 securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
139 securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
146 public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
147 long localPort, NeutronSecurityRule portSecurityRule,
148 Neutron_IPs vmIp, boolean write) {
149 if (null == portSecurityRule.getSecurityRuleProtocol()) {
150 /* TODO Rework on the priority values */
151 egressAclIPv4(dpid, segmentationId, attachedMac,
152 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
154 String ipaddress = null;
156 ipaddress = vmIp.getIpAddress();
158 InetAddress address = InetAddress.getByName(ipaddress);
159 // TODO: remove this when ipv6 support is implemented
160 if (address instanceof Inet6Address) {
161 LOG.debug("Skipping ip address {}. IPv6 support is not yet implemented.", address);
164 } catch (UnknownHostException e) {
165 LOG.warn("Invalid ip address {}", ipaddress, e);
170 if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
171 String prefixStr = portSecurityRule.getSecurityRuleRemoteIpPrefix();
173 IpPrefix ipPrefix = IpPrefixBuilder.getDefaultInstance(prefixStr);
174 // TODO: remove this when ipv6 support is implemented
175 if (ipPrefix.getIpv6Prefix() != null) {
176 LOG.debug("Skipping ip prefix {}. IPv6 support is not yet implemented.", ipPrefix);
179 } catch (IllegalArgumentException e) {
180 LOG.warn("Invalid ip prefix {}", prefixStr, e);
185 switch (portSecurityRule.getSecurityRuleProtocol()) {
187 LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
188 egressAclTcp(dpid, segmentationId, attachedMac,
189 portSecurityRule,ipaddress, write,
190 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
193 LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
194 egressAclUdp(dpid, segmentationId, attachedMac,
195 portSecurityRule, ipaddress, write,
196 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
198 case MatchUtils.ICMP:
199 LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
200 egressAclIcmp(dpid, segmentationId, attachedMac,
201 portSecurityRule, ipaddress,write,
202 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
205 LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other " +
206 "protocol = ", portSecurityRule.getSecurityRuleProtocol());
207 egressOtherProtocolAclHandler(dpid, segmentationId, attachedMac,
208 portSecurityRule, ipaddress, write,
209 Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
215 private void egressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String srcMac,
216 NeutronSecurityRule portSecurityRule, String dstAddress,
217 boolean write, Integer priority) {
218 MatchBuilder matchBuilder = new MatchBuilder();
219 String flowId = "Egress_Other_" + segmentationId + "_" + srcMac + "_";
220 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
224 Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
225 proto = protocol.shortValue();
226 flowId = flowId + proto;
227 } catch (NumberFormatException e) {
228 LOG.error("Protocol vlaue conversion failure", e);
230 matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
232 if (null != dstAddress) {
233 flowId = flowId + dstAddress;
234 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
235 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
237 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
238 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
239 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
240 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
242 flowId = flowId + "_Permit";
243 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
244 syncFlow(flowId, nodeBuilder, matchBuilder, priority, write, false, securityServicesManager.isConntrackEnabled());
248 public void programFixedSecurityGroup(Long dpid, String segmentationId, String attachedMac,
249 long localPort, List<Neutron_IPs> srcAddressList,
250 boolean isLastPortinBridge, boolean isComputePort ,boolean write) {
251 // If it is the only port in the bridge add the rule to allow any DHCP client traffic
252 //if (isLastPortinBridge) {
253 egressAclDhcpAllowClientTrafficFromVm(dpid, write, Constants.PROTO_DHCP_CLIENT_TRAFFIC_MATCH_PRIORITY);
256 programArpRule(dpid, segmentationId, localPort, attachedMac, write);
257 if (securityServicesManager.isConntrackEnabled()) {
258 programEgressAclFixedConntrackRule(dpid, segmentationId, localPort, attachedMac, write);
260 // add rule to drop the DHCP server traffic originating from the vm.
261 egressAclDhcpDropServerTrafficfromVm(dpid, localPort, write,
262 Constants.PROTO_DHCP_CLIENT_SPOOF_MATCH_PRIORITY_DROP);
263 //Adds rule to check legitimate ip/mac pair for each packet from the vm
264 for (Neutron_IPs srcAddress : srcAddressList) {
266 InetAddress address = InetAddress.getByName(srcAddress.getIpAddress());
267 if (address instanceof Inet4Address) {
268 String addressWithPrefix = srcAddress.getIpAddress() + HOST_MASK;
269 egressAclAllowTrafficFromVmIpMacPair(dpid, localPort, attachedMac, addressWithPrefix,
270 Constants.PROTO_VM_IP_MAC_MATCH_PRIORITY,write);
272 LOG.debug("Skipping IPv6 address {}. IPv6 support is not yet implemented.",
273 srcAddress.getIpAddress());
275 } catch(UnknownHostException e) {
276 LOG.warn("Invalid IP address {}", srcAddress.getIpAddress());
282 private void programArpRule(Long dpid, String segmentationId, long localPort, String attachedMac, boolean write) {
283 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
284 MatchBuilder matchBuilder = new MatchBuilder();
285 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
286 String flowId = "Egress_ARP_" + segmentationId + "_" + localPort + "_";
288 EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
289 EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
290 ethTypeBuilder.setType(new EtherType(0x0806L));
291 ethernetType.setEthernetType(ethTypeBuilder.build());
292 matchBuilder.setEthernetMatch(ethernetType.build());
294 ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
295 ArpSourceHardwareAddressBuilder arpSrc = new ArpSourceHardwareAddressBuilder();
296 arpSrc.setAddress(new MacAddress(attachedMac));
297 arpDstMatch.setArpSourceHardwareAddress(arpSrc.build());
298 matchBuilder.setLayer3Match(arpDstMatch.build());
300 syncFlow(flowId, nodeBuilder, matchBuilder, Constants.PROTO_MATCH_PRIORITY, write, false, false);
303 private void programEgressAclFixedConntrackRule(Long dpid,
304 String segmentationId, long localPort, String attachMac, boolean write) {
306 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
307 programConntrackUntrackRule(nodeName, segmentationId, localPort,attachMac,
308 Constants.CT_STATE_UNTRACKED_PRIORITY, write );
309 programConntrackTrackedPlusEstRule(nodeName, dpid, segmentationId, localPort,
310 Constants.CT_STATE_TRACKED_EST_PRIORITY, write );
311 programConntrackNewDropRule(nodeName, dpid, segmentationId, localPort,
312 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
313 LOG.info("programEgressAclFixedConntrackRule : default connection tracking rule are added.");
314 } catch (Exception e) {
315 LOG.error("Failed to add default conntrack rules : " , e);
319 private void programConntrackUntrackRule(String nodeName, String segmentationId,
320 long localPort, String attachMac, Integer priority, boolean write) {
321 MatchBuilder matchBuilder = new MatchBuilder();
322 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
323 String flowName = "Egress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
324 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder, attachMac, null);
325 matchBuilder = MatchUtils.addCtState(matchBuilder,0x00,0X80);
326 FlowBuilder flowBuilder = new FlowBuilder();
327 flowBuilder.setMatch(matchBuilder.build());
328 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
330 InstructionBuilder ib = new InstructionBuilder();
331 List<Instruction> instructionsList = Lists.newArrayList();
332 InstructionsBuilder isb = new InstructionsBuilder();
333 ActionBuilder ab = new ActionBuilder();
334 ab.setAction(ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0));
335 // 0xff means no table, 0x0 is table = 0
337 ab.setKey(new ActionKey(0));
338 List<Action> actionList = Lists.newArrayList();
339 actionList.add(ab.build());
340 ApplyActionsBuilder aab = new ApplyActionsBuilder();
341 aab.setAction(actionList);
343 ib.setKey(new InstructionKey(0));
344 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
345 instructionsList.add(ib.build());
346 isb.setInstruction(instructionsList);
347 flowBuilder.setInstructions(isb.build());
348 writeFlow(flowBuilder, nodeBuilder);
349 LOG.info("EGRESS:default programConntrackUntrackRule() flows are written");
351 removeFlow(flowBuilder, nodeBuilder);
355 private void programConntrackTrackedPlusEstRule(String nodeName, Long dpid, String segmentationId,
356 long localPort,Integer priority, boolean write) {
357 MatchBuilder matchBuilder = new MatchBuilder();
358 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
359 String flowName = "Egress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
360 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpid, localPort);
361 matchBuilder = MatchUtils.addCtState(matchBuilder,0x82, 0x82);
362 FlowBuilder flowBuilder = new FlowBuilder();
363 flowBuilder.setMatch(matchBuilder.build());
364 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
366 InstructionBuilder ib = new InstructionBuilder();
367 List<Instruction> instructionsList = Lists.newArrayList();
368 InstructionsBuilder isb = new InstructionsBuilder();
369 // got to next table instruction
370 ib = this.getMutablePipelineInstructionBuilder();
372 ib.setKey(new InstructionKey(0));
373 instructionsList.add(ib.build());
374 isb.setInstruction(instructionsList);
375 flowBuilder.setInstructions(isb.build());
376 writeFlow(flowBuilder, nodeBuilder);
377 LOG.info("EGRESS:default programConntrackTrackedPlusEstRule() flows are written");
379 removeFlow(flowBuilder, nodeBuilder);
383 private void programConntrackNewDropRule(String nodeName, Long dpid, String segmentationId,
384 long localPort, Integer priority, boolean write) {
385 MatchBuilder matchBuilder = new MatchBuilder();
386 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
387 String flowName = "Egress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
388 matchBuilder = MatchUtils.createInPortMatch(matchBuilder, dpid, localPort);
389 matchBuilder = MatchUtils.addCtState(matchBuilder,0x01, 0x01);
390 FlowBuilder flowBuilder = new FlowBuilder();
391 flowBuilder.setMatch(matchBuilder.build());
392 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
394 InstructionBuilder ib = new InstructionBuilder();
395 InstructionsBuilder isb = new InstructionsBuilder();
396 List<Instruction> instructions = Lists.newArrayList();
397 InstructionUtils.createDropInstructions(ib);
399 ib.setKey(new InstructionKey(0));
400 instructions.add(ib.build());
401 isb.setInstruction(instructions);
402 LOG.debug("Instructions contain: {}", ib.getInstruction());
403 flowBuilder.setInstructions(isb.build());
404 writeFlow(flowBuilder, nodeBuilder);
405 LOG.info("EGRESS:default programConntrackNewDropRule() flows are written");
407 removeFlow(flowBuilder, nodeBuilder);
412 * Allows IPv4 packet egress from the src mac address.
413 * @param dpidLong the dpid
414 * @param segmentationId the segementation id
415 * @param srcMac the src mac address
416 * @param write add or remove
417 * @param protoPortMatchPriority the protocol match priority.
419 private void egressAclIPv4(Long dpidLong, String segmentationId, String srcMac,
420 boolean write, Integer protoPortMatchPriority ) {
421 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
422 MatchBuilder matchBuilder = new MatchBuilder();
423 String flowId = "Egress_IP" + segmentationId + "_" + srcMac + "_Permit_";
424 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
425 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
429 * Creates a egress match with src macaddress. If dest address is specified
430 * destination specific match will be created. Otherwise a match with a
431 * CIDR will be created.
432 * @param dpidLong the dpid
433 * @param segmentationId the segmentation id
434 * @param srcMac the source mac address.
435 * @param portSecurityRule the security rule in the SG
436 * @param dstAddress the destination IP address
437 * @param write add or delete
438 * @param protoPortMatchPriority the protocol match priroty
440 private void egressAclTcp(Long dpidLong, String segmentationId, String srcMac,
441 NeutronSecurityRule portSecurityRule, String dstAddress,
442 boolean write, Integer protoPortMatchPriority) {
443 boolean portRange = false;
444 MatchBuilder matchBuilder = new MatchBuilder();
445 String flowId = "Egress_TCP_" + segmentationId + "_" + srcMac + "_";
446 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
448 /* Custom TCP Match */
449 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
450 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
451 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
452 portSecurityRule.getSecurityRulePortMin());
455 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
456 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
457 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
458 + portSecurityRule.getSecurityRulePortMax() + "_";
459 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
464 if (null != dstAddress) {
465 flowId = flowId + dstAddress;
466 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
467 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
469 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
470 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
471 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
472 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
474 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
476 Map<Integer, Integer> portMaskMap = MatchUtils
477 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
478 portSecurityRule.getSecurityRulePortMax());
479 for (Integer port: portMaskMap.keySet()) {
480 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
481 rangeflowId = rangeflowId + "_Permit";
482 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
483 0, port, portMaskMap.get(port));
484 syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
487 flowId = flowId + "_Permit";
488 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
493 * Creates a egress match with src macaddress. If dest address is specified
494 * destination specific match will be created. Otherwise a match with a
495 * CIDR will be created.
496 * @param dpidLong the dpid
497 * @param segmentationId the segmentation id
498 * @param srcMac the source mac address.
499 * @param portSecurityRule the security rule in the SG
500 * @param dstAddress the source IP address
501 * @param write add or delete
502 * @param protoPortMatchPriority the protocol match priority
504 private void egressAclIcmp(Long dpidLong, String segmentationId, String srcMac,
505 NeutronSecurityRule portSecurityRule, String dstAddress,
506 boolean write, Integer protoPortMatchPriority) {
508 MatchBuilder matchBuilder = new MatchBuilder();
509 String flowId = "Egress_ICMP_" + segmentationId + "_" + srcMac + "_";
510 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
511 /*Custom ICMP Match */
512 if (portSecurityRule.getSecurityRulePortMin() != null &&
513 portSecurityRule.getSecurityRulePortMax() != null) {
514 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
515 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
516 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
517 portSecurityRule.getSecurityRulePortMin().shortValue(),
518 portSecurityRule.getSecurityRulePortMax().shortValue());
520 /* All ICMP Match */ // We are getting from neutron NULL for both min and max
521 flowId = flowId + "all" + "_" ;
522 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder, MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
524 if (null != dstAddress) {
525 flowId = flowId + dstAddress;
526 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
527 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
528 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
529 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
530 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
531 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
532 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()));
535 flowId = flowId + "_Permit";
536 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
537 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
541 * Creates a egress match with src macaddress. If dest address is specified
542 * destination specific match will be created. Otherwise a match with a
543 * CIDR will be created.
544 * @param dpidLong the dpid
545 * @param segmentationId the segmentation id
546 * @param srcMac the source mac address.
547 * @param portSecurityRule the security rule in the SG
548 * @param dstAddress the source IP address
549 * @param write add or delete
550 * @param protoPortMatchPriority the protocol match priroty
552 private void egressAclUdp(Long dpidLong, String segmentationId, String srcMac,
553 NeutronSecurityRule portSecurityRule, String dstAddress,
554 boolean write, Integer protoPortMatchPriority) {
555 boolean portRange = false;
556 MatchBuilder matchBuilder = new MatchBuilder();
557 String flowId = "Egress_UDP_" + segmentationId + "_" + srcMac + "_";
558 matchBuilder = MatchUtils.createEtherMatchWithType(matchBuilder,srcMac,null);
560 /* Custom UDP Match */
561 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
562 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
563 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
564 portSecurityRule.getSecurityRulePortMin());
567 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
568 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
569 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
570 + portSecurityRule.getSecurityRulePortMax() + "_";
571 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
576 if (null != dstAddress) {
577 flowId = flowId + dstAddress;
578 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,null,
579 MatchUtils.iPv4PrefixFromIPv4Address(dstAddress));
580 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
581 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
582 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder, null,
583 new Ipv4Prefix(portSecurityRule
584 .getSecurityRuleRemoteIpPrefix()));
586 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
588 Map<Integer, Integer> portMaskMap = MatchUtils
589 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
590 portSecurityRule.getSecurityRulePortMax());
591 for (Integer port: portMaskMap.keySet()) {
592 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
593 rangeflowId = rangeflowId + "_Permit";
594 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
595 0, port, portMaskMap.get(port));
596 syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
599 flowId = flowId + "_Permit";
600 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
604 public void egressACLDefaultTcpDrop(Long dpidLong, String segmentationId, String attachedMac,
605 int priority, boolean write) {
606 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
607 FlowBuilder flowBuilder = new FlowBuilder();
608 String flowName = "TCP_Syn_Egress_Default_Drop_" + segmentationId + "_" + attachedMac;
609 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
611 MatchBuilder matchBuilder = new MatchBuilder();
612 MatchUtils.createSmacTcpPortWithFlagMatch(matchBuilder, attachedMac, Constants.TCP_SYN, segmentationId);
613 flowBuilder.setMatch(matchBuilder.build());
616 InstructionBuilder ib = new InstructionBuilder();
617 InstructionsBuilder isb = new InstructionsBuilder();
618 List<Instruction> instructions = Lists.newArrayList();
620 InstructionUtils.createDropInstructions(ib);
622 ib.setKey(new InstructionKey(0));
623 instructions.add(ib.build());
624 isb.setInstruction(instructions);
626 flowBuilder.setInstructions(isb.build());
627 writeFlow(flowBuilder, nodeBuilder);
629 removeFlow(flowBuilder, nodeBuilder);
633 public void egressACLTcpPortWithPrefix(Long dpidLong, String segmentationId, String attachedMac, boolean write,
634 Integer securityRulePortMin, String securityRuleIpPrefix,
636 PortNumber tcpPort = new PortNumber(securityRulePortMin);
637 Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
639 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
640 FlowBuilder flowBuilder = new FlowBuilder();
641 String flowName = "UcastEgress_" + segmentationId + "_" + attachedMac
642 + securityRulePortMin + securityRuleIpPrefix;
643 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
645 MatchBuilder matchBuilder = new MatchBuilder();
646 MatchUtils.createSmacTcpSynDstIpPrefixTcpPort(matchBuilder, new MacAddress(attachedMac),
647 tcpPort, Constants.TCP_SYN, segmentationId, srcIpPrefix);
648 flowBuilder.setMatch(matchBuilder.build());
651 InstructionsBuilder isb = new InstructionsBuilder();
652 List<Instruction> instructionsList = Lists.newArrayList();
654 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
656 ib.setKey(new InstructionKey(0));
657 instructionsList.add(ib.build());
658 isb.setInstruction(instructionsList);
660 flowBuilder.setInstructions(isb.build());
661 writeFlow(flowBuilder, nodeBuilder);
663 removeFlow(flowBuilder, nodeBuilder);
667 public void egressAllowProto(Long dpidLong, String segmentationId, String attachedMac, boolean write,
668 String securityRuleProtcol, Integer priority) {
669 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
670 FlowBuilder flowBuilder = new FlowBuilder();
671 String flowName = "EgressAllProto_" + segmentationId + "_"
672 + attachedMac + "_AllowEgressTCPSyn_" + securityRuleProtcol;
673 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
675 MatchBuilder matchBuilder = new MatchBuilder();
676 MatchUtils.createDmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null);
677 MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
678 flowBuilder.setMatch(matchBuilder.build());
681 InstructionsBuilder isb = new InstructionsBuilder();
682 List<Instruction> instructionsList = Lists.newArrayList();
684 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
686 ib.setKey(new InstructionKey(0));
687 instructionsList.add(ib.build());
688 isb.setInstruction(instructionsList);
690 flowBuilder.setInstructions(isb.build());
691 writeFlow(flowBuilder, nodeBuilder);
693 removeFlow(flowBuilder, nodeBuilder);
697 public void egressACLPermitAllProto(Long dpidLong, String segmentationId, String attachedMac,
698 boolean write, String securityRuleIpPrefix, Integer priority) {
699 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
700 FlowBuilder flowBuilder = new FlowBuilder();
701 String flowName = "Egress_Proto_ACL" + segmentationId + "_" +
702 attachedMac + "_Permit_" + securityRuleIpPrefix;
703 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
705 MatchBuilder matchBuilder = new MatchBuilder();
706 MatchUtils.createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId));
707 if (securityRuleIpPrefix != null) {
708 Ipv4Prefix srcIpPrefix = new Ipv4Prefix(securityRuleIpPrefix);
709 MatchUtils.createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, srcIpPrefix);
711 MatchUtils.createSmacIpTcpSynMatch(matchBuilder, new MacAddress(attachedMac), null, null);
713 flowBuilder.setMatch(matchBuilder.build());
716 InstructionsBuilder isb = new InstructionsBuilder();
717 List<Instruction> instructionsList = Lists.newArrayList();
719 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
721 ib.setKey(new InstructionKey(0));
722 instructionsList.add(ib.build());
723 isb.setInstruction(instructionsList);
725 flowBuilder.setInstructions(isb.build());
726 writeFlow(flowBuilder, nodeBuilder);
728 removeFlow(flowBuilder, nodeBuilder);
732 public void egressACLTcpSyn(Long dpidLong, String segmentationId, String attachedMac, boolean write,
733 Integer securityRulePortMin, Integer priority) {
734 PortNumber tcpPort = new PortNumber(securityRulePortMin);
736 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
737 FlowBuilder flowBuilder = new FlowBuilder();
738 String flowName = "Ucast_this.getTable()" + segmentationId + "_" + attachedMac + securityRulePortMin;
739 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
741 MatchBuilder matchBuilder = new MatchBuilder();
742 MatchUtils.createSmacTcpSyn(matchBuilder, attachedMac, tcpPort, Constants.TCP_SYN, segmentationId);
743 flowBuilder.setMatch(matchBuilder.build());
746 // Instantiate the Builders for the OF Actions and Instructions
747 InstructionsBuilder isb = new InstructionsBuilder();
748 List<Instruction> instructionsList = Lists.newArrayList();
750 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
752 ib.setKey(new InstructionKey(0));
753 instructionsList.add(ib.build());
754 isb.setInstruction(instructionsList);
756 flowBuilder.setInstructions(isb.build());
757 writeFlow(flowBuilder, nodeBuilder);
759 removeFlow(flowBuilder, nodeBuilder);
764 * Adds flow to allow any DHCP client traffic.
766 * @param dpidLong the dpid
767 * @param write whether to write or delete the flow
768 * @param priority the priority
770 private void egressAclDhcpAllowClientTrafficFromVm(Long dpidLong,
771 boolean write, Integer priority) {
772 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
773 String flowName = "Egress_DHCP_Client" + "_Permit_";
774 MatchBuilder matchBuilder = new MatchBuilder();
775 MatchUtils.createDhcpMatch(matchBuilder, DHCP_DESTINATION_PORT, DHCP_SOURCE_PORT);
776 syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false, false);
780 * Adds rule to prevent DHCP spoofing by the vm attached to the port.
782 * @param dpidLong the dpid
783 * @param localPort the local port
784 * @param write is write or delete
785 * @param priority the priority
787 private void egressAclDhcpDropServerTrafficfromVm(Long dpidLong, long localPort,
788 boolean write, Integer priority) {
790 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
791 String flowName = "Egress_DHCP_Server" + "_" + localPort + "_DROP_";
792 MatchBuilder matchBuilder = new MatchBuilder();
793 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
794 MatchUtils.createDhcpMatch(matchBuilder, DHCP_SOURCE_PORT, DHCP_DESTINATION_PORT);
795 syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, true, false);
799 * Adds rule to check legitimate ip/mac pair for each packet from the vm.
801 * @param dpidLong the dpid
802 * @param localPort the local port
803 * @param srcIp the vm ip address
804 * @param attachedMac the vm mac address
805 * @param priority the priority
806 * @param write is write or delete
808 private void egressAclAllowTrafficFromVmIpMacPair(Long dpidLong, long localPort,
809 String attachedMac, String srcIp,
810 Integer priority, boolean write) {
811 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
812 String flowName = "Egress_Allow_VM_IP_MAC" + "_" + localPort + attachedMac + "_Permit_";
813 MatchBuilder matchBuilder = new MatchBuilder();
814 MatchUtils.createSrcL3Ipv4MatchWithMac(matchBuilder, new Ipv4Prefix(srcIp),new MacAddress(attachedMac));
815 MatchUtils.createInPortMatch(matchBuilder, dpidLong, localPort);
816 LOG.debug("egressAclAllowTrafficFromVmIpMacPair: MatchBuilder contains: {}", matchBuilder);
817 syncFlow(flowName, nodeBuilder, matchBuilder, priority, write, false, false);
821 * Add or remove flow to the node.
823 * @param flowName the the flow id
824 * @param nodeBuilder the node builder
825 * @param matchBuilder the matchbuilder
826 * @param priority the protocol priority
827 * @param write whether it is a write
828 * @param drop whether it is a drop or forward
829 * @param isCtCommit commit the connection or CT to track
831 private void syncFlow(String flowName, NodeBuilder nodeBuilder,
832 MatchBuilder matchBuilder, Integer priority,
833 boolean write, boolean drop, boolean isCtCommit) {
834 MatchBuilder matchBuilder1 = matchBuilder;
836 matchBuilder1 = MatchUtils.addCtState(matchBuilder1,0x81, 0x81);
838 FlowBuilder flowBuilder = new FlowBuilder();
839 flowBuilder.setMatch(matchBuilder1.build());
840 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
843 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
844 InstructionBuilder ib1 = new InstructionBuilder();
845 ActionBuilder ab = new ActionBuilder();
846 ApplyActionsBuilder aab = new ApplyActionsBuilder();
848 InstructionUtils.createDropInstructions(ib);
851 ib.setKey(new InstructionKey(0));
852 InstructionsBuilder isb = new InstructionsBuilder();
853 List<Instruction> instructionsList = Lists.newArrayList();
854 instructionsList.add(ib.build());
856 LOG.info("Adding Conntarck rule, flowname = " + flowName);
857 ab.setAction(ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff));
859 ab.setKey(new ActionKey(0));
860 List<Action> actionList = Lists.newArrayList();
861 actionList.add(ab.build());
862 aab.setAction(actionList);
864 ib1.setKey(new InstructionKey(1));
865 ib1.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
866 instructionsList.add(ib1.build());
868 isb.setInstruction(instructionsList);
869 flowBuilder.setInstructions(isb.build());
870 writeFlow(flowBuilder, nodeBuilder);
872 removeFlow(flowBuilder, nodeBuilder);
877 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
878 super.setDependencies(bundleContext.getServiceReference(EgressAclProvider.class.getName()), this);
879 securityServicesManager =
880 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
881 securityGroupCacheManger =
882 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
886 public void setDependencies(Object impl) {}