MRI version bumpup for Aluminium
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronSecurityRuleListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.neutronvpn;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.collect.ImmutableBiMap;
13 import java.util.Collections;
14 import javax.annotation.PreDestroy;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
19 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
20 import org.opendaylight.infrautils.utils.concurrent.Executors;
21 import org.opendaylight.mdsal.binding.api.DataBroker;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceBuilder;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
31 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;
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.MatchesBuilder;
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.actions.packet.handling.PermitBuilder;
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.matches.ace.type.AceIpBuilder;
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.ace.ip.ace.ip.version.AceIpv4Builder;
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.AceIpv6Builder;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
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;
59
60 @Singleton
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);
73
74     private final DataBroker dataBroker;
75     private final ManagedNewTransactionRunner txRunner;
76     private final JobCoordinator jobCoordinator;
77
78     @Inject
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;
86     }
87
88     public void init() {
89         LOG.info("{} init", getClass().getSimpleName());
90     }
91
92     @Override
93     @PreDestroy
94     public void close() {
95         super.close();
96         Executors.shutdownAndAwaitTermination(getExecutorService());
97     }
98
99     @Override
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);
104         try {
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);
114         }
115     }
116
117     private InstanceIdentifier<Ace> getAceInstanceIdentifier(SecurityRule securityRule) {
118         return InstanceIdentifier
119                 .builder(AccessLists.class)
120                 .child(Acl.class,
121                         new AclKey(securityRule.getSecurityGroupId().getValue(), NeutronSecurityGroupConstants.ACLTYPE))
122                 .child(AccessListEntries.class)
123                 .child(Ace.class,
124                         new AceKey(securityRule.getUuid().getValue()))
125                 .build();
126     }
127
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);
136         }
137         if (securityRule.getPortRangeMax() != null) {
138             destinationPortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
139
140         }
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());
145         }
146         aceIpBuilder = handleRemoteIpPrefix(securityRule, aceIpBuilder, isDirectionIngress);
147         if (securityRule.getRemoteGroupId() != null) {
148             securityRuleAttrBuilder.setRemoteGroupId(securityRule.getRemoteGroupId());
149         }
150         if (securityRule.getProtocol() != null) {
151             SecurityRuleAttributes.Protocol protocol = securityRule.getProtocol();
152             if (protocol.getUint8() != null) {
153                 // uint8
154                 aceIpBuilder.setProtocol(protocol.getUint8());
155             } else {
156                 // symbolic protocol name
157                 aceIpBuilder.setProtocol(PROTOCOL_MAP.get(protocol.getIdentityref()));
158             }
159         }
160         securityRuleAttrBuilder.setDeleted(isDeleted);
161
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());
167
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(SecurityRuleAttr.class, securityRuleAttrBuilder.build());
174         return aceBuilder;
175     }
176
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());
185         } else {
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());
192
193         }
194         return aceIpBuilder;
195     }
196
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()));
205                 } else {
206                     aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(securityRule
207                         .getRemoteIpPrefix().getIpv4Prefix().getValue()));
208                 }
209                 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
210             } else {
211                 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
212                 if (isDirectionIngress) {
213                     aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
214                         securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
215                 } else {
216                     aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
217                         securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
218                 }
219                 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
220             }
221         } else {
222             if (securityRule.getEthertype() != null) {
223                 handleEtherType(securityRule, aceIpBuilder);
224             }
225         }
226
227         return aceIpBuilder;
228     }
229
230     @Override
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);
236         try {
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) {
244             /*
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.
248              */
249             LOG.warn("Exception occured while removing acl for security rule: {}. ", securityRule, ex);
250         }
251     }
252
253     @Override
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     }
259 }