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.IngressAclProvider;
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.Ipv6Prefix;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.EtherType;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.arp.match.fields.ArpTargetHardwareAddressBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.ethernet.match.fields.EthernetTypeBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.ArpMatchBuilder;
53 import org.osgi.framework.BundleContext;
54 import org.osgi.framework.ServiceReference;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
58 import java.math.BigInteger;
59 import java.net.Inet6Address;
60 import java.net.InetAddress;
61 import java.net.UnknownHostException;
62 import java.util.List;
65 public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
66 private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
67 private volatile SecurityServicesManager securityServicesManager;
68 private volatile SecurityGroupCacheManger securityGroupCacheManger;
69 private static final int PORT_RANGE_MIN = 1;
70 private static final int PORT_RANGE_MAX = 65535;
72 public IngressAclService() {
73 super(Service.INGRESS_ACL);
76 public IngressAclService(Service service) {
81 public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
82 long localPort, NeutronSecurityGroup securityGroup,
83 String portUuid, boolean write) {
85 LOG.trace("programPortSecurityGroup neutronSecurityGroup: {} ", securityGroup);
86 if (securityGroup == null || securityGroup.getSecurityRules() == null) {
90 List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
91 /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
92 for (NeutronSecurityRule portSecurityRule : portSecurityList) {
95 * Neutron Port Security Acl "ingress" and "IPv4"
96 * Check that the base conditions for flow based Port Security are true:
97 * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
98 * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
99 * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
103 if (portSecurityRule == null ||
104 portSecurityRule.getSecurityRuleEthertype() == null ||
105 portSecurityRule.getSecurityRuleDirection() == null) {
109 if ("ingress".equals(portSecurityRule.getSecurityRuleDirection())) {
110 LOG.debug("programPortSecurityGroup: Rule matching IP and ingress is: {} ", portSecurityRule);
111 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
112 //Remote Security group is selected
113 List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
114 .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
115 if (null != remoteSrcAddressList) {
116 for (Neutron_IPs vmIp :remoteSrcAddressList ) {
117 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
118 portSecurityRule, vmIp, write);
121 securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
123 securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
128 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
129 portSecurityRule, null, write);
132 securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
134 securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
141 public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
142 long localPort, NeutronSecurityRule portSecurityRule,
143 Neutron_IPs vmIp, boolean write) {
144 if (null == portSecurityRule.getSecurityRuleProtocol()) {
145 boolean isIpv6 = portSecurityRule.getSecurityRuleEthertype().equals("IPv6");
146 ingressAclIP(dpid, isIpv6, segmentationId, attachedMac,
147 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
149 String ipaddress = null;
151 ipaddress = vmIp.getIpAddress();
154 switch (portSecurityRule.getSecurityRuleProtocol()) {
156 LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
157 ingressAclTcp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
158 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
161 LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
162 ingressAclUdp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
163 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
165 case MatchUtils.ICMP:
166 case MatchUtils.ICMPV6:
167 LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
168 ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
169 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
172 LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other " +
173 "protocol = ", portSecurityRule.getSecurityRuleProtocol());
174 ingressOtherProtocolAclHandler(dpid, segmentationId, attachedMac, portSecurityRule,
175 null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
181 private void ingressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String dstMac,
182 NeutronSecurityRule portSecurityRule, String srcAddress,
183 boolean write, Integer protoPortMatchPriority) {
185 MatchBuilder matchBuilder = new MatchBuilder();
186 String flowId = "Ingress_Other_" + segmentationId + "_" + dstMac + "_";
187 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac);
190 Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
191 proto = protocol.shortValue();
192 flowId = flowId + proto;
193 } catch (NumberFormatException e) {
194 LOG.error("Protocol vlaue conversion failure", e);
196 matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
197 if (null != srcAddress) {
198 flowId = flowId + srcAddress;
199 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
200 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
201 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
202 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
203 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
204 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
206 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
207 flowId = flowId + "_Permit";
208 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
212 public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
213 long localPort, boolean isLastPortinSubnet,
214 boolean isComputePort, String attachMac, boolean write) {
215 //If this port is the only port in the compute node add the DHCP server rule.
216 if (isLastPortinSubnet && isComputePort ) {
217 ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
218 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
219 ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
220 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
223 if (securityServicesManager.isConntrackEnabled()) {
224 programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
226 programArpRule(dpid, segmentationId, localPort, attachMac, write);
230 private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
231 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
232 MatchBuilder matchBuilder = new MatchBuilder();
233 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
234 String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
235 EthernetMatchBuilder ethernetType = new EthernetMatchBuilder();
236 EthernetTypeBuilder ethTypeBuilder = new EthernetTypeBuilder();
237 ethTypeBuilder.setType(new EtherType(0x0806L));
238 ethernetType.setEthernetType(ethTypeBuilder.build());
239 matchBuilder.setEthernetMatch(ethernetType.build());
241 ArpMatchBuilder arpDstMatch = new ArpMatchBuilder();
242 ArpTargetHardwareAddressBuilder arpDst = new ArpTargetHardwareAddressBuilder();
243 arpDst.setAddress(new MacAddress(attachMac));
244 arpDstMatch.setArpTargetHardwareAddress(arpDst.build());
245 matchBuilder.setLayer3Match(arpDstMatch.build());
246 syncFlow(flowId, nodeBuilder, matchBuilder, Constants.PROTO_MATCH_PRIORITY, write, false, securityServicesManager.isConntrackEnabled());
249 private void programIngressAclFixedConntrackRule(Long dpid,
250 String segmentationId, String attachMac, long localPort, boolean write) {
252 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
253 programConntrackUntrackRule(nodeName, segmentationId, localPort, attachMac,
254 Constants.CT_STATE_UNTRACKED_PRIORITY, write );
255 programConntrackTrackedPlusEstRule(nodeName, segmentationId, localPort, attachMac,
256 Constants.CT_STATE_TRACKED_EST_PRIORITY, write );
257 programConntrackNewDropRule(nodeName, segmentationId, localPort, attachMac,
258 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
259 LOG.info("programIngressAclFixedConntrackRule : default connection tracking rule are added.");
260 } catch (Exception e) {
261 LOG.error("Failed to add default conntrack rules : " , e);
265 private void programConntrackUntrackRule(String nodeName, String segmentationId,
266 long localPort, String attachMac, Integer priority, boolean write) {
267 MatchBuilder matchBuilder = new MatchBuilder();
268 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
269 String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
270 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac);
271 matchBuilder = MatchUtils.addCtState(matchBuilder,0x00, 0x80);
272 FlowBuilder flowBuilder = new FlowBuilder();
273 flowBuilder.setMatch(matchBuilder.build());
274 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
276 InstructionBuilder ib = new InstructionBuilder();
277 List<Instruction> instructionsList = Lists.newArrayList();
278 InstructionsBuilder isb = new InstructionsBuilder();
279 ActionBuilder ab = new ActionBuilder();
280 ab.setAction(ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0));
281 // 0xff means no table, 0x0 is table = 0
282 // nxConntrackAction(Integer flags, Long zoneSrc,Integer conntrackZone, Short recircTable)
284 ab.setKey(new ActionKey(0));
285 List<Action> actionList = Lists.newArrayList();
286 actionList.add(ab.build());
287 ApplyActionsBuilder aab = new ApplyActionsBuilder();
288 aab.setAction(actionList);
291 ib.setKey(new InstructionKey(0));
292 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
293 instructionsList.add(ib.build());
294 isb.setInstruction(instructionsList);
295 flowBuilder.setInstructions(isb.build());
296 writeFlow(flowBuilder, nodeBuilder);
297 LOG.info("INGRESS:default programConntrackUntrackRule() flows are written");
299 removeFlow(flowBuilder, nodeBuilder);
303 private void programConntrackTrackedPlusEstRule(String nodeName, String segmentationId,
304 long localPort, String attachMac,Integer priority, boolean write) {
305 MatchBuilder matchBuilder = new MatchBuilder();
306 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
307 String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
308 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac);
309 matchBuilder = MatchUtils.addCtState(matchBuilder,0x82, 0x82);
310 FlowBuilder flowBuilder = new FlowBuilder();
311 flowBuilder.setMatch(matchBuilder.build());
312 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
314 InstructionBuilder ib = new InstructionBuilder();
315 List<Instruction> instructionsList = Lists.newArrayList();
316 InstructionsBuilder isb = new InstructionsBuilder();
318 ib = this.getMutablePipelineInstructionBuilder();
320 ib.setKey(new InstructionKey(0));
321 instructionsList.add(ib.build());
322 isb.setInstruction(instructionsList);
323 flowBuilder.setInstructions(isb.build());
324 writeFlow(flowBuilder, nodeBuilder);
325 LOG.info("INGRESS:default programConntrackTrackedPlusEstRule() flows are written");
327 removeFlow(flowBuilder, nodeBuilder);
331 private void programConntrackNewDropRule(String nodeName, String segmentationId,
332 long localPort, String attachMac, Integer priority, boolean write) {
333 MatchBuilder matchBuilder = new MatchBuilder();
334 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
335 String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
336 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac);
337 matchBuilder = MatchUtils.addCtState(matchBuilder,0x01, 0x01);
338 FlowBuilder flowBuilder = new FlowBuilder();
339 flowBuilder.setMatch(matchBuilder.build());
340 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
342 // Instantiate the Builders for the OF Actions and Instructions
343 InstructionBuilder ib = new InstructionBuilder();
344 InstructionsBuilder isb = new InstructionsBuilder();
346 // Instructions List Stores Individual Instructions
347 List<Instruction> instructions = Lists.newArrayList();
349 // Set the Output Port/Iface
350 InstructionUtils.createDropInstructions(ib);
352 ib.setKey(new InstructionKey(0));
353 instructions.add(ib.build());
355 // Add InstructionBuilder to the Instruction(s)Builder List
356 isb.setInstruction(instructions);
357 LOG.debug("Instructions contain: {}", ib.getInstruction());
358 // Add InstructionsBuilder to FlowBuilder
359 flowBuilder.setInstructions(isb.build());
360 writeFlow(flowBuilder, nodeBuilder);
361 LOG.info("INGRESS:default programConntrackNewDropRule flows are written");
363 removeFlow(flowBuilder, nodeBuilder);
368 * Allows an IPv4/v6 packet ingress to the destination mac address.
369 * @param dpidLong the dpid
370 * @param segmentationId the segementation id
371 * @param dstMac the destination mac address
372 * @param write add or remove
373 * @param protoPortMatchPriority the protocol match priority.
375 private void ingressAclIP(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
376 boolean write, Integer protoPortMatchPriority ) {
377 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
378 MatchBuilder matchBuilder = new MatchBuilder();
379 String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
381 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
383 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac);
385 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
389 * Creates a ingress match to the dst macaddress. If src address is specified
390 * source specific match will be created. Otherwise a match with a CIDR will
392 * @param dpidLong the dpid
393 * @param segmentationId the segmentation id
394 * @param dstMac the destination mac address.
395 * @param portSecurityRule the security rule in the SG
396 * @param srcAddress the destination IP address
397 * @param write add or delete
398 * @param protoPortMatchPriority the protocol match priroty
400 private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
401 NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
402 Integer protoPortMatchPriority ) {
403 boolean portRange = false;
404 MatchBuilder matchBuilder = new MatchBuilder();
405 String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
406 boolean isIpv6 = portSecurityRule.getSecurityRuleEthertype().equals("IPv6");
408 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
410 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac);
413 /* Custom TCP Match*/
414 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
415 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
416 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
417 portSecurityRule.getSecurityRulePortMin());
420 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
421 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
422 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
423 + portSecurityRule.getSecurityRulePortMax() + "_";
424 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
429 if (null != srcAddress) {
430 flowId = flowId + srcAddress;
432 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
433 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
435 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
436 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
438 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
439 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
441 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
442 new Ipv6Prefix(portSecurityRule
443 .getSecurityRuleRemoteIpPrefix()),null);
445 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
446 new Ipv4Prefix(portSecurityRule
447 .getSecurityRuleRemoteIpPrefix()),null);
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 syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
463 flowId = flowId + "_Permit";
464 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
469 * Creates a ingress match to the dst macaddress. If src address is specified
470 * source specific match will be created. Otherwise a match with a CIDR will
472 * @param dpidLong the dpid
473 * @param segmentationId the segmentation id
474 * @param dstMac the destination mac address.
475 * @param portSecurityRule the security rule in the SG
476 * @param srcAddress the destination IP address
477 * @param write add or delete
478 * @param protoPortMatchPriority the protocol match priroty
480 private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
481 NeutronSecurityRule portSecurityRule, String srcAddress,
482 boolean write, Integer protoPortMatchPriority ) {
483 boolean portRange = false;
484 boolean isIpv6 = portSecurityRule.getSecurityRuleEthertype().equals("IPv6");
485 MatchBuilder matchBuilder = new MatchBuilder();
486 String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
488 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
490 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac);
493 /* Custom UDP Match */
494 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
495 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
496 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
497 portSecurityRule.getSecurityRulePortMin());
500 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
501 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
502 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
503 + portSecurityRule.getSecurityRulePortMax() + "_";
504 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
509 if (null != srcAddress) {
510 flowId = flowId + srcAddress;
512 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
513 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
515 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
516 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
518 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
519 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
521 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
522 new Ipv6Prefix(portSecurityRule
523 .getSecurityRuleRemoteIpPrefix()),null);
525 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
526 new Ipv4Prefix(portSecurityRule
527 .getSecurityRuleRemoteIpPrefix()),null);
530 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
532 Map<Integer, Integer> portMaskMap = MatchUtils
533 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
534 portSecurityRule.getSecurityRulePortMax());
535 for (Integer port: portMaskMap.keySet()) {
536 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
537 rangeflowId = rangeflowId + "_Permit";
538 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
539 0, port, portMaskMap.get(port));
540 syncFlow(rangeflowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
543 flowId = flowId + "_Permit";
544 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
548 private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
549 NeutronSecurityRule portSecurityRule, String srcAddress,
550 boolean write, Integer protoPortMatchPriority) {
552 boolean isIpv6 = portSecurityRule.getSecurityRuleEthertype().equals("IPv6");
554 ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress, write, protoPortMatchPriority);
556 ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress, write, protoPortMatchPriority);
561 * Creates a ingress icmp match to the dst macaddress. If src address is specified
562 * source specific match will be created. Otherwise a match with a CIDR will
564 * @param dpidLong the dpid
565 * @param segmentationId the segmentation id
566 * @param dstMac the destination mac address.
567 * @param portSecurityRule the security rule in the SG
568 * @param srcAddress the destination IP address
569 * @param write add or delete
570 * @param protoPortMatchPriority the protocol match priority
572 private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
573 NeutronSecurityRule portSecurityRule, String srcAddress,
574 boolean write, Integer protoPortMatchPriority) {
576 MatchBuilder matchBuilder = new MatchBuilder();
577 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
578 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac);
580 /* Custom ICMP Match */
581 if (portSecurityRule.getSecurityRulePortMin() != null &&
582 portSecurityRule.getSecurityRulePortMax() != null) {
583 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
584 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
585 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
586 portSecurityRule.getSecurityRulePortMin().shortValue(),
587 portSecurityRule.getSecurityRulePortMax().shortValue());
590 flowId = flowId + "all" + "_";
591 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
593 if (null != srcAddress) {
594 flowId = flowId + srcAddress;
595 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
596 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
597 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
598 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
599 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
600 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
601 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
604 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
605 flowId = flowId + "_Permit";
606 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, securityServicesManager.isConntrackEnabled());
610 * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
611 * source specific match will be created. Otherwise a match with a CIDR will
613 * @param dpidLong the dpid
614 * @param segmentationId the segmentation id
615 * @param dstMac the destination mac address.
616 * @param portSecurityRule the security rule in the SG
617 * @param srcAddress the destination IP address
618 * @param write add or delete
619 * @param protoPortMatchPriority the protocol match priority
621 private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
622 NeutronSecurityRule portSecurityRule, String srcAddress,
623 boolean write, Integer protoPortMatchPriority) {
625 MatchBuilder matchBuilder = new MatchBuilder();
626 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
627 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
629 /* Custom ICMP Match */
630 if (portSecurityRule.getSecurityRulePortMin() != null &&
631 portSecurityRule.getSecurityRulePortMax() != null) {
632 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
633 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
634 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
635 portSecurityRule.getSecurityRulePortMin().shortValue(),
636 portSecurityRule.getSecurityRulePortMax().shortValue());
639 flowId = flowId + "all" + "_";
640 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
642 if (null != srcAddress) {
643 flowId = flowId + srcAddress;
644 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
645 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
646 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
647 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
648 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
649 new Ipv6Prefix(portSecurityRule
650 .getSecurityRuleRemoteIpPrefix()),null);
652 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
653 flowId = flowId + "_Permit";
654 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
658 * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
660 * @param dpidLong the dpid
661 * @param segmentationId the segmentation id
662 * @param dhcpMacAddress the DHCP server mac address
663 * @param write is write or delete
664 * @param protoPortMatchPriority the priority
666 private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
667 boolean write, Integer protoPortMatchPriority) {
669 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
670 MatchBuilder matchBuilder = new MatchBuilder();
671 MatchUtils.createDhcpServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build();
672 String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
673 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
677 * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
679 * @param dpidLong the dpid
680 * @param segmentationId the segmentation id
681 * @param dhcpMacAddress the DHCP server mac address
682 * @param write is write or delete
683 * @param protoPortMatchPriority the priority
685 private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
686 boolean write, Integer protoPortMatchPriority) {
688 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
689 MatchBuilder matchBuilder = new MatchBuilder();
690 MatchUtils.createDhcpv6ServerMatch(matchBuilder, dhcpMacAddress, 547, 546).build();
691 String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
692 syncFlow(flowId, nodeBuilder, matchBuilder, protoPortMatchPriority, write, false, false);
696 * Add or remove flow to the node.
698 * @param flowName the the flow id
699 * @param nodeBuilder the node builder
700 * @param matchBuilder the matchbuilder
701 * @param priority the protocol priority
702 * @param write whether it is a write
703 * @param drop whether it is a drop or forward
704 * @param isCtCommit commit the connection or CT to track
706 private void syncFlow(String flowName, NodeBuilder nodeBuilder,
707 MatchBuilder matchBuilder, Integer priority,
708 boolean write, boolean drop, boolean isCtCommit) {
709 MatchBuilder matchBuilder1 = matchBuilder;
711 matchBuilder1 = MatchUtils.addCtState(matchBuilder1,0x81, 0x81);
713 FlowBuilder flowBuilder = new FlowBuilder();
714 flowBuilder.setMatch(matchBuilder1.build());
715 FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable()).setPriority(priority);
718 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
719 InstructionBuilder ib1 = new InstructionBuilder();
720 ActionBuilder ab = new ActionBuilder();
721 ApplyActionsBuilder aab = new ApplyActionsBuilder();
723 InstructionUtils.createDropInstructions(ib);
726 InstructionsBuilder isb = new InstructionsBuilder();
727 List<Instruction> instructionsList = Lists.newArrayList();
728 ib.setKey(new InstructionKey(0));
729 instructionsList.add(ib.build());
731 LOG.info("Adding Conntarck rule, flowname = " + flowName);
732 ab.setAction(ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff));
734 ab.setKey(new ActionKey(0));
735 List<Action> actionList = Lists.newArrayList();
736 actionList.add(ab.build());
737 aab.setAction(actionList);
739 ib1.setKey(new InstructionKey(1));
740 ib1.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
741 instructionsList.add(ib1.build());
743 isb.setInstruction(instructionsList);
744 flowBuilder.setInstructions(isb.build());
745 writeFlow(flowBuilder, nodeBuilder);
747 removeFlow(flowBuilder, nodeBuilder);
752 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
753 super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
754 securityServicesManager =
755 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
756 securityGroupCacheManger =
757 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
761 public void setDependencies(Object impl) {