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.slf4j.Logger;
59 import org.slf4j.LoggerFactory;
62 public class NeutronSecurityRuleListener
63 extends AsyncDataTreeChangeListenerBase<SecurityRule, NeutronSecurityRuleListener> {
64 private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleListener.class);
65 private static final ImmutableBiMap<Class<? extends DirectionBase>,
66 Class<?extends org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase>>
67 DIRECTION_MAP = ImmutableBiMap.of(
68 DirectionEgress.class, NeutronSecurityRuleConstants.DIRECTION_EGRESS,
69 DirectionIngress.class, NeutronSecurityRuleConstants.DIRECTION_INGRESS);
70 private static final ImmutableBiMap<Class<? extends ProtocolBase>, Short> PROTOCOL_MAP = ImmutableBiMap.of(
71 ProtocolIcmp.class, NeutronSecurityRuleConstants.PROTOCOL_ICMP,
72 ProtocolTcp.class, NeutronSecurityRuleConstants.PROTOCOL_TCP,
73 ProtocolUdp.class, NeutronSecurityRuleConstants.PROTOCOL_UDP,
74 ProtocolIcmpV6.class, NeutronSecurityRuleConstants.PROTOCOL_ICMPV6);
76 private final DataBroker dataBroker;
77 private final ManagedNewTransactionRunner txRunner;
78 private final JobCoordinator jobCoordinator;
81 public NeutronSecurityRuleListener(final DataBroker dataBroker, JobCoordinator jobCoordinator) {
82 super(SecurityRule.class, NeutronSecurityRuleListener.class);
83 this.dataBroker = dataBroker;
84 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
85 this.jobCoordinator = jobCoordinator;
91 LOG.info("{} init", getClass().getSimpleName());
92 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
96 protected InstanceIdentifier<SecurityRule> getWildCardPath() {
97 return InstanceIdentifier.create(Neutron.class).child(SecurityRules.class).child(SecurityRule.class);
101 // TODO Clean up the exception handling
102 @SuppressWarnings("checkstyle:IllegalCatch")
103 protected void add(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
104 LOG.trace("added securityRule: {}", securityRule);
106 Ace ace = toAceBuilder(securityRule, false).build();
107 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
108 String jobKey = securityRule.getSecurityGroupId().getValue();
109 jobCoordinator.enqueueJob(jobKey,
110 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
111 tx -> tx.put(identifier, ace, CREATE_MISSING_PARENTS))),
112 NeutronSecurityRuleConstants.DJC_MAX_RETRIES);
113 } catch (Exception ex) {
114 LOG.error("Exception occured while adding acl for security rule: {}. ", securityRule, ex);
118 private InstanceIdentifier<Ace> getAceInstanceIdentifier(SecurityRule securityRule) {
119 return InstanceIdentifier
120 .builder(AccessLists.class)
122 new AclKey(securityRule.getSecurityGroupId().getValue(), NeutronSecurityRuleConstants.ACLTYPE))
123 .child(AccessListEntries.class)
125 new AceKey(securityRule.getUuid().getValue()))
129 private AceBuilder toAceBuilder(SecurityRule securityRule, boolean isDeleted) {
130 AceIpBuilder aceIpBuilder = new AceIpBuilder();
131 SecurityRuleAttrBuilder securityRuleAttrBuilder = new SecurityRuleAttrBuilder();
132 DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
133 boolean isDirectionIngress = false;
134 if (securityRule.getDirection() != null) {
135 securityRuleAttrBuilder.setDirection(DIRECTION_MAP.get(securityRule.getDirection()));
136 isDirectionIngress = securityRule.getDirection().equals(DirectionIngress.class);
138 if (securityRule.getPortRangeMax() != null) {
139 destinationPortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
142 if (securityRule.getPortRangeMin() != null) {
143 destinationPortRangeBuilder.setLowerPort(new PortNumber(securityRule.getPortRangeMin()));
144 // set destination port range if lower port is specified as it is mandatory parameter in acl model
145 aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
147 aceIpBuilder = handleRemoteIpPrefix(securityRule, aceIpBuilder, isDirectionIngress);
148 if (securityRule.getRemoteGroupId() != null) {
149 securityRuleAttrBuilder.setRemoteGroupId(securityRule.getRemoteGroupId());
151 if (securityRule.getProtocol() != null) {
152 SecurityRuleAttributes.Protocol protocol = securityRule.getProtocol();
153 if (protocol.getUint8() != null) {
155 aceIpBuilder.setProtocol(protocol.getUint8());
157 // symbolic protocol name
158 aceIpBuilder.setProtocol(PROTOCOL_MAP.get(protocol.getIdentityref()));
161 securityRuleAttrBuilder.setDeleted(isDeleted);
163 MatchesBuilder matchesBuilder = new MatchesBuilder();
164 matchesBuilder.setAceType(aceIpBuilder.build());
165 // set acl action as permit for the security rule
166 ActionsBuilder actionsBuilder = new ActionsBuilder();
167 actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(true).build());
169 AceBuilder aceBuilder = new AceBuilder();
170 aceBuilder.withKey(new AceKey(securityRule.getUuid().getValue()));
171 aceBuilder.setRuleName(securityRule.getUuid().getValue());
172 aceBuilder.setMatches(matchesBuilder.build());
173 aceBuilder.setActions(actionsBuilder.build());
174 aceBuilder.addAugmentation(SecurityRuleAttr.class, securityRuleAttrBuilder.build());
178 private AceIpBuilder handleEtherType(SecurityRule securityRule, AceIpBuilder aceIpBuilder) {
179 if (NeutronSecurityRuleConstants.ETHERTYPE_IPV4.equals(securityRule.getEthertype())) {
180 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
181 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(
182 NeutronSecurityRuleConstants.IPV4_ALL_NETWORK));
183 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(
184 NeutronSecurityRuleConstants.IPV4_ALL_NETWORK));
185 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
187 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
188 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
189 NeutronSecurityRuleConstants.IPV6_ALL_NETWORK));
190 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
191 NeutronSecurityRuleConstants.IPV6_ALL_NETWORK));
192 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
198 private AceIpBuilder handleRemoteIpPrefix(SecurityRule securityRule, AceIpBuilder aceIpBuilder,
199 boolean isDirectionIngress) {
200 if (securityRule.getRemoteIpPrefix() != null) {
201 if (securityRule.getRemoteIpPrefix().getIpv4Prefix() != null) {
202 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
203 if (isDirectionIngress) {
204 aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(securityRule
205 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
207 aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(securityRule
208 .getRemoteIpPrefix().getIpv4Prefix().getValue()));
210 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
212 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
213 if (isDirectionIngress) {
214 aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
215 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
217 aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
218 securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
220 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
223 if (securityRule.getEthertype() != null) {
224 handleEtherType(securityRule, aceIpBuilder);
232 // TODO Clean up the exception handling
233 @SuppressWarnings("checkstyle:IllegalCatch")
234 protected void remove(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
235 LOG.trace("removed securityRule: {}", securityRule);
236 InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
238 Ace ace = toAceBuilder(securityRule, true).build();
239 String jobKey = securityRule.getSecurityGroupId().getValue();
240 jobCoordinator.enqueueJob(jobKey,
241 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
242 tx -> tx.merge(identifier, ace, CREATE_MISSING_PARENTS))),
243 NeutronSecurityRuleConstants.DJC_MAX_RETRIES);
244 } catch (Exception ex) {
246 If there are out of sequence events where-in Sg-Rule delete could occur after SecurityGroup delete.
247 we would hit with exception here, trying to delete a child-node, after it's parent has got deleted.
248 Logging it as Warn, because if such event occur we are handling it in the AclEventListeners' Remove method.
250 LOG.warn("Exception occured while removing acl for security rule: {}. ", securityRule, ex);
255 protected void update(InstanceIdentifier<SecurityRule> instanceIdentifier,
256 SecurityRule oldSecurityRule, SecurityRule updatedSecurityRule) {
257 // security rule updation is not supported from openstack, so no need to handle update.
258 LOG.trace("updates on security rules not supported.");
262 protected NeutronSecurityRuleListener getDataTreeChangeListener() {