4deb38f52c807defe32343779587e9dd6ac3d917
[honeycomb.git] / v3po / v3po2vpp / src / main / java / io / fd / honeycomb / v3po / translate / v3po / interfaces / ip / Ipv4Customizer.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.interfaces.ip;
18
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21
22 import com.google.common.base.Optional;
23 import io.fd.honeycomb.v3po.translate.spi.write.ChildWriterCustomizer;
24 import io.fd.honeycomb.v3po.translate.v3po.util.NamingContext;
25 import io.fd.honeycomb.v3po.translate.v3po.util.FutureJVppCustomizer;
26 import io.fd.honeycomb.v3po.translate.v3po.util.VppApiInvocationException;
27 import io.fd.honeycomb.v3po.translate.v3po.utils.V3poUtils;
28 import io.fd.honeycomb.v3po.translate.write.WriteContext;
29 import io.fd.honeycomb.v3po.translate.write.WriteFailedException;
30 import java.util.concurrent.CompletionStage;
31 import javax.annotation.Nonnull;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
33 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.Interface1;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.Ipv4;
35 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.Address;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.Subnet;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.Netmask;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.ip.rev140616.interfaces._interface.ipv4.address.subnet.PrefixLength;
39 import org.opendaylight.yangtools.yang.binding.DataObject;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
41 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddress;
42 import org.openvpp.jvpp.dto.SwInterfaceAddDelAddressReply;
43 import org.openvpp.jvpp.future.FutureJVpp;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 public class Ipv4Customizer extends FutureJVppCustomizer implements ChildWriterCustomizer<Ipv4> {
48
49     private static final Logger LOG = LoggerFactory.getLogger(Ipv4Customizer.class);
50     private final NamingContext interfaceContext;
51
52     public Ipv4Customizer(final FutureJVpp vppApi, final NamingContext interfaceContext) {
53         super(vppApi);
54         this.interfaceContext = interfaceContext;
55     }
56
57     // TODO replace guava's Optionals with Java8
58     @Nonnull
59     @Override
60     public Optional<Ipv4> extract(@Nonnull final InstanceIdentifier<Ipv4> currentId,
61                                   @Nonnull final DataObject parentData) {
62         return Optional.fromNullable(((Interface1) parentData).getIpv4());
63     }
64
65     @Override
66     public void writeCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
67                                        @Nonnull final Ipv4 dataAfter, @Nonnull final WriteContext writeContext)
68         throws WriteFailedException {
69         try {
70             final String ifcName = id.firstKeyOf(Interface.class).getName();
71             setIpv4(id, ifcName, dataAfter, writeContext);
72         } catch (VppApiInvocationException e) {
73             LOG.warn("Create of Ipv4 failed", e);
74             throw new WriteFailedException.CreateFailedException(id, dataAfter, e);
75         }
76     }
77
78     @Override
79     public void updateCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
80                                         @Nonnull final Ipv4 dataBefore, @Nonnull final Ipv4 dataAfter,
81                                         @Nonnull final WriteContext writeContext)
82         throws WriteFailedException {
83         final String ifcName = id.firstKeyOf(Interface.class).getName();
84
85         // TODO handle update in a better way
86         try {
87             setIpv4(id, ifcName, dataAfter, writeContext);
88         } catch (VppApiInvocationException e) {
89             LOG.warn("Update of Ipv4 failed", e);
90             throw new WriteFailedException.UpdateFailedException(id, dataBefore, dataAfter, e);
91         }
92     }
93
94     @Override
95     public void deleteCurrentAttributes(@Nonnull final InstanceIdentifier<Ipv4> id,
96                                         @Nonnull final Ipv4 dataBefore, @Nonnull final WriteContext writeContext) {
97         // TODO implement delete
98     }
99
100     private void setIpv4(final InstanceIdentifier<Ipv4> id, final String name, final Ipv4 ipv4,
101                          final WriteContext writeContext)
102         throws WriteFailedException, VppApiInvocationException {
103         final int swIfc = interfaceContext.getIndex(name, writeContext.getMappingContext());
104
105         for (Address ipv4Addr : ipv4.getAddress()) {
106             Subnet subnet = ipv4Addr.getSubnet();
107
108             if (subnet instanceof PrefixLength) {
109                 setPrefixLengthSubnet(name, swIfc, ipv4Addr, (PrefixLength) subnet);
110             } else if (subnet instanceof Netmask) {
111                 setNetmaskSubnet();
112             } else {
113                 // FIXME how does choice extensibility work
114                 // FIXME it is not even possible to create a dedicated customizer for Interconnection, since it's not a DataObject
115                 // FIXME we might need a choice customizer
116                 // THis choice is already from augment, so its probably not possible to augment augmented choice
117                 LOG.error("Unable to handle subnet of type {}", subnet.getClass());
118                 throw new WriteFailedException(id, "Unable to handle subnet of type " + subnet.getClass());
119             }
120         }
121     }
122
123     private void setNetmaskSubnet() {
124         // FIXME
125         throw new UnsupportedOperationException("Unimplemented");
126     }
127
128     private void setPrefixLengthSubnet(final String name, final int swIfc, final Address ipv4Addr,
129                                        final PrefixLength subnet) throws VppApiInvocationException {
130         Short plen = subnet.getPrefixLength();
131         LOG.debug("Setting Subnet(prefix-length) for interface: {}, {}. Subnet: {}, Ipv4: {}", name, swIfc, subnet,
132             ipv4Addr);
133
134         byte[] addr = V3poUtils.ipv4AddressNoZoneToArray(ipv4Addr.getIp());
135
136         checkArgument(plen > 0, "Invalid length");
137         checkNotNull(addr, "Null address");
138
139         final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
140             getFutureJVpp().swInterfaceAddDelAddress(getSwInterfaceAddDelAddressRequest(
141                 swIfc, (byte) 1 /* isAdd */, (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, plen.byteValue(), addr));
142
143         final SwInterfaceAddDelAddressReply reply =
144             V3poUtils.getReply(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture());
145
146         if (reply.retval < 0) {
147             LOG.warn("Failed to set Subnet(prefix-length) for interface: {}, {},  Subnet: {}, Ipv4: {}", name, swIfc,
148                 subnet, ipv4Addr);
149             throw new VppApiInvocationException("swInterfaceAddDelAddress", reply.context, reply.retval);
150         } else {
151             LOG.debug("Subnet(prefix-length) set successfully for interface: {}, {},  Subnet: {}, Ipv4: {}", name,
152                 swIfc, subnet, ipv4Addr);
153         }
154     }
155
156     private SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd, final byte ipv6,
157                                                                         final byte deleteAll,
158                                                                         final byte length, final byte[] addr) {
159         final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
160         swInterfaceAddDelAddress.swIfIndex = swIfc;
161         swInterfaceAddDelAddress.isAdd = isAdd;
162         swInterfaceAddDelAddress.isIpv6 = ipv6;
163         swInterfaceAddDelAddress.delAll = deleteAll;
164         swInterfaceAddDelAddress.address = addr;
165         swInterfaceAddDelAddress.addressLength = length;
166         return swInterfaceAddDelAddress;
167     }
168
169 }