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.mdsal.binding.util.Datastore.CONFIGURATION;
12 import com.google.common.collect.ImmutableBiMap;
13 import java.util.Collections;
14 import java.util.Objects;
15 import javax.annotation.PreDestroy;
16 import javax.inject.Inject;
17 import javax.inject.Singleton;
18 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
19 import org.opendaylight.infrautils.utils.concurrent.Executors;
20 import org.opendaylight.mdsal.binding.api.DataBroker;
21 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
22 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceBuilder;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
32 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;
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.MatchesBuilder;
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.actions.packet.handling.PermitBuilder;
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.matches.ace.type.AceIpBuilder;
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.ace.ip.ace.ip.version.AceIpv4Builder;
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.AceIpv6Builder;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttrBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.SecurityRuleAttributes;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.Empty;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
61 public class NeutronSecurityRuleListener extends AbstractAsyncDataTreeChangeListener<SecurityRule> {
62 private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleListener.class);
63 private static final ImmutableBiMap<Class<? extends DirectionBase>,
64 Class<?extends org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase>>
65 DIRECTION_MAP = ImmutableBiMap.of(
66 DirectionEgress.class, NeutronSecurityGroupConstants.DIRECTION_EGRESS,
67 DirectionIngress.class, NeutronSecurityGroupConstants.DIRECTION_INGRESS);
68 private static final ImmutableBiMap<Class<? extends ProtocolBase>, Short> PROTOCOL_MAP = ImmutableBiMap.of(
69 ProtocolIcmp.class, NeutronSecurityGroupConstants.PROTOCOL_ICMP,
70 ProtocolTcp.class, NeutronSecurityGroupConstants.PROTOCOL_TCP,
71 ProtocolUdp.class, NeutronSecurityGroupConstants.PROTOCOL_UDP,
72 ProtocolIcmpV6.class, NeutronSecurityGroupConstants.PROTOCOL_ICMPV6);
74 private final DataBroker dataBroker;
75 private final ManagedNewTransactionRunner txRunner;
76 private final JobCoordinator jobCoordinator;
79 public NeutronSecurityRuleListener(final DataBroker dataBroker, JobCoordinator jobCoordinator) {
80 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
81 .child(SecurityRules.class).child(SecurityRule.class),
82 Executors.newSingleThreadExecutor("NeutronSecurityRuleListener", LOG));
83 this.dataBroker = dataBroker;
84 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
85 this.jobCoordinator = jobCoordinator;
89 LOG.info("{} init", getClass().getSimpleName());
96 Executors.shutdownAndAwaitTermination(getExecutorService());
100 // TODO Clean up the exception handling
101 @SuppressWarnings("checkstyle:IllegalCatch")
102 public void add(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
103 LOG.trace("added securityRule: {}", securityRule);
105 Ace ace = toAceBuilder(securityRule, false).build();
106 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
107 String jobKey = securityRule.getSecurityGroupId().getValue();
108 jobCoordinator.enqueueJob(jobKey,
109 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
110 tx -> tx.mergeParentStructurePut(identifier, ace))),
111 NeutronSecurityGroupConstants.DJC_MAX_RETRIES);
112 } catch (Exception ex) {
113 LOG.error("Exception occured while adding acl for security rule: {}. ", securityRule, ex);
117 private InstanceIdentifier<Ace> getAceInstanceIdentifier(SecurityRule securityRule) {
118 return InstanceIdentifier
119 .builder(AccessLists.class)
121 new AclKey(securityRule.getSecurityGroupId().getValue(), NeutronSecurityGroupConstants.ACLTYPE))
122 .child(AccessListEntries.class)
124 new AceKey(securityRule.getUuid().getValue()))
128 private AceBuilder toAceBuilder(SecurityRule securityRule, boolean isDeleted) {
129 AceIpBuilder aceIpBuilder = new AceIpBuilder();
130 SecurityRuleAttrBuilder securityRuleAttrBuilder = new SecurityRuleAttrBuilder();
131 DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
132 boolean isDirectionIngress = false;
133 if (securityRule.getDirection() != null) {
134 securityRuleAttrBuilder.setDirection(DIRECTION_MAP.get(securityRule.getDirection()));
135 isDirectionIngress = securityRule.getDirection().equals(DirectionIngress.class);
137 if (securityRule.getPortRangeMax() != null) {
138 destinationPortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
141 if (securityRule.getPortRangeMin() != null) {
142 destinationPortRangeBuilder.setLowerPort(new PortNumber(securityRule.getPortRangeMin()));
143 // set destination port range if lower port is specified as it is mandatory parameter in acl model
144 aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
146 aceIpBuilder = handleRemoteIpPrefix(securityRule, aceIpBuilder, isDirectionIngress);
147 if (securityRule.getRemoteGroupId() != null) {
148 securityRuleAttrBuilder.setRemoteGroupId(securityRule.getRemoteGroupId());
150 if (securityRule.getProtocol() != null) {
151 SecurityRuleAttributes.Protocol protocol = securityRule.getProtocol();
152 if (protocol.getUint8() != null) {
154 aceIpBuilder.setProtocol(protocol.getUint8());
156 // symbolic protocol name
157 aceIpBuilder.setProtocol(PROTOCOL_MAP.get(protocol.getIdentityref()));
160 securityRuleAttrBuilder.setDeleted(isDeleted);
162 MatchesBuilder matchesBuilder = new MatchesBuilder();
163 matchesBuilder.setAceType(aceIpBuilder.build());
164 // set acl action as permit for the security rule
165 ActionsBuilder actionsBuilder = new ActionsBuilder();
166 actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(Empty.getInstance()).build());
168 AceBuilder aceBuilder = new AceBuilder();
169 aceBuilder.withKey(new AceKey(securityRule.getUuid().getValue()));
170 aceBuilder.setRuleName(securityRule.getUuid().getValue());
171 aceBuilder.setMatches(matchesBuilder.build());
172 aceBuilder.setActions(actionsBuilder.build());
173 aceBuilder.addAugmentation(securityRuleAttrBuilder.build());
177 private AceIpBuilder handleEtherType(SecurityRule securityRule, AceIpBuilder aceIpBuilder) {
178 if (NeutronSecurityGroupConstants.ETHERTYPE_IPV4.equals(securityRule.getEthertype())) {
179 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
180 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(
181 NeutronSecurityGroupConstants.IPV4_ALL_NETWORK));
182 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(
183 NeutronSecurityGroupConstants.IPV4_ALL_NETWORK));
184 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
186 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
187 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
188 NeutronSecurityGroupConstants.IPV6_ALL_NETWORK));
189 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
190 NeutronSecurityGroupConstants.IPV6_ALL_NETWORK));
191 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
197 private AceIpBuilder handleRemoteIpPrefix(SecurityRule securityRule, AceIpBuilder aceIpBuilder,
198 boolean isDirectionIngress) {
199 if (securityRule.getRemoteIpPrefix() != null) {
200 if (securityRule.getRemoteIpPrefix().getIpv4Prefix() != null) {
201 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
202 if (isDirectionIngress) {
203 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(securityRule
204 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
206 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(securityRule
207 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
209 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
211 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
212 if (isDirectionIngress) {
213 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
214 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
216 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
217 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
219 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
222 if (securityRule.getEthertype() != null) {
223 handleEtherType(securityRule, aceIpBuilder);
231 // TODO Clean up the exception handling
232 @SuppressWarnings("checkstyle:IllegalCatch")
233 public void remove(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
234 LOG.trace("removed securityRule: {}", securityRule);
235 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
237 Ace ace = toAceBuilder(securityRule, true).build();
238 String jobKey = securityRule.getSecurityGroupId().getValue();
239 jobCoordinator.enqueueJob(jobKey,
240 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
241 tx -> tx.mergeParentStructureMerge(identifier, ace))),
242 NeutronSecurityGroupConstants.DJC_MAX_RETRIES);
243 } catch (Exception ex) {
245 If there are out of sequence events where-in Sg-Rule delete could occur after SecurityGroup delete.
246 we would hit with exception here, trying to delete a child-node, after it's parent has got deleted.
247 Logging it as Warn, because if such event occur we are handling it in the AclEventListeners' Remove method.
249 LOG.warn("Exception occured while removing acl for security rule: {}. ", securityRule, ex);
254 public void update(InstanceIdentifier<SecurityRule> instanceIdentifier,
255 SecurityRule oldSecurityRule, SecurityRule updatedSecurityRule) {
256 // security rule updation is not supported from openstack, so no need to handle update.
257 LOG.trace("updates on security rules not supported.");
258 if (Objects.equals(oldSecurityRule, updatedSecurityRule)) {