libnl 3.7.0
plug.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
4 */
5
6/**
7 * @ingroup qdisc
8 * @defgroup qdisc_plug Plug/Unplug Traffic (PLUG)
9 * @brief
10 *
11 * Queue traffic until an explicit release command.
12 *
13 * There are two ways to use this qdisc:
14 * 1. A simple "instantaneous" plug/unplug operation, by issuing an alternating
15 * sequence of TCQ_PLUG_BUFFER & TCQ_PLUG_RELEASE_INDEFINITE commands.
16 *
17 * 2. For network output buffering (a.k.a output commit) functionality.
18 * Output commit property is commonly used by applications using checkpoint
19 * based fault-tolerance to ensure that the checkpoint from which a system
20 * is being restored is consistent w.r.t outside world.
21 *
22 * Consider for e.g. Remus - a Virtual Machine checkpointing system,
23 * wherein a VM is checkpointed, say every 50ms. The checkpoint is replicated
24 * asynchronously to the backup host, while the VM continues executing the
25 * next epoch speculatively.
26 *
27 * The following is a typical sequence of output buffer operations:
28 * 1.At epoch i, start_buffer(i)
29 * 2. At end of epoch i (i.e. after 50ms):
30 * 2.1 Stop VM and take checkpoint(i).
31 * 2.2 start_buffer(i+1) and Resume VM
32 * 3. While speculatively executing epoch(i+1), asynchronously replicate
33 * checkpoint(i) to backup host.
34 * 4. When checkpoint_ack(i) is received from backup, release_buffer(i)
35 * Thus, this Qdisc would receive the following sequence of commands:
36 * TCQ_PLUG_BUFFER (epoch i)
37 * .. TCQ_PLUG_BUFFER (epoch i+1)
38 * ....TCQ_PLUG_RELEASE_ONE (epoch i)
39 * ......TCQ_PLUG_BUFFER (epoch i+2)
40 * ........
41 *
42 *
43 * State of the queue, when used for network output buffering:
44 *
45 * plug(i+1) plug(i) head
46 * ------------------+--------------------+---------------->
47 * | |
48 * | |
49 * pkts_current_epoch| pkts_last_epoch |pkts_to_release
50 * ----------------->|<--------+--------->|+--------------->
51 * v v
52 *
53 *
54 * @{
55 */
56
57#include <netlink-private/netlink.h>
58#include <netlink-private/tc.h>
59#include <netlink/netlink.h>
60#include <netlink/utils.h>
61#include <netlink-private/route/tc-api.h>
62#include <netlink/route/qdisc/plug.h>
63
64static int plug_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
65{
66 struct rtnl_plug *plug = data;
67 struct tc_plug_qopt opts;
68
69 if (!plug)
70 return -NLE_INVAL;
71
72 opts.action = plug->action;
73 opts.limit = plug->limit;
74
75 return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
76}
77
78/**
79 * @name Attribute Modification
80 * @{
81 */
82
83/**
84 * Insert a plug into the qdisc and buffer any incoming
85 * network traffic.
86 * @arg qdisc PLUG qdisc to be modified.
87 */
88int rtnl_qdisc_plug_buffer(struct rtnl_qdisc *qdisc)
89{
90 struct rtnl_plug *plug;
91
92 if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
93 return -NLE_NOMEM;
94
95 plug->action = TCQ_PLUG_BUFFER;
96 return 0;
97}
98
99/**
100 * Unplug the qdisc, releasing packets from queue head
101 * to the last complete buffer, while new traffic
102 * continues to be buffered.
103 * @arg qdisc PLUG qdisc to be modified.
104 */
105int rtnl_qdisc_plug_release_one(struct rtnl_qdisc *qdisc)
106{
107 struct rtnl_plug *plug;
108
109 if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
110 return -NLE_NOMEM;
111
112 plug->action = TCQ_PLUG_RELEASE_ONE;
113 return 0;
114}
115
116/**
117 * Indefinitely unplug the qdisc, releasing all packets.
118 * Network traffic will not be buffered until the next
119 * buffer command is issued.
120 * @arg qdisc PLUG qdisc to be modified.
121 */
122int rtnl_qdisc_plug_release_indefinite(struct rtnl_qdisc *qdisc)
123{
124 struct rtnl_plug *plug;
125
126 if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
127 return -NLE_NOMEM;
128
129 plug->action = TCQ_PLUG_RELEASE_INDEFINITE;
130 return 0;
131}
132
133/**
134 * Set limit of PLUG qdisc.
135 * @arg qdisc PLUG qdisc to be modified.
136 * @arg limit New limit.
137 * @return 0 on success or a negative error code.
138 */
139int rtnl_qdisc_plug_set_limit(struct rtnl_qdisc *qdisc, int limit)
140{
141 struct rtnl_plug *plug;
142
143 if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
144 return -NLE_NOMEM;
145
146 plug->action = TCQ_PLUG_LIMIT;
147 plug->limit = limit;
148
149 return 0;
150}
151
152/** @} */
153
154static struct rtnl_tc_ops plug_ops = {
155 .to_kind = "plug",
156 .to_type = RTNL_TC_TYPE_QDISC,
157 .to_size = sizeof(struct rtnl_plug),
158 .to_msg_fill = plug_msg_fill,
159};
160
161static void __init plug_init(void)
162{
163 rtnl_tc_register(&plug_ops);
164}
165
166static void __exit plug_exit(void)
167{
168 rtnl_tc_unregister(&plug_ops);
169}
170
171/** @} */
int nlmsg_append(struct nl_msg *n, void *data, size_t len, int pad)
Append data to tail of a netlink message.
Definition: msg.c:442
int rtnl_qdisc_plug_release_indefinite(struct rtnl_qdisc *qdisc)
Indefinitely unplug the qdisc, releasing all packets.
Definition: plug.c:122
int rtnl_qdisc_plug_release_one(struct rtnl_qdisc *qdisc)
Unplug the qdisc, releasing packets from queue head to the last complete buffer, while new traffic co...
Definition: plug.c:105
int rtnl_qdisc_plug_buffer(struct rtnl_qdisc *qdisc)
Insert a plug into the qdisc and buffer any incoming network traffic.
Definition: plug.c:88
int rtnl_qdisc_plug_set_limit(struct rtnl_qdisc *qdisc, int limit)
Set limit of PLUG qdisc.
Definition: plug.c:139
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1015
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1049