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, String attachMac, boolean write) {
220 ingressAclDhcpAllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
221 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
222 ingressAclDhcpv6AllowServerTraffic(dpid, segmentationId,dhcpMacAddress, attachMac,
223 write,Constants.PROTO_DHCP_SERVER_MATCH_PRIORITY);
225 if (securityServicesManager.isConntrackEnabled()) {
226 programIngressAclFixedConntrackRule(dpid, segmentationId, attachMac, localPort, write);
228 programArpRule(dpid, segmentationId, localPort, attachMac, write);
231 private void programArpRule(Long dpid, String segmentationId, long localPort, String attachMac, boolean write) {
232 MatchBuilder matchBuilder = new MatchBuilder();
233 String flowId = "Ingress_ARP_" + segmentationId + "_" + localPort + "_";
234 MatchUtils.createV4EtherMatchWithType(matchBuilder,null,null,MatchUtils.ETHERTYPE_ARP);
235 MatchUtils.addArpMacMatch(matchBuilder, null, attachMac);
236 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, Constants.PROTO_MATCH_PRIORITY,
237 matchBuilder, getTable());
238 addPipelineInstruction(flowBuilder, null, false);
239 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpid);
240 syncFlow(flowBuilder ,nodeBuilder, write);
243 private void programIngressAclFixedConntrackRule(Long dpid,
244 String segmentationId, String attachMac, long localPort, boolean write) {
246 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpid;
247 programConntrackUntrackRule(dpid, segmentationId, localPort, attachMac,
248 Constants.CT_STATE_UNTRACKED_PRIORITY, write );
249 programConntrackTrackedPlusEstRule(dpid, segmentationId, localPort, attachMac,
250 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
251 programConntrackTrackedPlusRelRule(dpid, segmentationId, localPort, attachMac,
252 Constants.CT_STATE_TRACKED_EXIST_PRIORITY, write );
253 programConntrackInvDropRule(dpid, segmentationId, localPort, attachMac,
254 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
255 programConntrackNewDropRule(dpid, segmentationId, localPort, attachMac,
256 Constants.CT_STATE_NEW_PRIORITY_DROP, write );
257 LOG.info("programIngressAclFixedConntrackRule : default connection tracking rule are added.");
258 } catch (Exception e) {
259 LOG.error("Failed to add default conntrack rules : " , e);
263 private void programConntrackUntrackRule(Long dpidLong, String segmentationId,
264 long localPort, String attachMac, Integer priority, boolean write) {
265 MatchBuilder matchBuilder = new MatchBuilder();
266 String flowName = "Ingress_Fixed_Conntrk_Untrk_" + segmentationId + "_" + localPort + "_";
267 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
268 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.UNTRACKED_CT_STATE,
269 MatchUtils.UNTRACKED_CT_STATE_MASK);
270 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
271 addInstructionWithConntrackRecirc(flowBuilder);
272 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
273 syncFlow(flowBuilder ,nodeBuilder, write);
276 private void programConntrackTrackedPlusEstRule(Long dpidLong, String segmentationId,
277 long localPort, String attachMac,Integer priority, boolean write) {
278 MatchBuilder matchBuilder = new MatchBuilder();
279 String flowName = "Ingress_Fixed_Conntrk_TrkEst_" + segmentationId + "_" + localPort + "_";
280 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
281 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_EST_CT_STATE,
282 MatchUtils.TRACKED_CT_STATE_MASK);
283 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
284 addPipelineInstruction(flowBuilder, null, false);
285 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
286 syncFlow(flowBuilder ,nodeBuilder, write);
289 private void programConntrackTrackedPlusRelRule(Long dpidLong, String segmentationId,
290 long localPort, String attachMac,Integer priority, boolean write) {
291 MatchBuilder matchBuilder = new MatchBuilder();
292 String flowName = "Ingress_Fixed_Conntrk_TrkRel_" + segmentationId + "_" + localPort + "_";
293 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,MatchUtils.ETHERTYPE_IPV4);
294 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_REL_CT_STATE,
295 MatchUtils.TRACKED_CT_STATE_MASK);
296 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
297 addPipelineInstruction(flowBuilder, null, false);
298 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
299 syncFlow(flowBuilder ,nodeBuilder, write);
302 private void programConntrackNewDropRule(Long dpidLong, String segmentationId,
303 long localPort, String attachMac, Integer priority, boolean write) {
304 MatchBuilder matchBuilder = new MatchBuilder();
306 String flowName = "Ingress_Fixed_Conntrk_NewDrop_" + segmentationId + "_" + localPort + "_";
307 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac,0x0800L);
308 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_NEW_CT_STATE,
309 MatchUtils.TRACKED_NEW_CT_STATE_MASK);
310 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
311 addPipelineInstruction(flowBuilder, null, true);
312 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
313 syncFlow(flowBuilder ,nodeBuilder, write);
316 private void programConntrackInvDropRule(Long dpidLong, String segmentationId,
317 long localPort, String attachMac, Integer priority, boolean write) {
318 MatchBuilder matchBuilder = new MatchBuilder();
319 String flowName = "Ingress_Fixed_Conntrk_InvDrop_" + segmentationId + "_" + localPort + "_";
320 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,attachMac, MatchUtils.ETHERTYPE_IPV4);
321 matchBuilder = MatchUtils.addCtState(matchBuilder,MatchUtils.TRACKED_INV_CT_STATE,
322 MatchUtils.TRACKED_INV_CT_STATE_MASK);
323 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowName, priority, matchBuilder, getTable());
324 addPipelineInstruction(flowBuilder, null, true);
325 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
326 syncFlow(flowBuilder ,nodeBuilder, write);
330 * Allows an IPv4/v6 packet ingress to the destination mac address.
331 * @param dpidLong the dpid
332 * @param isIpv6 indicates whether this is an Ipv
333 * @param segmentationId the segementation id
334 * @param dstMac the destination mac address
335 * @param write add or remove
336 * @param protoPortMatchPriority the protocol match priority.
338 private void ingressAclIp(Long dpidLong, boolean isIpv6, String segmentationId, String dstMac,
339 boolean write, Integer protoPortMatchPriority ) {
340 MatchBuilder matchBuilder = new MatchBuilder();
341 String flowId = "Ingress_IP" + segmentationId + "_" + dstMac + "_Permit_";
343 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
345 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
347 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
348 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
349 addInstructionWithConntrackCommit(flowBuilder, false);
350 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
351 syncFlow(flowBuilder ,nodeBuilder, write);
355 * Creates a ingress match to the dst macaddress. If src address is specified
356 * source specific match will be created. Otherwise a match with a CIDR will
358 * @param dpidLong the dpid
359 * @param segmentationId the segmentation id
360 * @param dstMac the destination mac address.
361 * @param portSecurityRule the security rule in the SG
362 * @param srcAddress the destination IP address
363 * @param write add or delete
364 * @param protoPortMatchPriority the protocol match priroty
366 private void ingressAclTcp(Long dpidLong, String segmentationId, String dstMac,
367 NeutronSecurityRule portSecurityRule, String srcAddress, boolean write,
368 Integer protoPortMatchPriority ) {
369 boolean portRange = false;
370 MatchBuilder matchBuilder = new MatchBuilder();
371 String flowId = "Ingress_TCP_" + segmentationId + "_" + dstMac + "_";
372 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
374 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
376 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
379 /* Custom TCP Match*/
380 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
381 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
382 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0,
383 portSecurityRule.getSecurityRulePortMin());
386 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
387 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
388 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
389 + portSecurityRule.getSecurityRulePortMax() + "_";
390 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.TCP_SHORT, 0, 0);
395 if (null != srcAddress) {
396 flowId = flowId + srcAddress;
398 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
399 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress),null);
401 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
402 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress),null);
404 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
405 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
407 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
408 new Ipv6Prefix(portSecurityRule
409 .getSecurityRuleRemoteIpPrefix()),null);
411 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
412 new Ipv4Prefix(portSecurityRule
413 .getSecurityRuleRemoteIpPrefix()),null);
416 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
418 Map<Integer, Integer> portMaskMap = MatchUtils
419 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
420 portSecurityRule.getSecurityRulePortMax());
421 for (Integer port: portMaskMap.keySet()) {
422 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
423 rangeflowId = rangeflowId + "_Permit";
424 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.TCP_SHORT,
425 0, port, portMaskMap.get(port));
426 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
427 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
428 matchBuilder, getTable());
429 addInstructionWithConntrackCommit(flowBuilder, false);
430 syncFlow(flowBuilder ,nodeBuilder, write);
433 flowId = flowId + "_Permit";
434 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
435 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
436 matchBuilder, getTable());
437 addInstructionWithConntrackCommit(flowBuilder, false);
438 syncFlow(flowBuilder ,nodeBuilder, write);
443 * Creates a ingress match to the dst macaddress. If src address is specified
444 * source specific match will be created. Otherwise a match with a CIDR will
446 * @param dpidLong the dpid
447 * @param segmentationId the segmentation id
448 * @param dstMac the destination mac address.
449 * @param portSecurityRule the security rule in the SG
450 * @param srcAddress the destination IP address
451 * @param write add or delete
452 * @param protoPortMatchPriority the protocol match priroty
454 private void ingressAclUdp(Long dpidLong, String segmentationId, String dstMac,
455 NeutronSecurityRule portSecurityRule, String srcAddress,
456 boolean write, Integer protoPortMatchPriority ) {
457 boolean portRange = false;
458 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
459 MatchBuilder matchBuilder = new MatchBuilder();
460 String flowId = "Ingress_UDP_" + segmentationId + "_" + dstMac + "_";
462 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
464 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
467 /* Custom UDP Match */
468 if (portSecurityRule.getSecurityRulePortMin().equals(portSecurityRule.getSecurityRulePortMax())) {
469 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_";
470 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0,
471 portSecurityRule.getSecurityRulePortMin());
474 if (portSecurityRule.getSecurityRulePortMin().equals(PORT_RANGE_MIN)
475 && portSecurityRule.getSecurityRulePortMax().equals(PORT_RANGE_MAX)) {
476 flowId = flowId + portSecurityRule.getSecurityRulePortMin() + "_"
477 + portSecurityRule.getSecurityRulePortMax() + "_";
478 matchBuilder = MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 0, 0);
483 if (null != srcAddress) {
484 flowId = flowId + srcAddress;
486 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
487 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
489 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
490 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
492 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
493 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
495 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
496 new Ipv6Prefix(portSecurityRule
497 .getSecurityRuleRemoteIpPrefix()),null);
499 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
500 new Ipv4Prefix(portSecurityRule
501 .getSecurityRuleRemoteIpPrefix()),null);
504 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
506 Map<Integer, Integer> portMaskMap = MatchUtils
507 .getLayer4MaskForRange(portSecurityRule.getSecurityRulePortMin(),
508 portSecurityRule.getSecurityRulePortMax());
509 for (Integer port: portMaskMap.keySet()) {
510 String rangeflowId = flowId + port + "_" + portMaskMap.get(port) + "_";
511 rangeflowId = rangeflowId + "_Permit";
512 MatchUtils.addLayer4MatchWithMask(matchBuilder, MatchUtils.UDP_SHORT,
513 0, port, portMaskMap.get(port));
514 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
515 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(rangeflowId, protoPortMatchPriority,
516 matchBuilder, getTable());
517 addInstructionWithConntrackCommit(flowBuilder, false);
518 syncFlow(flowBuilder ,nodeBuilder, write);
521 flowId = flowId + "_Permit";
522 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
523 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority,
524 matchBuilder, getTable());
525 addInstructionWithConntrackCommit(flowBuilder, false);
526 syncFlow(flowBuilder ,nodeBuilder, write);
530 private void ingressAclIcmp(Long dpidLong, String segmentationId, String dstMac,
531 NeutronSecurityRule portSecurityRule, String srcAddress,
532 boolean write, Integer protoPortMatchPriority) {
534 boolean isIpv6 = NeutronSecurityRule.ETHERTYPE_IPV6.equals(portSecurityRule.getSecurityRuleEthertype());
536 ingressAclIcmpV6(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
537 write, protoPortMatchPriority);
539 ingressAclIcmpV4(dpidLong, segmentationId, dstMac, portSecurityRule, srcAddress,
540 write, protoPortMatchPriority);
545 * Creates a ingress icmp match to the dst macaddress. If src address is specified
546 * source specific match will be created. Otherwise a match with a CIDR will
548 * @param dpidLong the dpid
549 * @param segmentationId the segmentation id
550 * @param dstMac the destination mac address.
551 * @param portSecurityRule the security rule in the SG
552 * @param srcAddress the destination IP address
553 * @param write add or delete
554 * @param protoPortMatchPriority the protocol match priority
556 private void ingressAclIcmpV4(Long dpidLong, String segmentationId, String dstMac,
557 NeutronSecurityRule portSecurityRule, String srcAddress,
558 boolean write, Integer protoPortMatchPriority) {
560 MatchBuilder matchBuilder = new MatchBuilder();
561 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
562 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,null,dstMac,MatchUtils.ETHERTYPE_IPV4);
564 /* Custom ICMP Match */
565 if (portSecurityRule.getSecurityRulePortMin() != null
566 && portSecurityRule.getSecurityRulePortMax() != null) {
567 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
568 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
569 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,
570 portSecurityRule.getSecurityRulePortMin().shortValue(),
571 portSecurityRule.getSecurityRulePortMax().shortValue());
574 flowId = flowId + "all" + "_";
575 matchBuilder = MatchUtils.createICMPv4Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
577 if (null != srcAddress) {
578 flowId = flowId + srcAddress;
579 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
580 MatchUtils.iPv4PrefixFromIPv4Address(srcAddress), null);
581 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
582 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
583 if (!portSecurityRule.getSecurityRuleRemoteIpPrefix().contains("/0")) {
584 matchBuilder = MatchUtils.addRemoteIpPrefix(matchBuilder,
585 new Ipv4Prefix(portSecurityRule.getSecurityRuleRemoteIpPrefix()),null);
588 flowId = flowId + "_Permit";
589 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
590 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
591 addInstructionWithConntrackCommit(flowBuilder, false);
592 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
593 syncFlow(flowBuilder ,nodeBuilder, write);
597 * Creates a ingress icmpv6 match to the dst macaddress. If src address is specified
598 * source specific match will be created. Otherwise a match with a CIDR will
600 * @param dpidLong the dpid
601 * @param segmentationId the segmentation id
602 * @param dstMac the destination mac address.
603 * @param portSecurityRule the security rule in the SG
604 * @param srcAddress the destination IP address
605 * @param write add or delete
606 * @param protoPortMatchPriority the protocol match priority
608 private void ingressAclIcmpV6(Long dpidLong, String segmentationId, String dstMac,
609 NeutronSecurityRule portSecurityRule, String srcAddress,
610 boolean write, Integer protoPortMatchPriority) {
612 MatchBuilder matchBuilder = new MatchBuilder();
613 String flowId = "Ingress_ICMP_" + segmentationId + "_" + dstMac + "_";
614 matchBuilder = MatchUtils.createV6EtherMatchWithType(matchBuilder,null,dstMac);
616 /* Custom ICMP Match */
617 if (portSecurityRule.getSecurityRulePortMin() != null
618 && portSecurityRule.getSecurityRulePortMax() != null) {
619 flowId = flowId + portSecurityRule.getSecurityRulePortMin().shortValue() + "_"
620 + portSecurityRule.getSecurityRulePortMax().shortValue() + "_";
621 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,
622 portSecurityRule.getSecurityRulePortMin().shortValue(),
623 portSecurityRule.getSecurityRulePortMax().shortValue());
626 flowId = flowId + "all" + "_";
627 matchBuilder = MatchUtils.createICMPv6Match(matchBuilder,MatchUtils.ALL_ICMP, MatchUtils.ALL_ICMP);
629 if (null != srcAddress) {
630 flowId = flowId + srcAddress;
631 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
632 MatchUtils.iPv6PrefixFromIPv6Address(srcAddress), null);
633 } else if (null != portSecurityRule.getSecurityRuleRemoteIpPrefix()) {
634 flowId = flowId + portSecurityRule.getSecurityRuleRemoteIpPrefix();
635 matchBuilder = MatchUtils.addRemoteIpv6Prefix(matchBuilder,
636 new Ipv6Prefix(portSecurityRule
637 .getSecurityRuleRemoteIpPrefix()),null);
639 addConntrackMatch(matchBuilder, MatchUtils.TRACKED_NEW_CT_STATE,MatchUtils.TRACKED_NEW_CT_STATE_MASK);
640 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
641 flowId = flowId + "_Permit";
642 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
643 addInstructionWithConntrackCommit(flowBuilder, false);
644 syncFlow(flowBuilder ,nodeBuilder, write);
648 * Add rule to ensure only DHCP server traffic from the specified mac is allowed.
650 * @param dpidLong the dpid
651 * @param segmentationId the segmentation id
652 * @param dhcpMacAddress the DHCP server mac address
653 * @param attachMac the mac address of the port
654 * @param write is write or delete
655 * @param protoPortMatchPriority the priority
657 private void ingressAclDhcpAllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
658 String attachMac, boolean write, Integer protoPortMatchPriority) {
660 MatchBuilder matchBuilder = new MatchBuilder();
661 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
662 MatchUtils.ETHERTYPE_IPV4);
663 MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 67, 68);
664 String flowId = "Ingress_DHCP_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
665 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
666 addPipelineInstruction(flowBuilder, null, false);
667 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
668 syncFlow(flowBuilder ,nodeBuilder, write);
672 * Add rule to ensure only DHCPv6 server traffic from the specified mac is allowed.
674 * @param dpidLong the dpid
675 * @param segmentationId the segmentation id
676 * @param dhcpMacAddress the DHCP server mac address
677 * @param attachMac the mac address of the port
678 * @param write is write or delete
679 * @param protoPortMatchPriority the priority
681 private void ingressAclDhcpv6AllowServerTraffic(Long dpidLong, String segmentationId, String dhcpMacAddress,
682 String attachMac, boolean write, Integer protoPortMatchPriority) {
684 MatchBuilder matchBuilder = new MatchBuilder();
685 matchBuilder = MatchUtils.createV4EtherMatchWithType(matchBuilder,dhcpMacAddress,attachMac,
686 MatchUtils.ETHERTYPE_IPV6);
687 MatchUtils.addLayer4Match(matchBuilder, MatchUtils.UDP_SHORT, 547, 546);
688 String flowId = "Ingress_DHCPv6_Server" + segmentationId + "_" + dhcpMacAddress + "_Permit_";
689 FlowBuilder flowBuilder = FlowUtils.createFlowBuilder(flowId, protoPortMatchPriority, matchBuilder, getTable());
690 addPipelineInstruction(flowBuilder, null, false);
691 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
692 syncFlow(flowBuilder ,nodeBuilder, write);
695 private void addConntrackMatch(MatchBuilder matchBuilder, int state, int mask) {
696 if (securityServicesManager.isConntrackEnabled()) {
697 MatchUtils.addCtState(matchBuilder, state, mask );
702 private FlowBuilder addInstructionWithConntrackCommit( FlowBuilder flowBuilder , boolean isDrop) {
703 InstructionBuilder instructionBuilder = null;
704 if (securityServicesManager.isConntrackEnabled()) {
705 Action conntrackAction = ActionUtils.nxConntrackAction(1, 0L, 0, (short)0xff);
706 instructionBuilder = InstructionUtils
707 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
709 return addPipelineInstruction(flowBuilder,instructionBuilder, isDrop);
712 private FlowBuilder addInstructionWithConntrackRecirc( FlowBuilder flowBuilder) {
713 InstructionBuilder instructionBuilder = null;
714 if (securityServicesManager.isConntrackEnabled()) {
715 Action conntrackAction = ActionUtils.nxConntrackAction(0, 0L, 0, (short)0x0);
716 instructionBuilder = InstructionUtils
717 .createInstructionBuilder(ActionUtils.conntrackActionBuilder(conntrackAction), 1, false);
718 List<Instruction> instructionsList = Lists.newArrayList();
719 instructionsList.add(instructionBuilder.build());
720 InstructionsBuilder isb = new InstructionsBuilder();
721 isb.setInstruction(instructionsList);
722 flowBuilder.setInstructions(isb.build());
727 private FlowBuilder addPipelineInstruction( FlowBuilder flowBuilder , InstructionBuilder instructionBuilder,
729 InstructionBuilder pipeLineIndstructionBuilder = createPipleLineInstructionBuilder(isDrop);
730 List<Instruction> instructionsList = Lists.newArrayList();
731 instructionsList.add(pipeLineIndstructionBuilder.build());
732 if (null != instructionBuilder) {
733 instructionsList.add(instructionBuilder.build());
735 InstructionsBuilder isb = new InstructionsBuilder();
736 isb.setInstruction(instructionsList);
737 flowBuilder.setInstructions(isb.build());
741 private InstructionBuilder createPipleLineInstructionBuilder(boolean drop) {
742 InstructionBuilder ib = this.getMutablePipelineInstructionBuilder();
744 InstructionUtils.createDropInstructions(ib);
747 List<Instruction> instructionsList = Lists.newArrayList();
748 ib.setKey(new InstructionKey(0));
749 instructionsList.add(ib.build());
753 * Add or remove flow to the node.
754 * @param flowBuilder the flow builder
755 * @param nodeBuilder the node builder
756 * @param write whether it is a write
758 private void syncFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder,
761 writeFlow(flowBuilder, nodeBuilder);
763 removeFlow(flowBuilder, nodeBuilder);
768 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
769 super.setDependencies(bundleContext.getServiceReference(IngressAclProvider.class.getName()), this);
770 securityServicesManager =
771 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
772 securityGroupCacheManger =
773 (SecurityGroupCacheManger) ServiceHelper.getGlobalInstance(SecurityGroupCacheManger.class, this);
777 public void setDependencies(Object impl) {