f0d260de246917ac91f50b576170fe08aa91519a
[honeycomb.git] / v3po / v3po2vpp / src / main / java / io / fd / honeycomb / v3po / translate / v3po / interfacesstate / L2Customizer.java
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package io.fd.honeycomb.v3po.translate.v3po.interfacesstate;
18
19 import static com.google.common.base.Preconditions.checkState;
20
21 import com.google.common.base.Preconditions;
22 import io.fd.honeycomb.v3po.translate.read.ReadContext;
23 import io.fd.honeycomb.v3po.translate.read.ReadFailedException;
24 import io.fd.honeycomb.v3po.translate.spi.read.ChildReaderCustomizer;
25 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
26 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
27 import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
28 import java.util.Optional;
29 import java.util.concurrent.CompletableFuture;
30 import javax.annotation.Nonnull;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.VppInterfaceStateAugmentationBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.L2Builder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces.state._interface.l2.interconnection.BridgeBasedBuilder;
37 import org.opendaylight.yangtools.concepts.Builder;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.openvpp.jvpp.dto.BridgeDomainDetails;
41 import org.openvpp.jvpp.dto.BridgeDomainDetailsReplyDump;
42 import org.openvpp.jvpp.dto.BridgeDomainDump;
43 import org.openvpp.jvpp.dto.BridgeDomainSwIfDetails;
44 import org.openvpp.jvpp.dto.SwInterfaceDetails;
45 import org.openvpp.jvpp.future.FutureJVpp;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 /**
50  * Customizer for reading ietf-interfaces:interfaces-state/interface/iface_name/v3po:l2
51  */
52 public class L2Customizer extends FutureJVppCustomizer
53         implements ChildReaderCustomizer<L2, L2Builder> {
54
55     private static final Logger LOG = LoggerFactory.getLogger(L2Customizer.class);
56     private final NamingContext interfaceContext;
57     private final NamingContext bridgeDomainContext;
58
59     public L2Customizer(@Nonnull final FutureJVpp futureJvpp,
60                         @Nonnull final NamingContext interfaceContext,
61                         @Nonnull final NamingContext bridgeDomainContext) {
62         super(futureJvpp);
63         this.interfaceContext = Preconditions.checkNotNull(interfaceContext, "interfaceContext should not be null");
64         this.bridgeDomainContext = Preconditions.checkNotNull(bridgeDomainContext, "bridgeDomainContext should not be null");
65     }
66
67     @Override
68     public void merge(@Nonnull final Builder<? extends DataObject> parentBuilder, @Nonnull final L2 readValue) {
69         ((VppInterfaceStateAugmentationBuilder) parentBuilder).setL2(readValue);
70     }
71
72     @Nonnull
73     @Override
74     public L2Builder getBuilder(@Nonnull final InstanceIdentifier<L2> id) {
75         return new L2Builder();
76     }
77
78     @Override
79     public void readCurrentAttributes(@Nonnull final InstanceIdentifier<L2> id, @Nonnull final L2Builder builder,
80                                       @Nonnull final ReadContext ctx) throws ReadFailedException {
81         LOG.debug("Reading attributes for L2: {}", id);
82         final InterfaceKey key = id.firstKeyOf(Interface.class);
83         final int ifaceId = interfaceContext.getIndex(key.getName(), ctx.getMappingContext());
84
85         final SwInterfaceDetails iface = InterfaceUtils.getVppInterfaceDetails(getFutureJVpp(), key,
86                 ifaceId, ctx.getModificationCache());
87         LOG.debug("Interface details for interface: {}, details: {}", key.getName(), iface);
88
89         final BridgeDomainDetailsReplyDump dumpReply = getDumpReply();
90         final Optional<BridgeDomainSwIfDetails> bdForInterface = getBridgeDomainForInterface(ifaceId, dumpReply);
91         if (bdForInterface.isPresent()) {
92             final BridgeDomainSwIfDetails bdSwIfDetails = bdForInterface.get();
93             final BridgeBasedBuilder bbBuilder = new BridgeBasedBuilder();
94             bbBuilder.setBridgeDomain(bridgeDomainContext.getName(bdSwIfDetails.bdId, ctx.getMappingContext()));
95
96             // Set BVI if the bridgeDomainDetails.bviSwIfIndex == current sw if index
97             final Optional<BridgeDomainDetails> bridgeDomainForInterface =
98                 getBridgeDomainForInterface(ifaceId, dumpReply, bdForInterface.get().bdId);
99             // Since we already found an interface assigned to a bridge domain, the details for BD must be present
100             checkState(bridgeDomainForInterface.isPresent());
101             if(bridgeDomainForInterface.get().bviSwIfIndex == ifaceId) {
102                 bbBuilder.setBridgedVirtualInterface(true);
103             }
104
105             if (bdSwIfDetails.shg != 0) {
106                 bbBuilder.setSplitHorizonGroup((short)bdSwIfDetails.shg);
107             }
108             builder.setInterconnection(bbBuilder.build());
109         }
110
111         // TODO is there a way to check if interconnection is XconnectBased?
112     }
113
114     private Optional<BridgeDomainSwIfDetails> getBridgeDomainForInterface(final int ifaceId,
115                                                                           final BridgeDomainDetailsReplyDump reply) {
116         if (null == reply || null == reply.bridgeDomainSwIfDetails || reply.bridgeDomainSwIfDetails.isEmpty()) {
117             return Optional.empty();
118         }
119         // interface can be added to only one BD only
120         return reply.bridgeDomainSwIfDetails.stream().filter(a -> a.swIfIndex == ifaceId).findFirst();
121     }
122
123
124     private Optional<BridgeDomainDetails> getBridgeDomainForInterface(final int ifaceId,
125                                                                       final BridgeDomainDetailsReplyDump reply,
126                                                                       int bdId) {
127         return reply.bridgeDomainDetails.stream().filter(a -> a.bdId == bdId).findFirst();
128     }
129
130     private BridgeDomainDetailsReplyDump getDumpReply() {
131         // We need to perform full bd dump, because there is no way
132         // to ask VPP for BD details given interface id/name (TODO add it to vpp.api?)
133         // TODO cache dump result
134         final BridgeDomainDump request = new BridgeDomainDump();
135         request.bdId = -1;
136
137         final CompletableFuture<BridgeDomainDetailsReplyDump> bdCompletableFuture =
138                 getFutureJVpp().bridgeDomainSwIfDump(request).toCompletableFuture();
139         return V3poUtils.getReply(bdCompletableFuture);
140     }
141 }