/*
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.groupbasedpolicy.neutron.mapper.mapping.rule;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.ArrayList;
import java.util.List;
import org.opendaylight.groupbasedpolicy.api.sf.EtherTypeClassifierDefinition;
import org.opendaylight.groupbasedpolicy.api.sf.IpProtoClassifierDefinition;
import org.opendaylight.groupbasedpolicy.api.sf.L4ClassifierDefinition;
import org.opendaylight.groupbasedpolicy.neutron.mapper.util.MappingUtils;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ContractId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ParameterName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.SubjectName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.change.action.of.security.group.rules.input.action.ActionChoice;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.change.action.of.security.group.rules.input.action.action.choice.AllowActionCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.neutron.gbp.mapper.rev150513.change.action.of.security.group.rules.input.action.action.choice.SfcActionCase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.HasDirection.Direction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.action.refs.ActionRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRef.ConnectionTracking;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.classifier.refs.ClassifierRefBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.endpoint.identification.constraints.EndpointIdentificationConstraints;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.endpoint.identification.constraints.EndpointIdentificationConstraintsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.endpoint.identification.constraints.endpoint.identification.constraints.L3EndpointIdentificationConstraintsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.endpoint.identification.constraints.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraint;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.has.endpoint.identification.constraints.endpoint.identification.constraints.l3.endpoint.identification.constraints.PrefixConstraintBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValueBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.parameter.value.RangeValueBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.Clause;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.ClauseBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.ConsumerMatchers;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.contract.clause.ConsumerMatchersBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstance;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.policy.subject.feature.instances.ClassifierInstanceBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionEgress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.DirectionIngress;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV4;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.EthertypeV6;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolBase;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolIcmpV6;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolTcp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.constants.rev150712.ProtocolUdp;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.SecurityRuleAttributes;
import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.secgroups.rev150712.security.rules.attributes.security.rules.SecurityRule;
import com.google.common.collect.ImmutableList;
public class SecRuleEntityDecoder {
private SecRuleEntityDecoder() {
throw new UnsupportedOperationException("Cannot create an instace.");
}
public static ContractId getContractId(SecurityRule secRule) {
return new ContractId(secRule.getUuid().getValue());
}
public static ClassifierInstance getClassifierInstance(SecurityRule secRule) {
ClassifierInstanceBuilder classifierBuilder = new ClassifierInstanceBuilder();
List<ParameterValue> params = new ArrayList<>();
Integer portMin = secRule.getPortRangeMin();
Integer portMax = secRule.getPortRangeMax();
if (portMin != null && portMax != null) {
classifierBuilder.setClassifierDefinitionId(L4ClassifierDefinition.DEFINITION.getId());
if (portMin.equals(portMax)) {
params.add(new ParameterValueBuilder().setName(new ParameterName(L4ClassifierDefinition.DST_PORT_PARAM))
.setIntValue(portMin.longValue())
.build());
} else {
params.add(new ParameterValueBuilder().setName(new ParameterName(L4ClassifierDefinition.DST_PORT_RANGE_PARAM))
.setRangeValue(
new RangeValueBuilder().setMin(portMin.longValue()).setMax(portMax.longValue()).build())
.build());
}
}
Long protocol = getProtocol(secRule);
if (protocol != null) {
if (classifierBuilder.getClassifierDefinitionId() == null) {
classifierBuilder.setClassifierDefinitionId(IpProtoClassifierDefinition.DEFINITION.getId());
}
params.add(new ParameterValueBuilder().setName(new ParameterName(IpProtoClassifierDefinition.PROTO_PARAM))
.setIntValue(protocol)
.build());
}
Long ethertype = getEtherType(secRule);
if (ethertype != null) {
if (classifierBuilder.getClassifierDefinitionId() == null) {
classifierBuilder.setClassifierDefinitionId(EtherTypeClassifierDefinition.DEFINITION.getId());
}
params.add(new ParameterValueBuilder().setName(new ParameterName(EtherTypeClassifierDefinition.ETHERTYPE_PARAM))
.setIntValue(ethertype)
.build());
}
ClassifierName classifierName = SecRuleNameDecoder.getClassifierInstanceName(secRule);
return classifierBuilder.setParameterValue(params).setName(new ClassifierName(classifierName)).build();
}
public static ActionRef createActionRefFromActionChoice(ActionChoice action) {
if(action instanceof SfcActionCase){
return MappingUtils.createSfcActionRef(((SfcActionCase) action).getSfcChainName());
} else if (action instanceof AllowActionCase) {
return MappingUtils.ACTION_REF_ALLOW;
}
return null;
}
public static ClassifierRef getClassifierRef(SecurityRule secRule) {
checkNotNull(secRule);
ClassifierName classifierInstanceName = SecRuleNameDecoder.getClassifierInstanceName(secRule);
ClassifierRefBuilder classifierRefBuilder = new ClassifierRefBuilder()
.setConnectionTracking(ConnectionTracking.Reflexive).setInstanceName(classifierInstanceName);
Direction direction = getDirection(secRule);
classifierRefBuilder.setDirection(direction);
ClassifierName classifierRefName = SecRuleNameDecoder.getClassifierRefName(secRule);
return classifierRefBuilder.setName(classifierRefName).build();
}
/**
* @param secRule
* @return direction resolved from {@link SecurityRule#getDirection()}
* @throws IllegalArgumentException if return value of
* {@link SecurityRule#getDirection()} is other than {@link DirectionIngress} or
* {@link DirectionEgress}
*/
public static Direction getDirection(SecurityRule secRule) {
Class<? extends DirectionBase> direction = secRule.getDirection();
if (direction == null) {
throw new IllegalArgumentException("Direction cannot be null.");
}
if (direction.isAssignableFrom(DirectionIngress.class)) {
return Direction.In;
}
if (direction.isAssignableFrom(DirectionEgress.class)) {
return Direction.Out;
}
throw new IllegalArgumentException("Direction " + direction + " from security group rule "
+ secRule + " is not supported. Direction can be only 'ingress' or 'egress'.");
}
/**
* @param secRule {@link SecurityRule#getRemoteIpPrefix()} is used for EIC
* and subject selection
* @return clause with the subject and with a consumer matcher containing EIC
*/
public static Clause getClause(SecurityRule secRule) {
checkNotNull(secRule);
SubjectName subjectName = SecRuleNameDecoder.getSubjectName(secRule);
ClauseBuilder clauseBuilder =
new ClauseBuilder().setSubjectRefs(ImmutableList.of(subjectName)).setName(SecRuleNameDecoder.getClauseName(secRule));
IpPrefix remoteIpPrefix = secRule.getRemoteIpPrefix();
if (remoteIpPrefix != null) {
clauseBuilder.setConsumerMatchers(createConsumerMatchersWithEic(remoteIpPrefix));
}
return clauseBuilder.build();
}
private static ConsumerMatchers createConsumerMatchersWithEic(IpPrefix ipPrefix) {
PrefixConstraint consumerPrefixConstraint = new PrefixConstraintBuilder().setIpPrefix(ipPrefix).build();
EndpointIdentificationConstraints eic =
new EndpointIdentificationConstraintsBuilder()
.setL3EndpointIdentificationConstraints(new L3EndpointIdentificationConstraintsBuilder()
.setPrefixConstraint(ImmutableList.<PrefixConstraint>of(consumerPrefixConstraint)).build())
.build();
return new ConsumerMatchersBuilder().setEndpointIdentificationConstraints(eic).build();
}
public static boolean isEtherTypeOfOneWithinTwo(SecurityRule one, SecurityRule two) {
Long oneEtherType = getEtherType(one);
Long twoEtherType = getEtherType(two);
return twoIsNullOrEqualsOne(oneEtherType, twoEtherType);
}
public static boolean isProtocolOfOneWithinTwo(SecurityRule one, SecurityRule two) {
Long oneProtocol = getProtocol(one);
Long twoProtocol = getProtocol(two);
return twoIsNullOrEqualsOne(oneProtocol, twoProtocol);
}
private static <T> boolean twoIsNullOrEqualsOne(T one, T two) {
if (two == null)
return true;
if (two.equals(one))
return true;
return false;
}
public static boolean isPortsOfOneWithinTwo(SecurityRule one, SecurityRule two) {
Integer onePortMin = one.getPortRangeMin();
Integer onePortMax = one.getPortRangeMax();
Integer twoPortMin = two.getPortRangeMin();
Integer twoPortMax = two.getPortRangeMax();
if (twoPortMin == null && twoPortMax == null) {
return true;
}
if ((onePortMin != null && twoPortMin != null && onePortMin >= twoPortMin)
&& (onePortMax != null && twoPortMax != null && onePortMax <= twoPortMax)) {
return true;
}
return false;
}
/**
* @param secRule
* @return {@code null} if {@link SecurityRule#getEthertype()} is null; Otherwise ethertype
* number
* @throws IllegalArgumentException if return value of
* {@link SecurityRule#getEthertype()} is other {@link EthertypeV4} or
* {@link EthertypeV6}
*/
public static Long getEtherType(SecurityRule secRule) {
Class<? extends EthertypeBase> ethertype = secRule.getEthertype();
if (ethertype == null) {
return null;
}
if (ethertype.isAssignableFrom(EthertypeV4.class)) {
return EtherTypeClassifierDefinition.IPv4_VALUE;
}
if (ethertype.isAssignableFrom(EthertypeV6.class)) {
return EtherTypeClassifierDefinition.IPv6_VALUE;
}
throw new IllegalArgumentException("Ethertype " + ethertype + " is not supported.");
}
/**
* @param secRule
* @return {@code null} if {@link SecurityRule#getProtocol()} is null; Otherwise protocol number
* @throws IllegalArgumentException if return value of
* {@link SecurityRule#getProtocol()} is other than {@link ProtocolTcp},
* {@link ProtocolUdp}, {@link ProtocolIcmp}, {@link ProtocolIcmpV6}
*/
public static Long getProtocol(SecurityRule secRule) {
SecurityRuleAttributes.Protocol protocol = secRule.getProtocol();
if (protocol == null) {
return null;
}
if (protocol.getUint8() != null) {
return protocol.getUint8().longValue();
}
if (protocol.getIdentityref() != null) {
if (protocol.getIdentityref().equals(ProtocolTcp.class)) {
return IpProtoClassifierDefinition.TCP_VALUE;
}
if (protocol.getIdentityref().equals(ProtocolUdp.class)) {
return IpProtoClassifierDefinition.UDP_VALUE;
}
if (protocol.getIdentityref().equals(ProtocolIcmp.class)) {
return IpProtoClassifierDefinition.ICMP_VALUE;
}
if (protocol.getIdentityref().equals(ProtocolIcmpV6.class)) {
return IpProtoClassifierDefinition.ICMPv6_VALUE;
}
}
throw new IllegalArgumentException("Neutron Security Rule Protocol value " + protocol + " is not supported.");
}
}