/* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once #include "sd-netlink.h" #include "alloc-util.h" #include "hash-funcs.h" typedef struct Link Link; typedef struct NetDev NetDev; typedef struct Manager Manager; typedef struct Request Request; typedef int (*request_process_func_t)(Request *req, Link *link, void *userdata); typedef int (*request_netlink_handler_t)(sd_netlink *nl, sd_netlink_message *m, Request *req, Link *link, void *userdata); typedef enum RequestType { REQUEST_TYPE_ACTIVATE_LINK, REQUEST_TYPE_ADDRESS, REQUEST_TYPE_ADDRESS_LABEL, REQUEST_TYPE_BRIDGE_FDB, REQUEST_TYPE_BRIDGE_MDB, REQUEST_TYPE_DHCP_SERVER, REQUEST_TYPE_DHCP4_CLIENT, REQUEST_TYPE_DHCP6_CLIENT, REQUEST_TYPE_IPV6_PROXY_NDP, REQUEST_TYPE_NDISC, REQUEST_TYPE_NEIGHBOR, REQUEST_TYPE_NETDEV_INDEPENDENT, REQUEST_TYPE_NETDEV_STACKED, REQUEST_TYPE_NEXTHOP, REQUEST_TYPE_RADV, REQUEST_TYPE_ROUTE, REQUEST_TYPE_ROUTING_POLICY_RULE, REQUEST_TYPE_SET_LINK_ADDRESS_GENERATION_MODE, /* Setting IPv6LL address generation mode. */ REQUEST_TYPE_SET_LINK_BOND, /* Setting bond configs. */ REQUEST_TYPE_SET_LINK_BRIDGE, /* Setting bridge configs. */ REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, /* Setting bridge VLAN configs. */ REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN, /* Removing bridge VLAN configs. */ REQUEST_TYPE_SET_LINK_CAN, /* Setting CAN interface configs. */ REQUEST_TYPE_SET_LINK_FLAGS, /* Setting IFF_NOARP or friends. */ REQUEST_TYPE_SET_LINK_GROUP, /* Setting interface group. */ REQUEST_TYPE_SET_LINK_IPOIB, /* Setting IPoIB configs. */ REQUEST_TYPE_SET_LINK_MAC, /* Setting MAC address. */ REQUEST_TYPE_SET_LINK_MASTER, /* Setting IFLA_MASTER. */ REQUEST_TYPE_SET_LINK_MTU, /* Setting MTU. */ REQUEST_TYPE_SRIOV, REQUEST_TYPE_TC_CLASS, REQUEST_TYPE_TC_QDISC, REQUEST_TYPE_UP_DOWN, _REQUEST_TYPE_MAX, _REQUEST_TYPE_INVALID = -EINVAL, } RequestType; struct Request { unsigned n_ref; Manager *manager; /* must be non-NULL */ Link *link; /* can be NULL */ RequestType type; /* Target object, e.g. Address, Route, NetDev, and so on. */ void *userdata; /* freeing userdata when the request is completed or failed. */ mfree_func_t free_func; /* hash and compare functions for userdata, used for dedup requests. */ hash_func_t hash_func; compare_func_t compare_func; /* Checks the request dependencies, and then processes this request, e.g. call address_configure(). * Return 1 when processed, 0 when its dependencies not resolved, and negative errno on failure. */ request_process_func_t process; /* incremented when requested, decremented when request is completed or failed. */ unsigned *counter; /* called in netlink handler, the 'counter' is decremented before this is called. * If this is specified, then the 'process' function must increment the reference of this * request, and pass this request to the netlink_call_async(), and set the destroy function * to the slot. */ request_netlink_handler_t netlink_handler; bool waiting_reply; }; Request *request_ref(Request *req); Request *request_unref(Request *req); DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_unref); void request_detach(Request *req); int netdev_queue_request( NetDev *netdev, request_process_func_t process, Request **ret); int link_queue_request_full( Link *link, RequestType type, void *userdata, mfree_func_t free_func, hash_func_t hash_func, compare_func_t compare_func, request_process_func_t process, unsigned *counter, request_netlink_handler_t netlink_handler, Request **ret); int manager_queue_request_full( Manager *manager, RequestType type, void *userdata, mfree_func_t free_func, hash_func_t hash_func, compare_func_t compare_func, request_process_func_t process, unsigned *counter, request_netlink_handler_t netlink_handler, Request **ret); int link_requeue_request(Link *link, Request *req, void *userdata, Request **ret); static inline int link_queue_request( Link *link, RequestType type, request_process_func_t process, Request **ret) { return link_queue_request_full(link, type, NULL, NULL, NULL, NULL, process, NULL, NULL, ret); } #define link_queue_request_safe(link, type, userdata, free_func, hash_func, compare_func, process, counter, netlink_handler, ret) \ ({ \ typeof(userdata) (*_f)(typeof(userdata)) = (free_func); \ void (*_h)(const typeof(*userdata)*, struct siphash*) = (hash_func); \ int (*_c)(const typeof(*userdata)*, const typeof(*userdata)*) = (compare_func); \ int (*_p)(Request*, Link*, typeof(userdata)) = (process); \ int (*_n)(sd_netlink*, sd_netlink_message*, Request*, Link*, typeof(userdata)) = (netlink_handler); \ \ link_queue_request_full(link, type, userdata, \ (mfree_func_t) _f, \ (hash_func_t) _h, \ (compare_func_t) _c, \ (request_process_func_t) _p, \ counter, \ (request_netlink_handler_t) _n, \ ret); \ }) int manager_process_requests(Manager *manager); int request_call_netlink_async(sd_netlink *nl, sd_netlink_message *m, Request *req); const char* request_type_to_string(RequestType t) _const_; typedef struct RemoveRequest RemoveRequest; typedef int (*remove_request_netlink_handler_t)(sd_netlink *nl, sd_netlink_message *m, RemoveRequest *req); struct RemoveRequest { Manager *manager; Link *link; void *userdata; /* e.g. Address */ mfree_func_t unref_func; /* e.g. address_unref() */ sd_netlink *netlink; sd_netlink_message *message; remove_request_netlink_handler_t netlink_handler; }; int remove_request_add( Manager *manager, Link *link, void *userdata, /* This is unref()ed when the call failed. */ mfree_func_t unref_func, sd_netlink *netlink, sd_netlink_message *message, remove_request_netlink_handler_t netlink_handler); #define _remove_request_add(manager, link, data, name, nl, m, handler) \ ({ \ typeof(*data) *_data = (data); \ int _r; \ \ _r = remove_request_add(manager, link, _data, \ (mfree_func_t) name##_unref, \ nl, m, handler); \ if (_r >= 0) \ name##_ref(_data); \ _r; \ }) #define link_remove_request_add(link, data, name, nl, m, handler) \ ({ \ Link *_link = (link); \ \ _remove_request_add(_link->manager, _link, data, name, \ nl, m, handler); \ }) #define manager_remove_request_add(manager, data, name, nl, m, handler) \ _remove_request_add(manager, NULL, data, name, nl, m, handler) int manager_process_remove_requests(Manager *manager);