1 // SPDX-License-Identifier: GPL-2.0+
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>
18 struct network_service
*s
;
19 char ifname
[IFNAMSIZ
+ 1];
24 uint32_t *forward_ports
;
25 uint32_t *cur_forward_ports
;
29 static struct nl_sock
*rtnl
;
30 static bool ignore_errors
;
33 unetd_nl_error_cb(struct sockaddr_nl
*nla
, struct nlmsgerr
*err
,
36 struct nlmsghdr
*nlh
= (struct nlmsghdr
*) err
- 1;
37 struct nlattr
*tb
[NLMSGERR_ATTR_MAX
+ 1];
39 int ack_len
= sizeof(*nlh
) + sizeof(int) + sizeof(*nlh
);
40 int len
= nlh
->nlmsg_len
;
41 const char *errstr
= "(unknown)";
46 if (!(nlh
->nlmsg_flags
& NLM_F_ACK_TLVS
))
49 if (!(nlh
->nlmsg_flags
& NLM_F_CAPPED
))
50 ack_len
+= err
->msg
.nlmsg_len
- sizeof(*nlh
);
52 attrs
= (void *) ((unsigned char *) nlh
+ ack_len
);
55 nla_parse(tb
, NLMSGERR_ATTR_MAX
, attrs
, len
, NULL
);
56 if (tb
[NLMSGERR_ATTR_MSG
])
57 errstr
= nla_data(tb
[NLMSGERR_ATTR_MSG
]);
59 D("Netlink error(%d): %s\n", err
->error
, errstr
);
64 static struct nl_msg
*vxlan_rtnl_msg(const char *ifname
, int type
, int flags
)
66 struct ifinfomsg iim
= {
67 .ifi_family
= AF_UNSPEC
,
71 msg
= nlmsg_alloc_simple(type
, flags
| NLM_F_REQUEST
);
75 nlmsg_append(msg
, &iim
, sizeof(iim
), 0);
76 nla_put_string(msg
, IFLA_IFNAME
, ifname
);
81 static int vxlan_rtnl_call(struct nl_msg
*msg
)
85 ret
= nl_send_auto_complete(rtnl
, msg
);
91 return nl_wait_for_ack(rtnl
);
102 rtnl
= nl_socket_alloc();
106 if (nl_connect(rtnl
, NETLINK_ROUTE
))
109 nl_socket_disable_seq_check(rtnl
);
110 nl_socket_set_buffer_size(rtnl
, 65536, 0);
111 nl_cb_err(nl_socket_get_cb(rtnl
), NL_CB_CUSTOM
, unetd_nl_error_cb
, NULL
);
113 fd
= nl_socket_get_fd(rtnl
);
116 setsockopt(fd
, SOL_NETLINK
, NETLINK_EXT_ACK
, &opt
, sizeof(opt
));
119 setsockopt(fd
, SOL_NETLINK
, NETLINK_CAP_ACK
, &opt
, sizeof(opt
));
124 nl_socket_free(rtnl
);
130 vxlan_tunnel_id(struct vxlan_tunnel
*vt
)
132 siphash_key_t key
= {};
133 const char *name
= network_service_name(vt
->s
);
139 siphash_to_le64(&val
, name
, strlen(name
), &key
);
141 return val
& 0x00ffffff;
145 vxlan_update_host_fdb_entry(struct vxlan_tunnel
*vt
, struct network_host
*host
, bool add
)
147 struct ndmsg ndmsg
= {
148 .ndm_family
= PF_BRIDGE
,
149 .ndm_state
= NUD_NOARP
| NUD_PERMANENT
,
150 .ndm_flags
= NTF_SELF
,
151 .ndm_ifindex
= vt
->ifindex
,
153 unsigned int flags
= NLM_F_REQUEST
;
154 uint8_t lladdr
[ETH_ALEN
] = {};
158 flags
|= NLM_F_CREATE
| NLM_F_APPEND
;
160 msg
= nlmsg_alloc_simple(add
? RTM_NEWNEIGH
: RTM_DELNEIGH
, flags
);
161 nlmsg_append(msg
, &ndmsg
, sizeof(ndmsg
), 0);
162 nla_put(msg
, NDA_LLADDR
, ETH_ALEN
, lladdr
);
163 nla_put(msg
, NDA_DST
, sizeof(struct in6_addr
), &host
->peer
.local_addr
);
164 nla_put_u32(msg
, NDA_IFINDEX
, vt
->net
->ifindex
);
166 return vxlan_rtnl_call(msg
);
170 vxlan_update_fdb_hosts(struct vxlan_tunnel
*vt
)
172 struct network_service
*s
= vt
->s
;
179 for (i
= 0; i
< s
->n_members
; i
++) {
180 if (s
->members
[i
] == vt
->net
->net_config
.local_host
)
183 if (vt
->forward_ports
&& !bitmask_test(vt
->forward_ports
, i
))
186 active
= s
->members
[i
]->peer
.state
.connected
;
187 if (active
== bitmask_test(vt
->cur_forward_ports
, i
))
190 if (!vxlan_update_host_fdb_entry(vt
, s
->members
[i
], active
))
191 bitmask_set_val(vt
->cur_forward_ports
, i
, active
);
196 vxlan_peer_update(struct network
*net
, struct network_service
*s
, struct network_peer
*peer
)
201 vxlan_update_fdb_hosts(s
->vxlan
);
205 vxlan_tunnel_init(struct vxlan_tunnel
*vt
)
207 struct network_peer
*local
= &vt
->net
->net_config
.local_host
->peer
;
208 struct nlattr
*linkinfo
, *data
;
211 if (vxlan_rtnl_init())
214 msg
= vxlan_rtnl_msg(vt
->ifname
, RTM_NEWLINK
, NLM_F_CREATE
| NLM_F_EXCL
);
216 linkinfo
= nla_nest_start(msg
, IFLA_LINKINFO
);
217 nla_put_string(msg
, IFLA_INFO_KIND
, "vxlan");
218 nla_put_u32(msg
, IFLA_MTU
, vt
->mtu
);
220 data
= nla_nest_start(msg
, IFLA_INFO_DATA
);
221 nla_put_u32(msg
, IFLA_VXLAN_ID
, vxlan_tunnel_id(vt
));
222 nla_put(msg
, IFLA_VXLAN_LOCAL6
, sizeof(struct in6_addr
), &local
->local_addr
);
223 nla_put_u16(msg
, IFLA_VXLAN_PORT
, vt
->port
);
224 nla_put_u8(msg
, IFLA_VXLAN_LEARNING
, 1);
225 nla_nest_end(msg
, data
);
227 nla_nest_end(msg
, linkinfo
);
229 if (vxlan_rtnl_call(msg
) < 0)
232 vt
->ifindex
= if_nametoindex(vt
->ifname
);
234 D_SERVICE(vt
->net
, vt
->s
, "failed to get ifindex for device %s", vt
->ifname
);
239 vxlan_update_fdb_hosts(vt
);
243 vxlan_tunnel_teardown(struct vxlan_tunnel
*vt
)
251 msg
= vxlan_rtnl_msg(vt
->ifname
, RTM_DELLINK
, 0);
252 vxlan_rtnl_call(msg
);
256 vxlan_find_ifname(struct network
*net
, const char *service
)
258 struct blob_attr
*cur
;
261 if (!net
->config
.tunnels
)
264 blobmsg_for_each_attr(cur
, net
->config
.tunnels
, rem
) {
267 if (!blobmsg_check_attr(cur
, true) ||
268 blobmsg_type(cur
) != BLOBMSG_TYPE_STRING
)
271 if (strcmp(blobmsg_get_string(cur
), service
) != 0)
274 name
= blobmsg_name(cur
);
275 if (strlen(name
) > IFNAMSIZ
)
285 __vxlan_mark_forward_host(struct vxlan_tunnel
*vt
, struct network_host
*host
)
287 struct network_service
*s
= vt
->s
;
290 for (i
= 0; i
< s
->n_members
; i
++) {
291 if (s
->members
[i
] != host
)
294 bitmask_set(vt
->forward_ports
, i
);
300 vxlan_mark_forward_host(struct vxlan_tunnel
*vt
, const char *name
)
302 struct network
*net
= vt
->net
;
303 struct network_host
*host
;
305 host
= avl_find_element(&net
->hosts
, name
, host
, node
);
309 __vxlan_mark_forward_host(vt
, host
);
313 vxlan_mark_forward_group(struct vxlan_tunnel
*vt
, const char *name
)
315 struct network
*net
= vt
->net
;
316 struct network_group
*group
;
319 group
= avl_find_element(&net
->groups
, name
, group
, node
);
323 for (i
= 0; i
< group
->n_members
; i
++)
324 __vxlan_mark_forward_host(vt
, group
->members
[i
]);
328 vxlan_init_forward_ports(struct vxlan_tunnel
*vt
, struct blob_attr
*data
)
330 unsigned int len
= bitmask_size(vt
->s
->n_members
);
331 struct blob_attr
*cur
;
334 vt
->cur_forward_ports
= realloc(vt
->cur_forward_ports
, len
);
335 memset(vt
->cur_forward_ports
, 0, len
);
337 if (!data
|| blobmsg_check_array(data
, BLOBMSG_TYPE_STRING
) <= 0) {
338 free(vt
->forward_ports
);
339 vt
->forward_ports
= NULL
;
343 vt
->forward_ports
= realloc(vt
->forward_ports
, len
);
344 memset(vt
->forward_ports
, 0, len
);
345 blobmsg_for_each_attr(cur
, data
, rem
) {
346 const char *name
= blobmsg_get_string(cur
);
349 vxlan_mark_forward_group(vt
, name
+ 1);
351 vxlan_mark_forward_host(vt
, name
);
356 vxlan_config_equal(struct network_service
*s1
, struct network_service
*s2
)
360 if (!blob_attr_equal(s1
->config
, s2
->config
))
363 if (s1
->n_members
!= s2
->n_members
)
366 for (i
= 0; i
< s1
->n_members
; i
++)
367 if (memcmp(s1
->members
[i
]->peer
.key
, s2
->members
[i
]->peer
.key
,
368 CURVE25519_KEY_SIZE
) != 0)
375 vxlan_init(struct network
*net
, struct network_service
*s
,
376 struct network_service
*s_old
)
379 VXCFG_ATTR_FWD_PORTS
,
385 static const struct blobmsg_policy policy
[__VXCFG_ATTR_MAX
] = {
386 [VXCFG_ATTR_FWD_PORTS
] = { "forward_ports", BLOBMSG_TYPE_ARRAY
},
387 [VXCFG_ATTR_ID
] = { "id", BLOBMSG_TYPE_INT32
},
388 [VXCFG_ATTR_PORT
] = { "port", BLOBMSG_TYPE_INT32
},
389 [VXCFG_ATTR_MTU
] = { "mtu", BLOBMSG_TYPE_INT32
},
391 struct blob_attr
*tb
[__VXCFG_ATTR_MAX
] = {};
392 struct blob_attr
*cur
;
393 struct vxlan_tunnel
*vt
= s
->vxlan
;
402 if (vxlan_config_equal(s
, s_old
)) {
408 vxlan_tunnel_teardown(vt
);
412 name
= vxlan_find_ifname(net
, network_service_name(s
));
414 D_SERVICE(net
, s
, "no configured tunnel ifname");
418 vt
= calloc(1, sizeof(*s
->vxlan
));
419 snprintf(vt
->ifname
, sizeof(vt
->ifname
), "%s", name
);
426 blobmsg_parse(policy
, __VXCFG_ATTR_MAX
, tb
, blobmsg_data(s
->config
),
427 blobmsg_len(s
->config
));
429 vxlan_init_forward_ports(vt
, tb
[VXCFG_ATTR_FWD_PORTS
]);
430 if ((cur
= tb
[VXCFG_ATTR_ID
]) != NULL
)
431 vt
->vni
= blobmsg_get_u32(cur
) & 0x00ffffff;
435 if ((cur
= tb
[VXCFG_ATTR_PORT
]) != NULL
)
436 vt
->port
= blobmsg_get_u32(cur
);
440 if ((cur
= tb
[VXCFG_ATTR_MTU
]) != NULL
)
441 vt
->mtu
= blobmsg_get_u32(cur
);
445 vxlan_tunnel_init(vt
);
449 vxlan_free(struct network
*net
, struct network_service
*s
)
451 struct vxlan_tunnel
*vt
= s
->vxlan
;
456 vxlan_tunnel_teardown(vt
);
458 free(vt
->forward_ports
);
462 const struct service_ops vxlan_ops
= {
465 .peer_update
= vxlan_peer_update
,