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.providers.openflow13.Service;
15 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
16 import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
17 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
18 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
19 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
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.opendaylight.action.types.rev131112.action.Action;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
38 import org.osgi.framework.BundleContext;
39 import org.osgi.framework.ServiceReference;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 import java.net.Inet4Address;
44 import java.net.Inet6Address;
45 import java.net.InetAddress;
46 import java.net.UnknownHostException;
47 import java.util.List;
50 public class IngressAclService extends AbstractServiceInstance implements IngressAclProvider, ConfigInterface {
51 private static final Logger LOG = LoggerFactory.getLogger(IngressAclService.class);
52 private volatile SecurityServicesManager securityServicesManager;
53 private volatile SecurityGroupCacheManger securityGroupCacheManger;
54 private static final int PORT_RANGE_MIN = 1;
55 private static final int PORT_RANGE_MAX = 65535;
57 public IngressAclService() {
58 super(Service.INGRESS_ACL);
61 public IngressAclService(Service service) {
66 public void programPortSecurityGroup(Long dpid, String segmentationId, String attachedMac,
67 long localPort, NeutronSecurityGroup securityGroup,
68 String portUuid, boolean write) {
70 LOG.trace("programPortSecurityGroup neutronSecurityGroup: {} ", securityGroup);
71 if (securityGroup == null || securityGroup.getSecurityRules() == null) {
75 List<NeutronSecurityRule> portSecurityList = securityGroup.getSecurityRules();
76 /* Iterate over the Port Security Rules in the Port Security Group bound to the port*/
77 for (NeutronSecurityRule portSecurityRule : portSecurityList) {
80 * Neutron Port Security Acl "ingress" and "IPv4"
81 * Check that the base conditions for flow based Port Security are true:
82 * Port Security Rule Direction ("ingress") and Protocol ("IPv4")
83 * Neutron defines the direction "ingress" as the vSwitch to the VM as defined in:
84 * http://docs.openstack.org/api/openstack-network/2.0/content/security_groups.html
88 if (portSecurityRule == null
89 || portSecurityRule.getSecurityRuleEthertype() == null
90 || portSecurityRule.getSecurityRuleDirection() == null) {
94 if (NeutronSecurityRule.DIRECTION_INGRESS.equals(portSecurityRule.getSecurityRuleDirection())) {
95 LOG.debug("programPortSecurityGroup: Rule matching IP and ingress is: {} ", portSecurityRule);
96 if (null != portSecurityRule.getSecurityRemoteGroupID()) {
97 //Remote Security group is selected
98 List<Neutron_IPs> remoteSrcAddressList = securityServicesManager
99 .getVmListForSecurityGroup(portUuid,portSecurityRule.getSecurityRemoteGroupID());
100 if (null != remoteSrcAddressList) {
101 for (Neutron_IPs vmIp :remoteSrcAddressList ) {
102 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
103 portSecurityRule, vmIp, write);
106 securityGroupCacheManger.addToCache(portSecurityRule.getSecurityRemoteGroupID(), portUuid);
108 securityGroupCacheManger.removeFromCache(portSecurityRule.getSecurityRemoteGroupID(),
113 programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
114 portSecurityRule, null, write);
117 securityGroupCacheManger.portAdded(securityGroup.getSecurityGroupUUID(), portUuid);
119 securityGroupCacheManger.portRemoved(securityGroup.getSecurityGroupUUID(), portUuid);
126 public void programPortSecurityRule(Long dpid, String segmentationId, String attachedMac,
127 long localPort, NeutronSecurityRule portSecurityRule,
128 Neutron_IPs vmIp, boolean write) {
129 String securityRuleEtherType = portSecurityRule.getSecurityRuleEthertype();
130 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(securityRuleEtherType);
131 if (!isIpv6 && !NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRuleEtherType)) {
132 LOG.debug("programPortSecurityRule: SecurityRuleEthertype {} does not match IPv4/v6.",
133 securityRuleEtherType);
137 if (null == portSecurityRule.getSecurityRuleProtocol()) {
138 ingressAclIp(dpid, isIpv6, segmentationId, attachedMac,
139 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
141 String ipaddress = null;
143 ipaddress = vmIp.getIpAddress();
145 InetAddress address = InetAddress.getByName(vmIp.getIpAddress());
146 if ((isIpv6 && (address instanceof Inet4Address)) || (!isIpv6 && address instanceof Inet6Address)) {
147 LOG.debug("programPortSecurityRule: Remote vmIP {} does not match "
148 + "with SecurityRuleEthertype {}.", ipaddress, securityRuleEtherType);
151 } catch (UnknownHostException e) {
152 LOG.warn("Invalid IP address {}", ipaddress, e);
157 switch (portSecurityRule.getSecurityRuleProtocol()) {
159 LOG.debug("programPortSecurityRule: Rule matching TCP", portSecurityRule);
160 ingressAclTcp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
161 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
164 LOG.debug("programPortSecurityRule: Rule matching UDP", portSecurityRule);
165 ingressAclUdp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
166 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
168 case MatchUtils.ICMP:
169 case MatchUtils.ICMPV6:
170 LOG.debug("programPortSecurityRule: Rule matching ICMP", portSecurityRule);
171 ingressAclIcmp(dpid, segmentationId, attachedMac, portSecurityRule, ipaddress,
172 write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
175 LOG.info("programPortSecurityAcl: Protocol is not TCP/UDP/ICMP but other "
176 + "protocol = ", portSecurityRule.getSecurityRuleProtocol());
177 ingressOtherProtocolAclHandler(dpid, segmentationId, attachedMac, portSecurityRule,
178 null, write, Constants.PROTO_PORT_PREFIX_MATCH_PRIORITY);
184 private void ingressOtherProtocolAclHandler(Long dpidLong, String segmentationId, String dstMac,
185 NeutronSecurityRule portSecurityRule, String srcAddress,
186 boolean write, Integer protoPortMatchPriority) {
187 MatchBuilder matchBuilder = new MatchBuilder();
188 String flowId = "Ingress_Other_" + segmentationId + "_" + dstMac + "_";
189 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
192 Integer protocol = new Integer(portSecurityRule.getSecurityRuleProtocol());
193 proto = protocol.shortValue();
194 flowId = flowId + proto;
195 } catch (NumberFormatException e) {
196 LOG.error("Protocol vlaue conversion failure", e);
198 matchBuilder = MatchUtils.createIpProtocolMatch(matchBuilder, proto);
199 if (null != srcAddress) {
200 flowId = flowId + srcAddress;
201 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
202 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
203 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
204 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
205 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
206 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
208 flowId = flowId + "_Permit";
209 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
210 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
211 matchBuilder, getTable());
212 addInstructionWithConntrackCommit(flowBuilder, false);
213 syncFlow(flowBuilder ,nodeBuilder, write);
217 public void programFixedSecurityGroup(Long dpid, String segmentationId, String dhcpMacAddress,
218 long localPort, boolean isLastPortinSubnet,
219 boolean isComputePort, String attachMac, boolean write) {
220 //If this port is the only port in the compute node add the DHCP server rule.
221 if (isLastPortinSubnet && isComputePort ) {
222 ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
223 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
224 ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress,
225 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
228 if (securityServicesManager.isConntrackEnabled()) {
229 programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
231 programArpRule(dpid, segmentationId, localPort, attachMac, write);
235 private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
236 MatchBuilder matchBuilder = new MatchBuilder();
237 String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
238 MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
239 MatchUtils.addArpMacMatch(matchBuilder, null, attachMac);
240 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
241 matchBuilder, getTable());
242 addPipelineInstruction(flowBuilder, null, false);
243 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
244 syncFlow(flowBuilder ,nodeBuilder, write);
247 private void programIngressAclFixedConntrackRule(Long dpid,
248 String segmentationId, String attachMac, long localPort, boolean write) {
250 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
251 programConntrackUntrackRule(dpid, segmentationId, localPort, attachMac,
252 Constants.CT_STATE_UNTRACKED_PRIORITY, write );
253 programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort, attachMac,
254 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
255 programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort, attachMac,
256 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
257 programConntrackInvDropRule(dpid, segmentationId, localPort, attachMac,
258 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
259 programConntrackNewDropRule(dpid, segmentationId, localPort, attachMac,
260 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
261 LOG.info("programIngressAclFixedConntrackRule : default connection tracking rule are added.");
262 } catch (Exception e) {
263 LOG.error("Failed to add default conntrack rules : " , e);
267 private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
268 long localPort, String attachMac, Integer priority, boolean write) {
269 MatchBuilder matchBuilder = new MatchBuilder();
270 String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
271 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
272 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
273 MatchUtils.UNTRACKED_CT_STATE_MASK);
274 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
275 addInstructionWithConntrackRecirc(flowBuilder);
276 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
277 syncFlow(flowBuilder ,nodeBuilder, write);
280 private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
281 long localPort, String attachMac,Integer priority, boolean write) {
282 MatchBuilder matchBuilder = new MatchBuilder();
283 String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
284 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
285 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
286 MatchUtils.TRACKED_CT_STATE_MASK);
287 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
288 addPipelineInstruction(flowBuilder, null, false);
289 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
290 syncFlow(flowBuilder ,nodeBuilder, write);
293 private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
294 long localPort, String attachMac,Integer priority, boolean write) {
295 MatchBuilder matchBuilder = new MatchBuilder();
296 String flowName = "Ingress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
297 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
298 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
299 MatchUtils.TRACKED_CT_STATE_MASK);
300 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
301 addPipelineInstruction(flowBuilder, null, false);
302 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
303 syncFlow(flowBuilder ,nodeBuilder, write);
306 private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
307 long localPort, String attachMac, Integer priority, boolean write) {
308 MatchBuilder matchBuilder = new MatchBuilder();
310 String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
311 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,0x0800L);
312 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
313 MatchUtils.TRACKED_NEW_CT_STATE_MASK);
314 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
315 addPipelineInstruction(flowBuilder, null, true);
316 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
317 syncFlow(flowBuilder ,nodeBuilder, write);
320 private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
321 long localPort, String attachMac, Integer priority, boolean write) {
322 MatchBuilder matchBuilder = new MatchBuilder();
323 String flowName = "Ingress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
324 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac, MatchUtils.ETHERTYPE_IPV4);
325 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
326 MatchUtils.TRACKED_INV_CT_STATE_MASK);
327 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
328 addPipelineInstruction(flowBuilder, null, true);
329 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
330 syncFlow(flowBuilder ,nodeBuilder, write);
334 * Allows an IPv4/v6 packet ingress to the destination mac address.
335 * @param dpidLong the dpid
336 * @param isIpv6 indicates whether this is an Ipv
337 * @param segmentationId the segementation id
338 * @param dstMac the destination mac address
339 * @param write add or remove
340 * @param protoPortMatchPriority the protocol match priority.
342 private void ingressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
343 boolean write, Integer protoPortMatchPriority ) {
344 MatchBuilder matchBuilder = new MatchBuilder();
345 String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
347 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
349 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
351 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
352 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
353 addInstructionWithConntrackCommit(flowBuilder, false);
354 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
355 syncFlow(flowBuilder ,nodeBuilder, write);
359 * Creates a ingress match to the dst macaddress. If src address is specified
360 * source specific match will be created. Otherwise a match with a CIDR will
362 * @param dpidLong the dpid
363 * @param segmentationId the segmentation id
364 * @param dstMac the destination mac address.
365 * @param portSecurityRule the security rule in the SG
366 * @param srcAddress the destination IP address
367 * @param write add or delete
368 * @param protoPortMatchPriority the protocol match priroty
370 private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
371 NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
372 Integer protoPortMatchPriority ) {
373 boolean portRange = false;
374 MatchBuilder matchBuilder = new MatchBuilder();
375 String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
376 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
378 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
380 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
383 /* Custom TCP Match*/
384 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
385 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
386 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
387 portSecurityRule.getSecurityRulePortMin());
390 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
391 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
392 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
393 + portSecurityRule.getSecurityRulePortMax() + "_";
394 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
399 if (null != srcAddress) {
400 flowId = flowId + srcAddress;
402 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
403 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
405 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
406 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
408 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
409 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
411 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
412 new Ipv6Prefix(portSecurityRule
413 .getSecurityRuleRemoteIpPrefix()),null);
415 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
416 new Ipv4Prefix(portSecurityRule
417 .getSecurityRuleRemoteIpPrefix()),null);
420 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
422 Map<Integer, Integer> portMaskMap = MatchUtils
423 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
424 portSecurityRule.getSecurityRulePortMax());
425 for (Integer port: portMaskMap.keySet()) {
426 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
427 rangeflowId = rangeflowId + "_Permit";
428 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
429 0, port, portMaskMap.get(port));
430 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
431 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
432 matchBuilder, getTable());
433 addInstructionWithConntrackCommit(flowBuilder, false);
434 syncFlow(flowBuilder ,nodeBuilder, write);
437 flowId = flowId + "_Permit";
438 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
439 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
440 matchBuilder, getTable());
441 addInstructionWithConntrackCommit(flowBuilder, false);
442 syncFlow(flowBuilder ,nodeBuilder, write);
447 * Creates a ingress match to the dst macaddress. If src address is specified
448 * source specific match will be created. Otherwise a match with a CIDR will
450 * @param dpidLong the dpid
451 * @param segmentationId the segmentation id
452 * @param dstMac the destination mac address.
453 * @param portSecurityRule the security rule in the SG
454 * @param srcAddress the destination IP address
455 * @param write add or delete
456 * @param protoPortMatchPriority the protocol match priroty
458 private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
459 NeutronSecurityRule portSecurityRule, String srcAddress,
460 boolean write, Integer protoPortMatchPriority ) {
461 boolean portRange = false;
462 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
463 MatchBuilder matchBuilder = new MatchBuilder();
464 String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
466 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
468 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
471 /* Custom UDP Match */
472 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
473 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
474 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
475 portSecurityRule.getSecurityRulePortMin());
478 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
479 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
480 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
481 + portSecurityRule.getSecurityRulePortMax() + "_";
482 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
487 if (null != srcAddress) {
488 flowId = flowId + srcAddress;
490 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
491 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
493 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
494 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
496 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
497 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
499 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
500 new Ipv6Prefix(portSecurityRule
501 .getSecurityRuleRemoteIpPrefix()),null);
503 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
504 new Ipv4Prefix(portSecurityRule
505 .getSecurityRuleRemoteIpPrefix()),null);
508 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
510 Map<Integer, Integer> portMaskMap = MatchUtils
511 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
512 portSecurityRule.getSecurityRulePortMax());
513 for (Integer port: portMaskMap.keySet()) {
514 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
515 rangeflowId = rangeflowId + "_Permit";
516 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
517 0, port, portMaskMap.get(port));
518 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
519 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
520 matchBuilder, getTable());
521 addInstructionWithConntrackCommit(flowBuilder, false);
522 syncFlow(flowBuilder ,nodeBuilder, write);
525 flowId = flowId + "_Permit";
526 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
527 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
528 matchBuilder, getTable());
529 addInstructionWithConntrackCommit(flowBuilder, false);
530 syncFlow(flowBuilder ,nodeBuilder, write);
534 private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
535 NeutronSecurityRule portSecurityRule, String srcAddress,
536 boolean write, Integer protoPortMatchPriority) {
538 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
540 ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
541 write, protoPortMatchPriority);
543 ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
544 write, protoPortMatchPriority);
549 * Creates a ingress icmp match to the dst macaddress. If src address is specified
550 * source specific match will be created. Otherwise a match with a CIDR will
552 * @param dpidLong the dpid
553 * @param segmentationId the segmentation id
554 * @param dstMac the destination mac address.
555 * @param portSecurityRule the security rule in the SG
556 * @param srcAddress the destination IP address
557 * @param write add or delete
558 * @param protoPortMatchPriority the protocol match priority
560 private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
561 NeutronSecurityRule portSecurityRule, String srcAddress,
562 boolean write, Integer protoPortMatchPriority) {
564 MatchBuilder matchBuilder = new MatchBuilder();
565 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
566 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
568 /* Custom ICMP Match */
569 if (portSecurityRule.getSecurityRulePortMin() != null
570 && portSecurityRule.getSecurityRulePortMax() != null) {
571 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
572 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
573 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
574 portSecurityRule.getSecurityRulePortMin().shortValue(),
575 portSecurityRule.getSecurityRulePortMax().shortValue());
578 flowId = flowId + "all" + "_";
579 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
581 if (null != srcAddress) {
582 flowId = flowId + srcAddress;
583 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
584 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
585 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
586 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
587 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
588 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
589 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
592 flowId = flowId + "_Permit";
593 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
594 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
595 addInstructionWithConntrackCommit(flowBuilder, false);
596 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
597 syncFlow(flowBuilder ,nodeBuilder, write);
601 * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
602 * source specific match will be created. Otherwise a match with a CIDR will
604 * @param dpidLong the dpid
605 * @param segmentationId the segmentation id
606 * @param dstMac the destination mac address.
607 * @param portSecurityRule the security rule in the SG
608 * @param srcAddress the destination IP address
609 * @param write add or delete
610 * @param protoPortMatchPriority the protocol match priority
612 private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
613 NeutronSecurityRule portSecurityRule, String srcAddress,
614 boolean write, Integer protoPortMatchPriority) {
616 MatchBuilder matchBuilder = new MatchBuilder();
617 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
618 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
620 /* Custom ICMP Match */
621 if (portSecurityRule.getSecurityRulePortMin() != null
622 && portSecurityRule.getSecurityRulePortMax() != null) {
623 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
624 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
625 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
626 portSecurityRule.getSecurityRulePortMin().shortValue(),
627 portSecurityRule.getSecurityRulePortMax().shortValue());
630 flowId = flowId + "all" + "_";
631 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
633 if (null != srcAddress) {
634 flowId = flowId + srcAddress;
635 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
636 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
637 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
638 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
639 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
640 new Ipv6Prefix(portSecurityRule
641 .getSecurityRuleRemoteIpPrefix()),null);
643 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
644 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
645 flowId = flowId + "_Permit";
646 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
647 addInstructionWithConntrackCommit(flowBuilder, false);
648 syncFlow(flowBuilder ,nodeBuilder, write);
652 * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
654 * @param dpidLong the dpid
655 * @param segmentationId the segmentation id
656 * @param dhcpMacAddress the DHCP server mac address
657 * @param write is write or delete
658 * @param protoPortMatchPriority the priority
660 private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
661 boolean write, Integer protoPortMatchPriority) {
663 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
664 MatchBuilder matchBuilder = new MatchBuilder();
665 MatchUtils.createDhcpServerMatch(matchBuilder, dhcpMacAddress, 67, 68).build();
666 String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
667 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
668 addPipelineInstruction(flowBuilder, null, false);
669 syncFlow(flowBuilder ,nodeBuilder, write);
673 * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
675 * @param dpidLong the dpid
676 * @param segmentationId the segmentation id
677 * @param dhcpMacAddress the DHCP server mac address
678 * @param write is write or delete
679 * @param protoPortMatchPriority the priority
681 private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
682 boolean write, Integer protoPortMatchPriority) {
684 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
685 MatchBuilder matchBuilder = new MatchBuilder();
686 MatchUtils.createDhcpv6ServerMatch(matchBuilder, dhcpMacAddress, 547, 546).build();
687 String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
688 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
689 addPipelineInstruction(flowBuilder, null, false);
690 syncFlow(flowBuilder ,nodeBuilder, write);
693 private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
694 if (securityServicesManager.isConntrackEnabled()) {
695 MatchUtils.addCtState(matchBuilder, state, mask );
700 private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
701 InstructionBuilder instructionBuilder = null;
702 if (securityServicesManager.isConntrackEnabled()) {
703 Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
704 instructionBuilder = InstructionUtils
705 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
707 return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
710 private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
711 InstructionBuilder instructionBuilder = null;
712 if (securityServicesManager.isConntrackEnabled()) {
713 Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
714 instructionBuilder = InstructionUtils
715 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
716 List<Instruction> instructionsList = Lists.newArrayList();
717 instructionsList.add(instructionBuilder.build());
718 InstructionsBuilder isb = new InstructionsBuilder();
719 isb.setInstruction(instructionsList);
720 flowBuilder.setInstructions(isb.build());
725 private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder , InstructionBuilder instructionBuilder,
727 InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
728 List<Instruction> instructionsList = Lists.newArrayList();
729 instructionsList.add(pipeLineIndstructionBuilder.build());
730 if (null != instructionBuilder) {
731 instructionsList.add(instructionBuilder.build());
733 InstructionsBuilder isb = new InstructionsBuilder();
734 isb.setInstruction(instructionsList);
735 flowBuilder.setInstructions(isb.build());
739 private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
740 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
742 InstructionUtils.createDropInstructions(ib);
745 List<Instruction> instructionsList = Lists.newArrayList();
746 ib.setKey(new InstructionKey(0));
747 instructionsList.add(ib.build());
751 * Add or remove flow to the node.
752 * @param flowBuilder the flow builder
753 * @param nodeBuilder the node builder
754 * @param write whether it is a write
756 private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
759 writeFlow(flowBuilder, nodeBuilder);
761 removeFlow(flowBuilder, nodeBuilder);
766 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
767 super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
768 securityServicesManager =
769 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
770 securityGroupCacheManger =
771 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
775 public void setDependencies(Object impl) {