summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-queue.h
blob: e35cd73efd944def8120bce462d904cef36e557a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/* 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 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);