Merge "Add default flows validation to IT"
[netvirt.git] / vpnservice / neutronvpn / 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 com.google.common.collect.ImmutableBiMap;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
13 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
14 import org.opendaylight.genius.mdsalutil.MDSALUtil;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.AccessLists;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.Acl;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.AclKey;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.AccessListEntries;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.Ace;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceBuilder;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.access.control.list.rev160218.access.lists.acl.access.list.entries.AceKey;
22 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;
23 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;
24 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;
25 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;
26 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;
27 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;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.DestinationPortRangeBuilder;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.packet.fields.rev160218.acl.transport.header.fields.SourcePortRangeBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttr;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.SecurityRuleAttrBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.SecurityRuleAttributes;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.SecurityRules;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 public class NeutronSecurityRuleListener
52         extends AsyncDataTreeChangeListenerBase<SecurityRule, NeutronSecurityRuleListener> {
53     private static final Logger LOG = LoggerFactory.getLogger(NeutronSecurityRuleListener.class);
54     private final DataBroker dataBroker;
55     private static final ImmutableBiMap<Class<? extends DirectionBase>, Class<? extends org.opendaylight.yang.gen.
56             v1.urn.opendaylight.netvirt.aclservice.rev160608.DirectionBase>> DIRECTION_MAP = ImmutableBiMap.of(
57             DirectionEgress.class, NeutronSecurityRuleConstants.DIRECTION_EGRESS,
58             DirectionIngress.class, NeutronSecurityRuleConstants.DIRECTION_INGRESS);
59     private static final ImmutableBiMap<Class<? extends ProtocolBase>, Short> PROTOCOL_MAP = ImmutableBiMap.of(
60             ProtocolIcmp.class, NeutronSecurityRuleConstants.PROTOCOL_ICMP,
61             ProtocolTcp.class, NeutronSecurityRuleConstants.PROTOCOL_TCP,
62             ProtocolUdp.class, NeutronSecurityRuleConstants.PROTOCOL_UDP,
63             ProtocolIcmpV6.class, NeutronSecurityRuleConstants.PROTOCOL_ICMPV6);
64
65     public NeutronSecurityRuleListener(final DataBroker dataBroker) {
66         super(SecurityRule.class, NeutronSecurityRuleListener.class);
67         this.dataBroker = dataBroker;
68     }
69
70     public void start() {
71         LOG.info("{} start", getClass().getSimpleName());
72         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
73     }
74
75     @Override
76     protected InstanceIdentifier<SecurityRule> getWildCardPath() {
77         return InstanceIdentifier.create(Neutron.class).child(SecurityRules.class).child(SecurityRule.class);
78     }
79
80     @Override
81     protected void add(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
82         if (LOG.isTraceEnabled()) {
83             LOG.trace("added securityRule: {}", securityRule);
84         }
85         try {
86             Ace ace = toAceBuilder(securityRule).build();
87             InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
88             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, identifier, ace);
89         } catch (Exception ex) {
90             LOG.error("Exception occured while adding acl for security rule: ", ex);
91         }
92     }
93
94     private InstanceIdentifier<Ace> getAceInstanceIdentifier(SecurityRule securityRule) {
95         return InstanceIdentifier
96                 .builder(AccessLists.class)
97                 .child(Acl.class,
98                         new AclKey(securityRule.getSecurityGroupId().getValue(), NeutronSecurityRuleConstants.ACLTYPE))
99                 .child(AccessListEntries.class)
100                 .child(Ace.class,
101                         new AceKey(securityRule.getUuid().getValue()))
102                 .build();
103     }
104
105     private AceBuilder toAceBuilder(SecurityRule securityRule) {
106         AceIpBuilder aceIpBuilder = new AceIpBuilder();
107         SecurityRuleAttrBuilder securityRuleAttrBuilder = new SecurityRuleAttrBuilder();
108         SourcePortRangeBuilder sourcePortRangeBuilder = new SourcePortRangeBuilder();
109         DestinationPortRangeBuilder destinationPortRangeBuilder = new DestinationPortRangeBuilder();
110         boolean isDirectionIngress = false;
111         if (securityRule.getDirection() != null) {
112             securityRuleAttrBuilder.setDirection(DIRECTION_MAP.get(securityRule.getDirection()));
113             isDirectionIngress = securityRule.getDirection().equals(DirectionIngress.class);
114         }
115         if (securityRule.getPortRangeMax() != null) {
116             if (isDirectionIngress) {
117                 sourcePortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
118             } else {
119                 destinationPortRangeBuilder.setUpperPort(new PortNumber(securityRule.getPortRangeMax()));
120             }
121         }
122         if (securityRule.getPortRangeMin() != null) {
123             if (isDirectionIngress) {
124                 sourcePortRangeBuilder.setLowerPort(new PortNumber(securityRule.getPortRangeMin()));
125                 // set source port range if lower port is specified as it is mandatory parameter in acl model
126                 aceIpBuilder.setSourcePortRange(sourcePortRangeBuilder.build());
127             } else {
128                 destinationPortRangeBuilder.setLowerPort(new PortNumber(securityRule.getPortRangeMin()));
129                 // set destination port range if lower port is specified as it is mandatory parameter in acl model
130                 aceIpBuilder.setDestinationPortRange(destinationPortRangeBuilder.build());
131             }
132         }
133         aceIpBuilder = handleRemoteIpPrefix(securityRule, aceIpBuilder, isDirectionIngress);
134         if (securityRule.getRemoteGroupId() != null) {
135             securityRuleAttrBuilder.setRemoteGroupId(securityRule.getRemoteGroupId());
136         }
137         if (securityRule.getProtocol() != null) {
138             SecurityRuleAttributes.Protocol protocol = securityRule.getProtocol();
139             if (protocol.getUint8() != null) {
140                 // uint8
141                 aceIpBuilder.setProtocol(protocol.getUint8());
142             } else {
143                 // symbolic protocol name
144                 aceIpBuilder.setProtocol(PROTOCOL_MAP.get(protocol.getIdentityref()));
145             }
146         }
147
148         MatchesBuilder matchesBuilder = new MatchesBuilder();
149         matchesBuilder.setAceType(aceIpBuilder.build());
150         // set acl action as permit for the security rule
151         ActionsBuilder actionsBuilder = new ActionsBuilder();
152         actionsBuilder.setPacketHandling(new PermitBuilder().setPermit(true).build());
153
154         AceBuilder aceBuilder = new AceBuilder();
155         aceBuilder.setKey(new AceKey(securityRule.getUuid().getValue()));
156         aceBuilder.setRuleName(securityRule.getUuid().getValue());
157         aceBuilder.setMatches(matchesBuilder.build());
158         aceBuilder.setActions(actionsBuilder.build());
159         aceBuilder.addAugmentation(SecurityRuleAttr.class, securityRuleAttrBuilder.build());
160         return aceBuilder;
161     }
162
163     private AceIpBuilder handleEtherType(SecurityRule securityRule, AceIpBuilder aceIpBuilder) {
164         if (NeutronSecurityRuleConstants.ETHERTYPE_IPV4.equals(securityRule.getEthertype())) {
165             AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
166             aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(
167                 NeutronSecurityRuleConstants.IPV4_ALL_NETWORK));
168             aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(
169                 NeutronSecurityRuleConstants.IPV4_ALL_NETWORK));
170             aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
171         } else {
172             AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
173             aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
174                 NeutronSecurityRuleConstants.IPV6_ALL_NETWORK));
175             aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
176                 NeutronSecurityRuleConstants.IPV6_ALL_NETWORK));
177             aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
178
179         }
180         return aceIpBuilder;
181     }
182
183     private AceIpBuilder handleRemoteIpPrefix(SecurityRule securityRule, AceIpBuilder aceIpBuilder,
184                                               boolean isDirectionIngress) {
185         if (securityRule.getRemoteIpPrefix() != null) {
186             if (securityRule.getRemoteIpPrefix().getIpv4Prefix() != null) {
187                 AceIpv4Builder aceIpv4Builder = new AceIpv4Builder();
188                 if (isDirectionIngress) {
189                     aceIpv4Builder.setSourceIpv4Network(new Ipv4Prefix(securityRule
190                         .getRemoteIpPrefix().getIpv4Prefix().getValue()));
191                 } else {
192                     aceIpv4Builder.setDestinationIpv4Network(new Ipv4Prefix(securityRule
193                         .getRemoteIpPrefix().getIpv4Prefix().getValue()));
194                 }
195                 aceIpBuilder.setAceIpVersion(aceIpv4Builder.build());
196             } else {
197                 AceIpv6Builder aceIpv6Builder = new AceIpv6Builder();
198                 if (isDirectionIngress) {
199                     aceIpv6Builder.setSourceIpv6Network(new Ipv6Prefix(
200                         securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
201                 } else {
202                     aceIpv6Builder.setDestinationIpv6Network(new Ipv6Prefix(
203                         securityRule.getRemoteIpPrefix().getIpv6Prefix().getValue()));
204                 }
205                 aceIpBuilder.setAceIpVersion(aceIpv6Builder.build());
206             }
207         } else {
208             if (securityRule.getEthertype() != null) {
209                 handleEtherType( securityRule, aceIpBuilder);
210             }
211         }
212
213         return aceIpBuilder;
214     }
215
216     @Override
217     protected void remove(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule securityRule) {
218         if (LOG.isTraceEnabled()) {
219             LOG.trace("removed securityRule: {}", securityRule);
220         }
221         try {
222             InstanceIdentifier<Ace> identifier = getAceInstanceIdentifier(securityRule);
223             MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, identifier);
224         } catch (Exception ex) {
225             LOG.error("Exception occured while removing acl for security rule: ", ex);
226         }
227     }
228
229     @Override
230     protected void update(InstanceIdentifier<SecurityRule> instanceIdentifier, SecurityRule oldSecurityRule, SecurityRule updatedSecurityRule) {
231         // security rule updation is not supported from openstack, so no need to handle update.
232         LOG.trace("updates on security rules not supported.");
233     }
234
235     @Override
236     protected NeutronSecurityRuleListener getDataTreeChangeListener() {
237         return this;
238     }
239 }