From b77a5725338dc700873b36c98af85d70acd7bbe4 Mon Sep 17 00:00:00 2001 From: Michal Cmarada Date: Fri, 15 Jun 2018 13:12:53 +0200 Subject: HC2VPP-304 - add SRv6 policy module new models: - hc2vpp-oc-srte-policy@2017-09-18.yang (ietf draft for srte-policies) - vpp-oc-srte-policy@2018-05-14.yang (augments oc-srte-policy model with VPP specific configuration) - policy-context@2018-06-07.yang defines policy contexts for policies and candidate paths new features: - adds support for writing/reading SRv6 policies - adds support for writing/reading L2 steering - adds support for writing/reading L3 steering - implements support for FIB table management (HC2VPP-345) Change-Id: Ie83ac8ecdcc0e46086e1ecdaecbb811746151c2f Signed-off-by: Michal Cmarada --- .../read/policy/request/PolicyReadRequest.java | 281 +++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 srv6/srv6-impl/src/main/java/io/fd/hc2vpp/srv6/read/policy/request/PolicyReadRequest.java (limited to 'srv6/srv6-impl/src/main/java/io/fd/hc2vpp/srv6/read/policy/request/PolicyReadRequest.java') diff --git a/srv6/srv6-impl/src/main/java/io/fd/hc2vpp/srv6/read/policy/request/PolicyReadRequest.java b/srv6/srv6-impl/src/main/java/io/fd/hc2vpp/srv6/read/policy/request/PolicyReadRequest.java new file mode 100644 index 000000000..8117d4d91 --- /dev/null +++ b/srv6/srv6-impl/src/main/java/io/fd/hc2vpp/srv6/read/policy/request/PolicyReadRequest.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2018 Bell Canada, Pantheon Technologies and/or its affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fd.hc2vpp.srv6.read.policy.request; + +import com.google.common.base.Preconditions; +import io.fd.hc2vpp.srv6.read.ReadRequest; +import io.fd.hc2vpp.srv6.util.CandidatePathContextManager; +import io.fd.hc2vpp.srv6.util.JVppRequest; +import io.fd.hc2vpp.srv6.util.PolicyContextManager; +import io.fd.hc2vpp.srv6.util.Srv6Util; +import io.fd.honeycomb.translate.read.ReadContext; +import io.fd.honeycomb.translate.read.ReadFailedException; +import io.fd.honeycomb.translate.util.read.cache.DumpCacheManager; +import io.fd.vpp.jvpp.core.dto.SrPoliciesDetails; +import io.fd.vpp.jvpp.core.dto.SrPoliciesDetailsReplyDump; +import io.fd.vpp.jvpp.core.dto.SrPoliciesDump; +import io.fd.vpp.jvpp.core.future.FutureJVppCore; +import io.fd.vpp.jvpp.core.types.Srv6Sid; +import io.fd.vpp.jvpp.core.types.Srv6SidList; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import javax.annotation.Nonnull; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.BindingSidAllocMode; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.DataplaneType; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.PathExplicitlyDefined; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.PolicyAdminState; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.SegmentListOperState; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.SegmentType; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.SidValueType; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.binding.sid.properties.BindingSidBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.binding.sid.properties.binding.sid.StateBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.candidate.paths.CandidatePathsBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.candidate.paths.candidate.paths.CandidatePath; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.candidate.paths.candidate.paths.CandidatePathBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.NamedSegmentList; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.NamedSegmentListBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.NamedSegmentListKey; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.named.segment.list.SegmentsBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.named.segment.list.segments.Segment; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.named.segment.list.segments.SegmentBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.named.segment.lists.named.segment.lists.named.segment.list.segments.SegmentKey; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.path.segment.list.properties.SegmentListsBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.path.segment.list.properties.segment.lists.SegmentList; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.path.segment.list.properties.segment.lists.SegmentListBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.policies.policies.Policy; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.policies.policies.PolicyBuilder; +import org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.policies.policies.PolicyKey; +import org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.SegmentRoutingPolicyBehavior; +import org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.SegmentRoutingPolicyType; +import org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.VppSrPolicyAugmentation; +import org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.VppSrPolicyAugmentationBuilder; +import org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.segment.routing.traffic.engineering.policies.policy.VppSrPolicyBuilder; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.policy.context.rev180607.srv6.candidate.path.context.attributes.srv6.candidate.path.mappings.Srv6CandidatePathMapping; +import org.opendaylight.yang.gen.v1.urn.honeycomb.params.xml.ns.yang.policy.context.rev180607.srv6.policy.context.attributes.srv6.policy.mappings.Srv6PolicyMapping; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.fib.table.management.rev180521.Ipv6; +import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.vpp.fib.table.management.rev180521.VniReference; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PolicyReadRequest extends JVppRequest + implements ReadRequest { + + private static final String DASH_SEPARATOR = "-"; + private static final Logger LOG = LoggerFactory.getLogger(PolicyReadRequest.class); + private static final SrPoliciesDump STATIC_DUMP_REQUEST = new SrPoliciesDump(); + private static final SrPoliciesDetailsReplyDump STATIC_EMPTY_REPLY = new SrPoliciesDetailsReplyDump(); + private final PolicyContextManager policyCtx; + private final CandidatePathContextManager candidateCtx; + private final DumpCacheManager dumpManager; + + public PolicyReadRequest(FutureJVppCore futureJVpp, PolicyContextManager policyCtx, + final CandidatePathContextManager candidateCtx) { + super(futureJVpp); + this.policyCtx = policyCtx; + this.candidateCtx = candidateCtx; + this.dumpManager = new DumpCacheManager.DumpCacheManagerBuilder().acceptOnly( + SrPoliciesDetailsReplyDump.class) + .withExecutor((identifier, params) -> getReplyForRead( + getApi().srPoliciesDump(STATIC_DUMP_REQUEST).toCompletableFuture(), identifier)) + .build(); + } + + @Nonnull + public List readAllKeys(@Nonnull InstanceIdentifier id, @Nonnull ReadContext ctx) + throws ReadFailedException { + return dumpManager.getDump(id, ctx.getModificationCache()).or(STATIC_EMPTY_REPLY).srPoliciesDetails.stream() + .map(srPoliciesDetails -> arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr)) + .map(bsid -> parsePolicyKey(ctx, bsid)) + .collect(Collectors.toList()); + } + + private PolicyKey parsePolicyKey(final @Nonnull ReadContext ctx, final Ipv6Address bsid) { + Srv6PolicyMapping policy = policyCtx.getPolicy(bsid, ctx.getMappingContext()); + return new PolicyKey(policy.getColor(), new IpAddress(policy.getEndpoint())); + } + + @Override + public void readSpecific(@Nonnull InstanceIdentifier id, @Nonnull ReadContext ctx, + @Nonnull PolicyBuilder builder) throws ReadFailedException { + PolicyKey key = id.firstKeyOf(Policy.class); + Ipv6Address bsid = + policyCtx.getPolicyBsid(key.getColor(), key.getEndpoint().getIpv6Address(), ctx.getMappingContext()); + + dumpManager.getDump(id, ctx.getModificationCache()).or(STATIC_EMPTY_REPLY).srPoliciesDetails.stream() + .filter(srPoliciesDetails -> arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr).getValue() + .equals(bsid.getValue())) + .findFirst() + .ifPresent((SrPoliciesDetails details) -> bindPolicy(details, ctx, builder)); + } + + private void bindPolicy(SrPoliciesDetails srPoliciesDetails, @Nonnull ReadContext ctx, + final PolicyBuilder builder) { + + Ipv6Address bsid = arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr); + Srv6PolicyMapping policy = policyCtx.getPolicy(bsid, ctx.getMappingContext()); + IpAddress endpoint = new IpAddress(policy.getEndpoint()); + builder.setName(policy.getName()).setEndpoint(endpoint).setColor(policy.getColor()); + builder.setKey(new PolicyKey(policy.getColor(), endpoint)); + builder.setBindingSid(new BindingSidBuilder().setState( + new StateBuilder().setType(DataplaneType.Srv6).setAllocMode(BindingSidAllocMode.Explicit) + .setValue(new SidValueType(new IpAddress(bsid))).build()).build()); + builder.addAugmentation(VppSrPolicyAugmentation.class, new VppSrPolicyAugmentationBuilder() + .setVppSrPolicy(new VppSrPolicyBuilder().setState( + new org.opendaylight.yang.gen.v1.urn.hc2vpp.params.xml.ns.yang.vpp.oc.srte.policy.rev180514.sr.policy.StateBuilder() + .setPolicyBehavior( + SegmentRoutingPolicyBehavior.forValue((int) srPoliciesDetails.isEncap)) + .setPolicyType(SegmentRoutingPolicyType.forValue((int) srPoliciesDetails.type)) + .setTableId(new VniReference(Integer.toUnsignedLong(srPoliciesDetails.fibTable))) + .setAddressFamily(Ipv6.class) + .build()).build()) + .build()); + + builder.setState( + new org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.policy.properties.StateBuilder() + .setName(policy.getName()).setEndpoint(endpoint) + .setColor(policy.getColor()).setAdminState(PolicyAdminState.UP) + .build()); + + builder.setCandidatePaths( + new CandidatePathsBuilder().setCandidatePath(resolveCandidatePaths(srPoliciesDetails, ctx)).build()); + } + + private List resolveCandidatePaths(final SrPoliciesDetails srPoliciesDetails, + final ReadContext ctx) { + List candidatePaths = new ArrayList<>(); + //only one candidate path can be selected and present on device at the same time + if (srPoliciesDetails.sidLists == null) { + LOG.debug("No policy segments found for BSID: {}", srPoliciesDetails.bsid); + return candidatePaths; + } + Ipv6Address bsid = arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr); + Srv6CandidatePathMapping candidatePath = + candidateCtx.getCandidatePath(bsid, ctx.getMappingContext()); + + CandidatePathBuilder candidatePathBuilder = + new CandidatePathBuilder() + .setDistinguisher(candidatePath.getDistinguisher()) + .setPreference(candidatePath.getPreference()) + .setProvisioningMethod(candidatePath.getProvisioningMethod()) + .setName(candidatePath.getName()); + + candidatePathBuilder.setState( + new org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.candidate.paths.candidate.paths.candidate.path.StateBuilder() + .setDistinguisher(candidatePath.getDistinguisher()) + .setPreference(candidatePath.getPreference()) + .setProvisioningMethod(candidatePath.getProvisioningMethod()) + .setComputationMethod(PathExplicitlyDefined.class) + .setName(candidatePath.getName()) + .build()); + candidatePathBuilder.setBindingSid(new BindingSidBuilder().setState( + new StateBuilder().setAllocMode(BindingSidAllocMode.Explicit).setType(DataplaneType.Srv6) + .setValue(new SidValueType(new IpAddress(bsid))).build()).build()); + + List segments = new ArrayList<>(); + for (Srv6SidList sidlist : srPoliciesDetails.sidLists) { + long weight = Integer.toUnsignedLong(sidlist.weight); + SegmentListBuilder segmentListBuilder = + new SegmentListBuilder().setName(Srv6Util.getCandidatePathName(bsid, weight)); + segmentListBuilder.setState( + new org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.path.segment.list.StateBuilder() + .setName(Srv6Util.getCandidatePathName(bsid, weight)) + .setWeight(weight) + .setOperState(SegmentListOperState.ACTIVE) + .build()); + segments.add(segmentListBuilder.build()); + } + candidatePathBuilder.setSegmentLists(new SegmentListsBuilder().setSegmentList(segments).build()); + candidatePaths.add(candidatePathBuilder.build()); + return candidatePaths; + } + + public List readNamedSegmentListKeys(final InstanceIdentifier id, + final ReadContext ctx) throws ReadFailedException { + return dumpManager.getDump(id, ctx.getModificationCache()).or(STATIC_EMPTY_REPLY).srPoliciesDetails.stream() + .map(srPoliciesDetails -> { + String bsid = arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr).getValue(); + return Arrays.stream(srPoliciesDetails.sidLists).map(srv6SidList -> srv6SidList.weight) + .map(weight -> bsid + DASH_SEPARATOR + weight).collect(Collectors.toList()); + }).flatMap(Collection::stream).map(NamedSegmentListKey::new).distinct().collect(Collectors.toList()); + } + + public void readNamedSegmentList(final InstanceIdentifier id, + final NamedSegmentListBuilder builder, + final ReadContext ctx) + throws ReadFailedException { + NamedSegmentListKey key = id.firstKeyOf(NamedSegmentList.class); + builder.setKey(key) + .setName(key.getName()) + .setState( + new org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.segment.list.properties.StateBuilder() + .setName(key.getName()) + .build()); + + Long weight = parseWeight(key); + String bsid = parseBsid(key); + Preconditions.checkNotNull(bsid, "Weight/Bsid not resolved for Iid: {}", id); + + builder.setSegments(new SegmentsBuilder().build()); + dumpManager.getDump(id, ctx.getModificationCache()).or(STATIC_EMPTY_REPLY).srPoliciesDetails.stream() + .filter(srPoliciesDetails -> arrayToIpv6AddressNoZone(srPoliciesDetails.bsid.addr).getValue() + .equals(bsid)) + .forEach(srPoliciesDetails -> Arrays.stream(srPoliciesDetails.sidLists) + .forEach(srv6SidList -> { + if (srv6SidList.weight == weight.intValue()) { + List segments = IntStream.range(0, srv6SidList.numSids) + .mapToObj(i -> parseSrv6Sid(i, srv6SidList.sids[i])) + .collect(Collectors.toList()); + builder.setSegments(new SegmentsBuilder().setSegment(segments).build()); + } + })); + } + + private Segment parseSrv6Sid(final int i, final Srv6Sid srv6Sid) { + // shifting index by 1 so it matches original indexing + long index = i + 1; + SegmentBuilder builder = new SegmentBuilder().setKey(new SegmentKey(index)).setState( + new org.opendaylight.yang.gen.v1.http.cisco.com.ns.yang.oc.srte.policy.rev170918.segment.properties.StateBuilder() + .setIndex(index) + .setType(SegmentType.Type2) + .setSidValue(new SidValueType( + new IpAddress(new Ipv6Address(arrayToIpv6AddressNoZone(srv6Sid.addr))))) + .build()); + return builder.build(); + } + + + private Long parseWeight(final NamedSegmentListKey key) { + String[] values = key.getName().split(DASH_SEPARATOR); + + return values.length == 2 + ? Long.parseLong(values[1]) + : 0; + } + + private String parseBsid(final NamedSegmentListKey key) { + String[] values = key.getName().split(DASH_SEPARATOR); + return values.length == 2 ? values[0] : null; + } + +} -- cgit 1.2.3-korg