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 
64 static 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  */
88 int 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  */
105 int 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  */
122 int 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  */
139 int 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 
154 static 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 
161 static void __init plug_init(void)
162 {
163  rtnl_tc_register(&plug_ops);
164 }
165 
166 static 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
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
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