summaryrefslogtreecommitdiff
path: root/src/network/networkd-queue.c
blob: e06a16bbb48037f556ea9df7705243beee99a33f (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
/* SPDX-License-Identifier: LGPL-2.1-or-later */

#include "networkd-address.h"
#include "networkd-manager.h"
#include "networkd-neighbor.h"
#include "networkd-nexthop.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-queue.h"

static void request_free_object(RequestType type, void *object) {
        switch(type) {
        case REQUEST_TYPE_ROUTING_POLICY_RULE:
                routing_policy_rule_free(object);
                break;
        default:
                assert_not_reached("invalid request type.");
        }
}

Request *request_free(Request *req) {
        if (!req)
                return NULL;

        if (req->on_free)
                req->on_free(req);
        if (req->consume_object)
                request_free_object(req->type, req->object);
        if (req->link && req->link->manager)
                ordered_set_remove(req->link->manager->request_queue, req);
        link_unref(req->link);

        return mfree(req);
}

DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free);

void request_drop(Request *req) {
        if (req->message_counter)
                (*req->message_counter)--;

        request_free(req);
}

int link_queue_request(
                Link *link,
                RequestType type,
                void *object,
                bool consume_object,
                unsigned *message_counter,
                link_netlink_message_handler_t netlink_handler,
                Request **ret) {

        _cleanup_(request_freep) Request *req = NULL;
        int r;

        assert(link);
        assert(link->manager);
        assert(type >= 0 && type < _REQUEST_TYPE_MAX);
        assert(object);
        assert(netlink_handler);

        req = new(Request, 1);
        if (!req) {
                if (consume_object)
                        request_free_object(type, object);
                return -ENOMEM;
        }

        *req = (Request) {
                .link = link,
                .type = type,
                .object = object,
                .consume_object = consume_object,
                .message_counter = message_counter,
                .netlink_handler = netlink_handler,
        };

        link_ref(link);

        r = ordered_set_ensure_put(&link->manager->request_queue, NULL, req);
        if (r < 0)
                return r;

        if (req->message_counter)
                (*req->message_counter)++;

        if (ret)
                *ret = req;

        TAKE_PTR(req);
        return 0;
}

int manager_process_requests(sd_event_source *s, void *userdata) {
        Manager *manager = userdata;
        int r;

        assert(manager);

        for (;;) {
                bool processed = false;
                Request *req;

                ORDERED_SET_FOREACH(req, manager->request_queue) {
                        switch(req->type) {
                        case REQUEST_TYPE_ROUTING_POLICY_RULE:
                                r = request_process_routing_policy_rule(req);
                                break;
                        default:
                                return -EINVAL;
                        }
                        if (r < 0)
                                link_enter_failed(req->link);
                        if (r > 0) {
                                ordered_set_remove(manager->request_queue, req);
                                request_free(req);
                                processed = true;
                        }
                }

                if (!processed)
                        break;
        }

        return 0;
}