mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 06:50:10 +01:00
clat: support all pref64 lengths
Support all the prefix lengths defined in RFC 6052.
This commit is contained in:
parent
5dba386055
commit
131ef566ef
4 changed files with 179 additions and 16 deletions
|
|
@ -273,6 +273,170 @@ rewrite_icmp(struct __sk_buff *skb, const struct ipv6hdr *ip6h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert an IPv4 address to the corresponding "IPv4-Embedded IPv6 Address"
|
||||
* according to RFC 6052 2.2.
|
||||
*
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |PL| 0-------------32--40--48--56--64--72--80--88--96--104---------|
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |32| prefix |v4(32) | u | suffix |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |40| prefix |v4(24) | u |(8)| suffix |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |48| prefix |v4(16) | u | (16) | suffix |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |56| prefix |(8)| u | v4(24) | suffix |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |64| prefix | u | v4(32) | suffix |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
* |96| prefix | v4(32) |
|
||||
* +--+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|
||||
*
|
||||
*/
|
||||
static __always_inline bool
|
||||
v4addr_to_v6(__be32 addr4, struct in6_addr *addr6, const struct in6_addr *pref64, int pref64_len)
|
||||
{
|
||||
union {
|
||||
__be32 a32;
|
||||
__u8 a8[4];
|
||||
} u;
|
||||
|
||||
u.a32 = addr4;
|
||||
|
||||
addr6->s6_addr32[0] = 0;
|
||||
addr6->s6_addr32[1] = 0;
|
||||
addr6->s6_addr32[2] = 0;
|
||||
addr6->s6_addr32[3] = 0;
|
||||
|
||||
switch (pref64_len) {
|
||||
case 96:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr32[1] = pref64->s6_addr32[1];
|
||||
addr6->s6_addr32[2] = pref64->s6_addr32[2];
|
||||
addr6->s6_addr32[3] = addr4;
|
||||
break;
|
||||
case 64:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr32[1] = pref64->s6_addr32[1];
|
||||
addr6->s6_addr[9] = u.a8[0];
|
||||
addr6->s6_addr[10] = u.a8[1];
|
||||
addr6->s6_addr[11] = u.a8[2];
|
||||
addr6->s6_addr[12] = u.a8[3];
|
||||
break;
|
||||
case 56:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr32[1] = pref64->s6_addr32[1];
|
||||
addr6->s6_addr[7] = u.a8[0];
|
||||
addr6->s6_addr[9] = u.a8[1];
|
||||
addr6->s6_addr[10] = u.a8[2];
|
||||
addr6->s6_addr[11] = u.a8[3];
|
||||
break;
|
||||
case 48:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr16[2] = pref64->s6_addr16[2];
|
||||
addr6->s6_addr[6] = u.a8[0];
|
||||
addr6->s6_addr[7] = u.a8[1];
|
||||
addr6->s6_addr[9] = u.a8[2];
|
||||
addr6->s6_addr[10] = u.a8[3];
|
||||
break;
|
||||
case 40:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr[4] = pref64->s6_addr[4];
|
||||
addr6->s6_addr[5] = u.a8[0];
|
||||
addr6->s6_addr[6] = u.a8[1];
|
||||
addr6->s6_addr[7] = u.a8[2];
|
||||
addr6->s6_addr[9] = u.a8[3];
|
||||
break;
|
||||
case 32:
|
||||
addr6->s6_addr32[0] = pref64->s6_addr32[0];
|
||||
addr6->s6_addr32[1] = addr4;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the IPv4 address @addr4 and the NAT64 prefix @pref64 from an IPv6 address,
|
||||
* given the known prefix length @pref64_len. See the table above.
|
||||
*/
|
||||
static __always_inline bool
|
||||
v6addr_to_v4(const struct in6_addr *addr6, int pref64_len, __be32 *addr4, struct in6_addr *pref64)
|
||||
{
|
||||
union {
|
||||
__be32 a32;
|
||||
__u8 a8[4];
|
||||
} u;
|
||||
|
||||
pref64->s6_addr32[0] = 0;
|
||||
pref64->s6_addr32[1] = 0;
|
||||
pref64->s6_addr32[2] = 0;
|
||||
pref64->s6_addr32[3] = 0;
|
||||
|
||||
switch (pref64_len) {
|
||||
case 96:
|
||||
u.a32 = addr6->s6_addr32[3];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
pref64->s6_addr32[1] = addr6->s6_addr32[1];
|
||||
pref64->s6_addr32[2] = addr6->s6_addr32[2];
|
||||
break;
|
||||
case 64:
|
||||
u.a8[0] = addr6->s6_addr[9];
|
||||
u.a8[1] = addr6->s6_addr[10];
|
||||
u.a8[2] = addr6->s6_addr[11];
|
||||
u.a8[3] = addr6->s6_addr[12];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
pref64->s6_addr32[1] = addr6->s6_addr32[1];
|
||||
break;
|
||||
case 56:
|
||||
u.a8[0] = addr6->s6_addr[7];
|
||||
u.a8[1] = addr6->s6_addr[9];
|
||||
u.a8[2] = addr6->s6_addr[10];
|
||||
u.a8[3] = addr6->s6_addr[11];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
pref64->s6_addr32[1] = addr6->s6_addr32[1];
|
||||
pref64->s6_addr[7] = 0;
|
||||
break;
|
||||
case 48:
|
||||
u.a8[0] = addr6->s6_addr[6];
|
||||
u.a8[1] = addr6->s6_addr[7];
|
||||
u.a8[2] = addr6->s6_addr[9];
|
||||
u.a8[3] = addr6->s6_addr[10];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
pref64->s6_addr32[1] = addr6->s6_addr32[1];
|
||||
pref64->s6_addr16[3] = 0;
|
||||
break;
|
||||
case 40:
|
||||
u.a8[0] = addr6->s6_addr[5];
|
||||
u.a8[1] = addr6->s6_addr[6];
|
||||
u.a8[2] = addr6->s6_addr[7];
|
||||
u.a8[3] = addr6->s6_addr[9];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
pref64->s6_addr32[1] = addr6->s6_addr32[1];
|
||||
pref64->s6_addr16[3] = 0;
|
||||
pref64->s6_addr[5] = 0;
|
||||
|
||||
break;
|
||||
case 32:
|
||||
u.a32 = addr6->s6_addr32[1];
|
||||
|
||||
pref64->s6_addr32[0] = addr6->s6_addr32[0];
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
*addr4 = u.a32;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ipv4 traffic in from application on this device, needs to be translated to v6 and sent to PLAT */
|
||||
static int
|
||||
clat_handle_v4(struct __sk_buff *skb)
|
||||
|
|
@ -314,12 +478,12 @@ clat_handle_v4(struct __sk_buff *skb)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/* src v4 as last octet of clat address */
|
||||
dst_hdr.saddr = config.local_v6;
|
||||
dst_hdr.daddr = config.pref64;
|
||||
dst_hdr.daddr.s6_addr32[3] = iph->daddr;
|
||||
dst_hdr.nexthdr = iph->protocol;
|
||||
dst_hdr.hop_limit = iph->ttl;
|
||||
if (!v4addr_to_v6(iph->daddr, &dst_hdr.daddr, &config.pref64, config.pref64_len))
|
||||
goto out;
|
||||
|
||||
dst_hdr.saddr = config.local_v6;
|
||||
dst_hdr.nexthdr = iph->protocol;
|
||||
dst_hdr.hop_limit = iph->ttl;
|
||||
/* weird definition in ipv6hdr */
|
||||
dst_hdr.priority = (iph->tos & 0x70) >> 4;
|
||||
dst_hdr.flow_lbl[0] = iph->tos << 4;
|
||||
|
|
@ -495,6 +659,7 @@ clat_handle_v6(struct __sk_buff *skb)
|
|||
int ret = TC_ACT_OK;
|
||||
void *data_end = SKB_DATA_END(skb);
|
||||
void *data = SKB_DATA(skb);
|
||||
__be32 saddr4;
|
||||
struct in6_addr subnet_v6;
|
||||
struct ethhdr *eth;
|
||||
struct iphdr *iph;
|
||||
|
|
@ -512,8 +677,8 @@ clat_handle_v6(struct __sk_buff *skb)
|
|||
if (!v6addr_equal(&ip6h->daddr, &config.local_v6))
|
||||
goto out;
|
||||
|
||||
subnet_v6 = ip6h->saddr;
|
||||
subnet_v6.s6_addr32[3] = 0; /* prefix len is always 96 for now */
|
||||
if (!v6addr_to_v4(&ip6h->saddr, config.pref64_len, &saddr4, &subnet_v6))
|
||||
goto out;
|
||||
|
||||
if (!v6addr_equal(&subnet_v6, &config.pref64))
|
||||
goto out;
|
||||
|
|
@ -529,7 +694,7 @@ clat_handle_v6(struct __sk_buff *skb)
|
|||
goto out;
|
||||
|
||||
dst_hdr.daddr = config.local_v4.s_addr;
|
||||
dst_hdr.saddr = ip6h->saddr.s6_addr32[3];
|
||||
dst_hdr.saddr = saddr4;
|
||||
dst_hdr.protocol = ip6h->nexthdr;
|
||||
dst_hdr.ttl = ip6h->hop_limit;
|
||||
dst_hdr.tos = ip6h->priority << 4 | (ip6h->flow_lbl[0] >> 4);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
struct clat_config {
|
||||
struct in6_addr local_v6;
|
||||
struct in6_addr pref64;
|
||||
struct in_addr local_v4;
|
||||
struct in_addr local_v4;
|
||||
unsigned pref64_len;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -409,12 +409,8 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
gint64 expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_pref64_lifetime(msg, offset));
|
||||
|
||||
/* Currently, only /96 is supported */
|
||||
if (pref64_length != 96) {
|
||||
_LOGW("Ignored PREF64 for unsupported prefix length: %d (only /96 is supported)",
|
||||
pref64_length);
|
||||
continue;
|
||||
}
|
||||
/* libndp should only return lengths defined in RFC 8781 */
|
||||
nm_assert(NM_IN_SET(pref64_length, 96, 64, 56, 48, 40, 32));
|
||||
|
||||
/* Newer RA has more up to date information, prefer it: */
|
||||
if (!pref64_found) {
|
||||
|
|
|
|||
|
|
@ -5689,6 +5689,7 @@ _l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
|
|||
clat_config.local_v4.s_addr = self->priv.p->clat_address_4->addr;
|
||||
clat_config.local_v6 = self->priv.p->clat_address_6.address;
|
||||
clat_config.pref64 = *l3cd_pref64;
|
||||
clat_config.pref64_len = l3cd_pref64_plen;
|
||||
self->priv.p->clat_bpf->bss->config = clat_config;
|
||||
|
||||
if (self->priv.p->clat_socket < 0) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue