1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2022 Felix Fietkau <nbd@nbd.name>
7 #include <sys/socket.h>
8 #include <netlink/msg.h>
9 #include <netlink/attr.h>
10 #include <netlink/socket.h>
11 #include <netinet/if_ether.h>
13 #include <linux/rtnetlink.h>
14 #include <linux/ipv6.h>
15 #include <linux/udp.h>
20 struct network_service
*s
;
21 char ifname
[IFNAMSIZ
+ 1];
26 uint32_t *forward_ports
;
27 uint32_t *cur_forward_ports
;
32 vxlan_tunnel_id(struct vxlan_tunnel
*vt
)
34 siphash_key_t key
= {};
35 const char *name
= network_service_name(vt
->s
);
41 siphash_to_le64(&val
, name
, strlen(name
), &key
);
43 return val
& 0x00ffffff;
46 static struct nl_msg
*vxlan_rtnl_msg(const char *ifname
, int type
, int flags
)
48 struct ifinfomsg iim
= {
49 .ifi_family
= AF_UNSPEC
,
53 msg
= nlmsg_alloc_simple(type
, flags
| NLM_F_REQUEST
);
57 nlmsg_append(msg
, &iim
, sizeof(iim
), 0);
58 nla_put_string(msg
, IFLA_IFNAME
, ifname
);
64 vxlan_update_host_fdb_entry(struct vxlan_tunnel
*vt
, struct network_host
*host
, bool add
)
66 struct ndmsg ndmsg
= {
67 .ndm_family
= PF_BRIDGE
,
68 .ndm_state
= NUD_NOARP
| NUD_PERMANENT
,
69 .ndm_flags
= NTF_SELF
,
70 .ndm_ifindex
= vt
->ifindex
,
72 unsigned int flags
= NLM_F_REQUEST
;
73 uint8_t lladdr
[ETH_ALEN
] = {};
77 flags
|= NLM_F_CREATE
| NLM_F_APPEND
;
79 msg
= nlmsg_alloc_simple(add
? RTM_NEWNEIGH
: RTM_DELNEIGH
, flags
);
80 nlmsg_append(msg
, &ndmsg
, sizeof(ndmsg
), 0);
81 nla_put(msg
, NDA_LLADDR
, ETH_ALEN
, lladdr
);
82 nla_put(msg
, NDA_DST
, sizeof(struct in6_addr
), &host
->peer
.local_addr
);
83 nla_put_u32(msg
, NDA_IFINDEX
, vt
->net
->ifindex
);
85 return rtnl_call(msg
);
89 vxlan_update_fdb_hosts(struct vxlan_tunnel
*vt
)
91 struct network_service
*s
= vt
->s
;
98 for (i
= 0; i
< s
->n_members
; i
++) {
99 if (s
->members
[i
] == vt
->net
->net_config
.local_host
)
102 if (vt
->forward_ports
&& !bitmask_test(vt
->forward_ports
, i
))
105 active
= s
->members
[i
]->peer
.state
.connected
;
106 if (active
== bitmask_test(vt
->cur_forward_ports
, i
))
109 if (!vxlan_update_host_fdb_entry(vt
, s
->members
[i
], active
))
110 bitmask_set_val(vt
->cur_forward_ports
, i
, active
);
115 vxlan_peer_update(struct network
*net
, struct network_service
*s
, struct network_peer
*peer
)
120 vxlan_update_fdb_hosts(s
->vxlan
);
124 vxlan_tunnel_init(struct vxlan_tunnel
*vt
)
126 struct network_peer
*local
= &vt
->net
->net_config
.local_host
->peer
;
127 struct nlattr
*linkinfo
, *data
;
129 struct in6_addr group_addr
;
135 memset(&group_addr
, 0xff, sizeof(group_addr
));
136 msg
= vxlan_rtnl_msg(vt
->ifname
, RTM_NEWLINK
, NLM_F_CREATE
| NLM_F_EXCL
);
138 linkinfo
= nla_nest_start(msg
, IFLA_LINKINFO
);
139 nla_put_string(msg
, IFLA_INFO_KIND
, "vxlan");
140 nla_put_u32(msg
, IFLA_MTU
, vt
->mtu
);
142 data
= nla_nest_start(msg
, IFLA_INFO_DATA
);
143 nla_put_u32(msg
, IFLA_VXLAN_ID
, vxlan_tunnel_id(vt
));
144 nla_put(msg
, IFLA_VXLAN_LOCAL6
, sizeof(struct in6_addr
), &local
->local_addr
);
145 nla_put(msg
, IFLA_VXLAN_GROUP6
, sizeof(struct in6_addr
), &group_addr
);
146 nla_put_u16(msg
, IFLA_VXLAN_PORT
, htons(vt
->port
));
147 nla_put_u8(msg
, IFLA_VXLAN_LEARNING
, 1);
148 nla_put_u32(msg
, IFLA_VXLAN_LINK
, vt
->net
->ifindex
);
149 nla_nest_end(msg
, data
);
151 nla_nest_end(msg
, linkinfo
);
153 if (rtnl_call(msg
) < 0)
156 vt
->ifindex
= if_nametoindex(vt
->ifname
);
158 D_SERVICE(vt
->net
, vt
->s
, "failed to get ifindex for device %s", vt
->ifname
);
163 vxlan_update_fdb_hosts(vt
);
165 mtu
= 1420 - sizeof(struct ipv6hdr
) - sizeof(struct udphdr
) - 8;
166 unetd_attach_mssfix(vt
->ifindex
, mtu
);
170 vxlan_tunnel_teardown(struct vxlan_tunnel
*vt
)
175 msg
= vxlan_rtnl_msg(vt
->ifname
, RTM_DELLINK
, 0);
180 vxlan_find_ifname(struct network
*net
, const char *service
)
182 struct blob_attr
*cur
;
185 if (!net
->config
.tunnels
)
188 blobmsg_for_each_attr(cur
, net
->config
.tunnels
, rem
) {
191 if (!blobmsg_check_attr(cur
, true) ||
192 blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
195 if (strcmp(blobmsg_get_string(cur
), service
) != 0)
198 name
= blobmsg_name(cur
);
199 if (strlen(name
) > IFNAMSIZ
)
209 __vxlan_mark_forward_host(struct vxlan_tunnel
*vt
, struct network_host
*host
)
211 struct network_service
*s
= vt
->s
;
214 for (i
= 0; i
< s
->n_members
; i
++) {
215 if (s
->members
[i
] != host
)
218 bitmask_set(vt
->forward_ports
, i
);
224 vxlan_mark_forward_host(struct vxlan_tunnel
*vt
, const char *name
)
226 struct network
*net
= vt
->net
;
227 struct network_host
*host
;
229 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
233 __vxlan_mark_forward_host(vt
, host
);
237 vxlan_mark_forward_group(struct vxlan_tunnel
*vt
, const char *name
)
239 struct network
*net
= vt
->net
;
240 struct network_group
*group
;
243 group
= avl_find_element(&net
->groups
, name
, group
, node
);
247 for (i
= 0; i
< group
->n_members
; i
++)
248 __vxlan_mark_forward_host(vt
, group
->members
[i
]);
252 vxlan_init_forward_ports(struct vxlan_tunnel
*vt
, struct blob_attr
*data
)
254 unsigned int len
= bitmask_size(vt
->s
->n_members
);
255 struct blob_attr
*cur
;
258 vt
->cur_forward_ports
= realloc(vt
->cur_forward_ports
, len
);
259 memset(vt
->cur_forward_ports
, 0, len
);
261 if (!data
|| blobmsg_check_array(data
, BLOBMSG_TYPE_STRING
) <= 0) {
262 free(vt
->forward_ports
);
263 vt
->forward_ports
= NULL
;
267 vt
->forward_ports
= realloc(vt
->forward_ports
, len
);
268 memset(vt
->forward_ports
, 0, len
);
269 blobmsg_for_each_attr(cur
, data
, rem
) {
270 const char *name
= blobmsg_get_string(cur
);
273 vxlan_mark_forward_group(vt
, name
+ 1);
275 vxlan_mark_forward_host(vt
, name
);
280 vxlan_config_equal(struct network_service
*s1
, struct network_service
*s2
)
284 if (!blob_attr_equal(s1
->config
, s2
->config
))
287 if (s1
->n_members
!= s2
->n_members
)
290 for (i
= 0; i
< s1
->n_members
; i
++)
291 if (memcmp(s1
->members
[i
]->peer
.key
, s2
->members
[i
]->peer
.key
,
292 CURVE25519_KEY_SIZE
) != 0)
299 vxlan_init(struct network
*net
, struct network_service
*s
,
300 struct network_service
*s_old
)
303 VXCFG_ATTR_FWD_PORTS
,
309 static const struct blobmsg_policy policy
[__VXCFG_ATTR_MAX
] = {
310 [VXCFG_ATTR_FWD_PORTS
] = { "forward_ports", BLOBMSG_TYPE_ARRAY
},
311 [VXCFG_ATTR_ID
] = { "id", BLOBMSG_TYPE_INT32
},
312 [VXCFG_ATTR_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
313 [VXCFG_ATTR_MTU
] = { "mtu", BLOBMSG_TYPE_INT32
},
315 struct blob_attr
*tb
[__VXCFG_ATTR_MAX
] = {};
316 struct blob_attr
*cur
;
317 struct vxlan_tunnel
*vt
= s
->vxlan
;
326 if (vxlan_config_equal(s
, s_old
)) {
332 vxlan_tunnel_teardown(vt
);
336 name
= vxlan_find_ifname(net
, network_service_name(s
));
338 D_SERVICE(net
, s
, "no configured tunnel ifname");
342 vt
= calloc(1, sizeof(*s
->vxlan
));
343 snprintf(vt
->ifname
, sizeof(vt
->ifname
), "%s", name
);
350 blobmsg_parse(policy
, __VXCFG_ATTR_MAX
, tb
, blobmsg_data(s
->config
),
351 blobmsg_len(s
->config
));
353 vxlan_init_forward_ports(vt
, tb
[VXCFG_ATTR_FWD_PORTS
]);
354 if ((cur
= tb
[VXCFG_ATTR_ID
]) != NULL
)
355 vt
->vni
= blobmsg_get_u32(cur
) & 0x00ffffff;
359 if ((cur
= tb
[VXCFG_ATTR_PORT
]) != NULL
)
360 vt
->port
= blobmsg_get_u32(cur
);
364 if ((cur
= tb
[VXCFG_ATTR_MTU
]) != NULL
)
365 vt
->mtu
= blobmsg_get_u32(cur
);
369 vxlan_tunnel_init(vt
);
373 vxlan_free(struct network
*net
, struct network_service
*s
)
375 struct vxlan_tunnel
*vt
= s
->vxlan
;
380 vxlan_tunnel_teardown(vt
);
382 free(vt
->forward_ports
);
386 const struct service_ops vxlan_ops
= {
389 .peer_update
= vxlan_peer_update
,