1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright(c) 2023 Cisco Systems, Inc.
5 * npt66.c: NPT66 plugin
6 * An implementation of Network Prefix Translation for IPv6-to-IPv6 (NPTv6) as
7 * specified in RFC6296.
13 #include <vlib/vlib.h>
14 #include <vnet/feature/feature.h>
15 #include <vppinfra/pool.h>
19 npt66_feature_enable_disable (u32 sw_if_index, bool is_add)
21 if (vnet_feature_enable_disable ("ip6-unicast", "npt66-input", sw_if_index,
24 if (vnet_feature_enable_disable ("ip6-output", "npt66-output", sw_if_index,
31 ipv6_prefix_zero (ip6_address_t *address, int prefix_len)
33 int byte_index = prefix_len / 8;
34 int bit_offset = prefix_len % 8;
35 uint8_t mask = (1 << (8 - bit_offset)) - 1;
38 address->as_u8[byte_index] &= mask;
39 for (int i = byte_index + 1; i < 16; i++)
41 address->as_u8[i] = 0;
47 npt66_binding_add_del (u32 sw_if_index, ip6_address_t *internal,
48 int internal_plen, ip6_address_t *external,
49 int external_plen, bool is_add)
51 npt66_main_t *nm = &npt66_main;
54 /* Currently limited to a single binding per interface */
55 npt66_binding_t *b = npt66_interface_by_sw_if_index (sw_if_index);
59 bool configure_feature = false;
60 /* Ensure prefix lengths are less than or equal to a /64 */
61 if (internal_plen > 64 || external_plen > 64)
62 return VNET_API_ERROR_INVALID_VALUE;
64 /* Create a binding entry (or update existing) */
67 pool_get_zero (nm->bindings, b);
68 configure_feature = true;
70 b->internal = *internal;
71 b->internal_plen = internal_plen;
72 b->external = *external;
73 b->external_plen = external_plen;
74 b->sw_if_index = sw_if_index;
76 ipv6_prefix_zero (&b->internal, internal_plen);
77 ipv6_prefix_zero (&b->external, external_plen);
78 vec_validate_init_empty (nm->interface_by_sw_if_index, sw_if_index, ~0);
79 nm->interface_by_sw_if_index[sw_if_index] = b - nm->bindings;
82 delta = ip_csum_add_even (delta, b->external.as_u64[0]);
83 delta = ip_csum_add_even (delta, b->external.as_u64[1]);
84 delta = ip_csum_sub_even (delta, b->internal.as_u64[0]);
85 delta = ip_csum_sub_even (delta, b->internal.as_u64[1]);
86 delta = ip_csum_fold (delta);
89 if (configure_feature)
90 rv = npt66_feature_enable_disable (sw_if_index, is_add);
94 /* Delete a binding entry */
95 npt66_binding_t *b = npt66_interface_by_sw_if_index (sw_if_index);
97 return VNET_API_ERROR_NO_SUCH_ENTRY;
98 nm->interface_by_sw_if_index[sw_if_index] = ~0;
99 pool_put (nm->bindings, b);
100 rv = npt66_feature_enable_disable (sw_if_index, is_add);
107 * Do a lookup in the interface vector (interface_by_sw_if_index)
108 * and return pool entry.
111 npt66_interface_by_sw_if_index (u32 sw_if_index)
113 npt66_main_t *nm = &npt66_main;
115 if (!nm->interface_by_sw_if_index ||
116 sw_if_index > (vec_len (nm->interface_by_sw_if_index) - 1))
118 u32 index = nm->interface_by_sw_if_index[sw_if_index];
121 if (pool_is_free_index (nm->bindings, index))
123 return pool_elt_at_index (nm->bindings, index);