summaryrefslogtreecommitdiffstats
path: root/l3/utils/src/main/java/io/fd/hc2vpp/l3/utils/ip/write/IpWriter.java
blob: 2ce008810c560aaa2fc334bbfaed46a8aa9feaa4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
 * Copyright (c) 2017 Cisco 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.l3.utils.ip.write;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import io.fd.hc2vpp.common.translate.util.AddressTranslator;
import io.fd.hc2vpp.common.translate.util.ByteDataTranslator;
import io.fd.hc2vpp.common.translate.util.JvppReplyConsumer;
import io.fd.hc2vpp.common.translate.util.NamingContext;
import io.fd.honeycomb.translate.MappingContext;
import io.fd.honeycomb.translate.write.WriteFailedException;
import io.fd.jvpp.core.dto.IpNeighborAddDel;
import io.fd.jvpp.core.dto.SwInterfaceAddDelAddress;
import io.fd.jvpp.core.dto.SwInterfaceAddDelAddressReply;
import io.fd.jvpp.core.future.FutureJVppCore;
import io.fd.jvpp.core.types.IpNeighbor;
import io.fd.jvpp.core.types.IpNeighborFlags;
import java.util.concurrent.CompletionStage;
import java.util.function.Supplier;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import org.opendaylight.yang.gen.v1.http.fd.io.hc2vpp.yang.vpp.vlan.rev190527.interfaces._interface.sub.interfaces.SubInterface;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4AddressNoZone;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6AddressNoZone;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev180220.interfaces.Interface;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;

/**
 * Utility class providing Ipv4/6 CUD support.
 */
public interface IpWriter extends ByteDataTranslator, AddressTranslator, JvppReplyConsumer {

    int DOTTED_QUAD_MASK_LENGTH = 4;
    int IPV4_ADDRESS_PART_BITS_COUNT = 8;
    int NETMASK_PART_LIMIT = 256; // 2 power to 8

    default void addDelAddress(@Nonnull final FutureJVppCore futureJVppCore, final boolean add,
                               final InstanceIdentifier<?> id,
                               @Nonnegative final int ifaceId,
                               @Nonnull final Ipv4AddressNoZone address, @Nonnegative final byte prefixLength)
            throws WriteFailedException {
        checkArgument(prefixLength > 0, "Invalid prefix length");
        checkNotNull(address, "address should not be null");

        final byte[] addressBytes = ipv4AddressNoZoneToArray(address);

        final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
                futureJVppCore.swInterfaceAddDelAddress(
                        getSwInterfaceAddDelAddressRequest(ifaceId, booleanToByte(add) /* isAdd */,
                                (byte) 0 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));

        getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
    }

    default void addDelAddress(@Nonnull final FutureJVppCore futureJVppCore, final boolean add,
                               final InstanceIdentifier<?> id,
                               @Nonnegative final int ifaceId,
                               @Nonnull final Ipv6AddressNoZone address, @Nonnegative final byte prefixLength)
            throws WriteFailedException {
        checkNotNull(address, "address should not be null");

        final byte[] addressBytes = ipv6AddressNoZoneToArray(address);

        final CompletionStage<SwInterfaceAddDelAddressReply> swInterfaceAddDelAddressReplyCompletionStage =
                futureJVppCore.swInterfaceAddDelAddress(
                        getSwInterfaceAddDelAddressRequest(ifaceId, booleanToByte(add) /* isAdd */,
                                (byte) 1 /* isIpv6 */, (byte) 0 /* delAll */, prefixLength, addressBytes));

        getReplyForWrite(swInterfaceAddDelAddressReplyCompletionStage.toCompletableFuture(), id);
    }

    default SwInterfaceAddDelAddress getSwInterfaceAddDelAddressRequest(final int swIfc, final byte isAdd,
                                                                        final byte ipv6, final byte deleteAll,
                                                                        final byte length, final byte[] addr) {
        final SwInterfaceAddDelAddress swInterfaceAddDelAddress = new SwInterfaceAddDelAddress();
        swInterfaceAddDelAddress.swIfIndex = swIfc;
        swInterfaceAddDelAddress.isAdd = isAdd;
        swInterfaceAddDelAddress.isIpv6 = ipv6;
        swInterfaceAddDelAddress.delAll = deleteAll;
        swInterfaceAddDelAddress.address = addr;
        swInterfaceAddDelAddress.addressLength = length;
        return swInterfaceAddDelAddress;
    }

    /**
     * Returns the prefix size in bits of the specified subnet mask. Example: For the subnet mask 255.255.255.128 it
     * returns 25 while for 255.0.0.0 it returns 8. If the passed subnetMask array is not complete or contains not only
     * leading ones, IllegalArgumentExpression is thrown
     *
     * @param mask the subnet mask in dot notation 255.255.255.255
     * @return the prefix length as number of bits
     */
    default byte getSubnetMaskLength(final String mask) {
        String[] maskParts = mask.split("\\.");

        checkArgument(maskParts.length == DOTTED_QUAD_MASK_LENGTH,
                "Network mask %s is not in Quad Dotted Decimal notation!", mask);

        long maskAsNumber = 0;
        for (int i = 0; i < DOTTED_QUAD_MASK_LENGTH; i++) {
            maskAsNumber <<= IPV4_ADDRESS_PART_BITS_COUNT;
            int value = Integer.parseInt(maskParts[i]);
            checkArgument(value < NETMASK_PART_LIMIT, "Network mask %s contains invalid number(s) over 255!", mask);
            checkArgument(value >= 0, "Network mask %s contains invalid negative number(s)!", mask);
            maskAsNumber += value;
        }

        String bits = Long.toBinaryString(maskAsNumber);
        checkArgument(bits.length() == IPV4_ADDRESS_PART_BITS_COUNT * DOTTED_QUAD_MASK_LENGTH,
                "Incorrect network mask %s", mask);
        final int leadingOnes = bits.indexOf('0');
        checkArgument(leadingOnes != -1, "Broadcast address %s is not allowed!", mask);
        checkArgument(bits.substring(leadingOnes).indexOf('1') == -1,
                "Non-contiguous network mask %s is not allowed!", mask);
        return (byte) leadingOnes;
    }

    default int subInterfaceIndex(final InstanceIdentifier<?> id, final NamingContext interfaceContext,
                                  final MappingContext mappingContext) {
        return interfaceContext
                .getIndex(id.firstKeyOf(Interface.class).getName() + "." + id.firstKeyOf(SubInterface.class).getIdentifier(),
                        mappingContext);
    }

    default void addDelNeighbour(@Nonnull final InstanceIdentifier<?> id,
                                 @Nonnull final Supplier<IpNeighborAddDel> requestSupplier,
                                 @Nonnull final FutureJVppCore api) throws WriteFailedException {
        getReplyForWrite(api.ipNeighborAddDel(requestSupplier.get()).toCompletableFuture(), id);
    }

    default IpNeighborAddDel preBindRequest(final boolean add) {
        IpNeighborAddDel request = new IpNeighborAddDel();
        request.neighbor = new IpNeighbor();
        request.isAdd = ByteDataTranslator.INSTANCE.booleanToByte(add);
        request.neighbor.flags = new IpNeighborFlags();
        request.neighbor.flags.add(IpNeighborFlags.IpNeighborFlagsOptions.IP_API_NEIGHBOR_FLAG_STATIC);
        return request;
    }
}