123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- /*
- * lib/route/qdisc/plug.c PLUG Qdisc
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation version 2.1
- * of the License.
- *
- * Copyright (c) 2012 Shriram Rajagopalan <rshriram@cs.ubc.ca>
- */
- /**
- * @ingroup qdisc
- * @defgroup qdisc_plug Plug/Unplug Traffic (PLUG)
- * @brief
- *
- * Queue traffic until an explicit release command.
- *
- * There are two ways to use this qdisc:
- * 1. A simple "instantaneous" plug/unplug operation, by issuing an alternating
- * sequence of TCQ_PLUG_BUFFER & TCQ_PLUG_RELEASE_INDEFINITE commands.
- *
- * 2. For network output buffering (a.k.a output commit) functionality.
- * Output commit property is commonly used by applications using checkpoint
- * based fault-tolerance to ensure that the checkpoint from which a system
- * is being restored is consistent w.r.t outside world.
- *
- * Consider for e.g. Remus - a Virtual Machine checkpointing system,
- * wherein a VM is checkpointed, say every 50ms. The checkpoint is replicated
- * asynchronously to the backup host, while the VM continues executing the
- * next epoch speculatively.
- *
- * The following is a typical sequence of output buffer operations:
- * 1.At epoch i, start_buffer(i)
- * 2. At end of epoch i (i.e. after 50ms):
- * 2.1 Stop VM and take checkpoint(i).
- * 2.2 start_buffer(i+1) and Resume VM
- * 3. While speculatively executing epoch(i+1), asynchronously replicate
- * checkpoint(i) to backup host.
- * 4. When checkpoint_ack(i) is received from backup, release_buffer(i)
- * Thus, this Qdisc would receive the following sequence of commands:
- * TCQ_PLUG_BUFFER (epoch i)
- * .. TCQ_PLUG_BUFFER (epoch i+1)
- * ....TCQ_PLUG_RELEASE_ONE (epoch i)
- * ......TCQ_PLUG_BUFFER (epoch i+2)
- * ........
- *
- *
- * State of the queue, when used for network output buffering:
- *
- * plug(i+1) plug(i) head
- * ------------------+--------------------+---------------->
- * | |
- * | |
- * pkts_current_epoch| pkts_last_epoch |pkts_to_release
- * ----------------->|<--------+--------->|+--------------->
- * v v
- *
- *
- * @{
- */
- #include <netlink-private/netlink.h>
- #include <netlink-private/tc.h>
- #include <netlink/netlink.h>
- #include <netlink/utils.h>
- #include <netlink-private/route/tc-api.h>
- #include <netlink/route/qdisc/plug.h>
- static int plug_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
- {
- struct rtnl_plug *plug = data;
- struct tc_plug_qopt opts;
- if (!plug)
- return -NLE_INVAL;
- opts.action = plug->action;
- opts.limit = plug->limit;
- return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD);
- }
- /**
- * @name Attribute Modification
- * @{
- */
- /**
- * Insert a plug into the qdisc and buffer any incoming
- * network traffic.
- * @arg qdisc PLUG qdisc to be modified.
- */
- int rtnl_qdisc_plug_buffer(struct rtnl_qdisc *qdisc)
- {
- struct rtnl_plug *plug;
- if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
- return -NLE_NOMEM;
- plug->action = TCQ_PLUG_BUFFER;
- return 0;
- }
- /**
- * Unplug the qdisc, releasing packets from queue head
- * to the last complete buffer, while new traffic
- * continues to be buffered.
- * @arg qdisc PLUG qdisc to be modified.
- */
- int rtnl_qdisc_plug_release_one(struct rtnl_qdisc *qdisc)
- {
- struct rtnl_plug *plug;
- if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
- return -NLE_NOMEM;
- plug->action = TCQ_PLUG_RELEASE_ONE;
- return 0;
- }
- /**
- * Indefinitely unplug the qdisc, releasing all packets.
- * Network traffic will not be buffered until the next
- * buffer command is issued.
- * @arg qdisc PLUG qdisc to be modified.
- */
- int rtnl_qdisc_plug_release_indefinite(struct rtnl_qdisc *qdisc)
- {
- struct rtnl_plug *plug;
- if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
- return -NLE_NOMEM;
- plug->action = TCQ_PLUG_RELEASE_INDEFINITE;
- return 0;
- }
- /**
- * Set limit of PLUG qdisc.
- * @arg qdisc PLUG qdisc to be modified.
- * @arg limit New limit.
- * @return 0 on success or a negative error code.
- */
- int rtnl_qdisc_plug_set_limit(struct rtnl_qdisc *qdisc, int limit)
- {
- struct rtnl_plug *plug;
-
- if (!(plug = rtnl_tc_data(TC_CAST(qdisc))))
- return -NLE_NOMEM;
-
- plug->action = TCQ_PLUG_LIMIT;
- plug->limit = limit;
- return 0;
- }
- /** @} */
- static struct rtnl_tc_ops plug_ops = {
- .to_kind = "plug",
- .to_type = RTNL_TC_TYPE_QDISC,
- .to_size = sizeof(struct rtnl_plug),
- .to_msg_fill = plug_msg_fill,
- };
- static void __init plug_init(void)
- {
- rtnl_tc_register(&plug_ops);
- }
- static void __exit plug_exit(void)
- {
- rtnl_tc_unregister(&plug_ops);
- }
- /** @} */
|