2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.netvirt.neutronvpn;
10 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import com.google.common.collect.ImmutableBiMap;
15 import java.util.Collections;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
23 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
25 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceBuilder;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.ActionsBuilder;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.MatchesBuilder;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.actions.packet.handling.PermitBuilder;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.AceIpBuilder;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv4Builder;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.ace.matches.ace.type.ace.ip.ace.ip.version.AceIpv6Builder;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttrBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.SecurityRuleAttributes;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
57 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
58 import org.opendaylight.yangtools.yang.common.Empty;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
63 public class NeutronSecurityRuleListener
64 extends AsyncDataTreeChangeListenerBase<SecurityRule, NeutronSecurityRuleListener> {
65 private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleListener.class);
66 private static final ImmutableBiMap<Class<? extends DirectionBase>,
67 Class<?extends org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase>>
68 DIRECTION_MAP = ImmutableBiMap.of(
69 DirectionEgress.class, NeutronSecurityGroupConstants.DIRECTION_EGRESS,
70 DirectionIngress.class, NeutronSecurityGroupConstants.DIRECTION_INGRESS);
71 private static final ImmutableBiMap<Class<? extends ProtocolBase>, Short> PROTOCOL_MAP = ImmutableBiMap.of(
72 ProtocolIcmp.class, NeutronSecurityGroupConstants.PROTOCOL_ICMP,
73 ProtocolTcp.class, NeutronSecurityGroupConstants.PROTOCOL_TCP,
74 ProtocolUdp.class, NeutronSecurityGroupConstants.PROTOCOL_UDP,
75 ProtocolIcmpV6.class, NeutronSecurityGroupConstants.PROTOCOL_ICMPV6);
77 private final DataBroker dataBroker;
78 private final ManagedNewTransactionRunner txRunner;
79 private final JobCoordinator jobCoordinator;
82 public NeutronSecurityRuleListener(final DataBroker dataBroker, JobCoordinator jobCoordinator) {
83 super(SecurityRule.class, NeutronSecurityRuleListener.class);
84 this.dataBroker = dataBroker;
85 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
86 this.jobCoordinator = jobCoordinator;
92 LOG.info("{} init", getClass().getSimpleName());
93 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
97 protected InstanceIdentifier<SecurityRule> getWildCardPath() {
98 return InstanceIdentifier.create(Neutron.class).child(SecurityRules.class).child(SecurityRule.class);
102 // TODO Clean up the exception handling
103 @SuppressWarnings("checkstyle:IllegalCatch")
104 protected void add(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
105 LOG.trace("added securityRule: {}", securityRule);
107 Ace ace = toAceBuilder(securityRule, false).build();
108 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
109 String jobKey = securityRule.getSecurityGroupId().getValue();
110 jobCoordinator.enqueueJob(jobKey,
111 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
112 tx -> tx.put(identifier, ace, CREATE_MISSING_PARENTS))),
113 NeutronSecurityGroupConstants.DJC_MAX_RETRIES);
114 } catch (Exception ex) {
115 LOG.error("Exception occured while adding acl for security rule: {}. ", securityRule, ex);
119 private InstanceIdentifier<Ace> getAceInstanceIdentifier(SecurityRule securityRule) {
120 return InstanceIdentifier
121 .builder(AccessLists.class)
123 new AclKey(securityRule.getSecurityGroupId().getValue(), NeutronSecurityGroupConstants.ACLTYPE))
124 .child(AccessListEntries.class)
126 new AceKey(securityRule.getUuid().getValue()))
130 private AceBuilder toAceBuilder(SecurityRule securityRule, boolean isDeleted) {
131 AceIpBuilder aceIpBuilder = new AceIpBuilder();
132 SecurityRuleAttrBuilder securityRuleAttrBuilder = new SecurityRuleAttrBuilder();
133 DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
134 boolean isDirectionIngress = false;
135 if (securityRule.getDirection() != null) {
136 securityRuleAttrBuilder.setDirection(DIRECTION_MAP.get(securityRule.getDirection()));
137 isDirectionIngress = securityRule.getDirection().equals(DirectionIngress.class);
139 if (securityRule.getPortRangeMax() != null) {
140 destinationPortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
143 if (securityRule.getPortRangeMin() != null) {
144 destinationPortRangeBuilder.setLowerPort(new PortNumber(securityRule.getPortRangeMin()));
145 // set destination port range if lower port is specified as it is mandatory parameter in acl model
146 aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
148 aceIpBuilder = handleRemoteIpPrefix(securityRule, aceIpBuilder, isDirectionIngress);
149 if (securityRule.getRemoteGroupId() != null) {
150 securityRuleAttrBuilder.setRemoteGroupId(securityRule.getRemoteGroupId());
152 if (securityRule.getProtocol() != null) {
153 SecurityRuleAttributes.Protocol protocol = securityRule.getProtocol();
154 if (protocol.getUint8() != null) {
156 aceIpBuilder.setProtocol(protocol.getUint8());
158 // symbolic protocol name
159 aceIpBuilder.setProtocol(PROTOCOL_MAP.get(protocol.getIdentityref()));
162 securityRuleAttrBuilder.setDeleted(isDeleted);
164 MatchesBuilder matchesBuilder = new MatchesBuilder();
165 matchesBuilder.setAceType(aceIpBuilder.build());
166 // set acl action as permit for the security rule
167 ActionsBuilder actionsBuilder = new ActionsBuilder();
168 actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(Empty.getInstance()).build());
170 AceBuilder aceBuilder = new AceBuilder();
171 aceBuilder.withKey(new AceKey(securityRule.getUuid().getValue()));
172 aceBuilder.setRuleName(securityRule.getUuid().getValue());
173 aceBuilder.setMatches(matchesBuilder.build());
174 aceBuilder.setActions(actionsBuilder.build());
175 aceBuilder.addAugmentation(SecurityRuleAttr.class, securityRuleAttrBuilder.build());
179 private AceIpBuilder handleEtherType(SecurityRule securityRule, AceIpBuilder aceIpBuilder) {
180 if (NeutronSecurityGroupConstants.ETHERTYPE_IPV4.equals(securityRule.getEthertype())) {
181 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
182 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(
183 NeutronSecurityGroupConstants.IPV4_ALL_NETWORK));
184 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(
185 NeutronSecurityGroupConstants.IPV4_ALL_NETWORK));
186 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
188 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
189 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
190 NeutronSecurityGroupConstants.IPV6_ALL_NETWORK));
191 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
192 NeutronSecurityGroupConstants.IPV6_ALL_NETWORK));
193 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
199 private AceIpBuilder handleRemoteIpPrefix(SecurityRule securityRule, AceIpBuilder aceIpBuilder,
200 boolean isDirectionIngress) {
201 if (securityRule.getRemoteIpPrefix() != null) {
202 if (securityRule.getRemoteIpPrefix().getIpv4Prefix() != null) {
203 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
204 if (isDirectionIngress) {
205 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(securityRule
206 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
208 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(securityRule
209 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
211 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
213 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
214 if (isDirectionIngress) {
215 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
216 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
218 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
219 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
221 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
224 if (securityRule.getEthertype() != null) {
225 handleEtherType(securityRule, aceIpBuilder);
233 // TODO Clean up the exception handling
234 @SuppressWarnings("checkstyle:IllegalCatch")
235 protected void remove(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
236 LOG.trace("removed securityRule: {}", securityRule);
237 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
239 Ace ace = toAceBuilder(securityRule, true).build();
240 String jobKey = securityRule.getSecurityGroupId().getValue();
241 jobCoordinator.enqueueJob(jobKey,
242 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
243 tx -> tx.merge(identifier, ace, CREATE_MISSING_PARENTS))),
244 NeutronSecurityGroupConstants.DJC_MAX_RETRIES);
245 } catch (Exception ex) {
247 If there are out of sequence events where-in Sg-Rule delete could occur after SecurityGroup delete.
248 we would hit with exception here, trying to delete a child-node, after it's parent has got deleted.
249 Logging it as Warn, because if such event occur we are handling it in the AclEventListeners' Remove method.
251 LOG.warn("Exception occured while removing acl for security rule: {}. ", securityRule, ex);
256 protected void update(InstanceIdentifier<SecurityRule> instanceIdentifier,
257 SecurityRule oldSecurityRule, SecurityRule updatedSecurityRule) {
258 // security rule updation is not supported from openstack, so no need to handle update.
259 LOG.trace("updates on security rules not supported.");
263 protected NeutronSecurityRuleListener getDataTreeChangeListener() {