From patchwork Mon Aug 6 17:09:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yousuk Seung X-Patchwork-Id: 954005 X-Patchwork-Delegate: dsahern@gmail.com Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=google.com header.i=@google.com header.b="B7SP0M4W"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 41kkfn3xxhz9ryt for ; Tue, 7 Aug 2018 03:10:09 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732588AbeHFTUJ (ORCPT ); Mon, 6 Aug 2018 15:20:09 -0400 Received: from mail-ua0-f202.google.com ([209.85.217.202]:34500 "EHLO mail-ua0-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728349AbeHFTUJ (ORCPT ); Mon, 6 Aug 2018 15:20:09 -0400 Received: by mail-ua0-f202.google.com with SMTP id n10-v6so9294770uao.1 for ; Mon, 06 Aug 2018 10:10:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=srn+SRc5D+5AzS9r1CVsg5P/W8n+cBs+GN7vDGpVZ28=; b=B7SP0M4W7lcuTS28t3y1z++BTokYhywz8RVkVlPEFkkhyAAPXVxG2oAXJXVOzOJcD9 BlDX9kM8Sv/u0PVc5eH/UiW5+Vf4hmkr1QHE0ENZNkMIWqLrQ9dJGZ4oO5fdPUrjvwOX jXTX8AU4ymAR9ZukUcYuhIW+qr1FZ8SZcDau5TYXKqaC0ewJKR48bC7eQOzeUoaGYNrW o9AupaGQglSo/WE4VSLZPsNm3/xLK+IvjxU2v6s7WfXOveeiV2rFXPz7f3Tg5fXP5szL ecGywZ0gbueXoSjBy8qc8MEEMrDoVinHR6kv7xuye9ao/g9BzlxYLgbVtMEC5Zp95UeN EzaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=srn+SRc5D+5AzS9r1CVsg5P/W8n+cBs+GN7vDGpVZ28=; b=LWSqbZUA11Yi9BnmAFO1diNUelU3772YlTArqb7YKl8VNQxg7nD01T86TbuR68P95J qrYJGEXrM8yVZoQgBOfshxQ4wB84NfPH76xnbfF8aFqGeLy/hep11ehyPKBBN3/MZPmg 7HRPbf9OGrcAvx6yvbN/l1o1lkvtMy34RhbpEF8RsHdhlnRiYf97zW/BNxR5/JlBRF+4 LvYyh7k3GW7UQPmuit1uLt//hRfh03tzhIKwEUmhKtbb/yPVei8cJt8zeuz2HaBbmQqT ByvF4ejIsMpP1jEw/jSe+AEWcmZmpDUyHXzLGWJioBk5+zIKcnQmSm5EHF29YCtR7Oc7 pu6Q== X-Gm-Message-State: AOUpUlHZ/PKqsfMTScdiZce26ppqDRSwgkm1DeGimBa7eLigmg+JucXQ CFMPFy8YvH9XJySJoCgb5otuniINT8RLTrLzNbdCMpBMcFyf/zp5aGfwLdKLTUzzX/Za7QMvsip UbkXpgcfMvM+Oy6lhQ3kyMUfGai5G3dXyv1IlgGAugg1yjbh7UPsi/NfAIGkhZrjI X-Google-Smtp-Source: AAOMgpcZPMtaScnRctpdsV2Wh+SXvDhPxawlYhqM3P87lMiK7LqUmScezbmEHlTaEfgCl8KPWi85x4ZVFdCQ X-Received: by 2002:a1f:ab48:: with SMTP id u69-v6mr9613499vke.70.1533575405993; Mon, 06 Aug 2018 10:10:05 -0700 (PDT) Date: Mon, 6 Aug 2018 10:09:52 -0700 In-Reply-To: <20180806170953.164776-1-ysseung@google.com> Message-Id: <20180806170953.164776-3-ysseung@google.com> Mime-Version: 1.0 References: <20180806170953.164776-1-ysseung@google.com> X-Mailer: git-send-email 2.18.0.597.ga71716f1ad-goog Subject: [PATCH iproute2-next 2/3] q_netem: support delivering packets in delayed time slots From: Yousuk Seung To: netdev@vger.kernel.org Cc: Stephen Hemminger , David Ahern , Michael McLennan , Priyaranjan Jha , Dave Taht , Yousuk Seung , Neal Cardwell Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Dave Taht Slotting is a crude approximation of the behaviors of shared media such as cable, wifi, and LTE, which gather up a bunch of packets within a varying delay window and deliver them, relative to that, nearly all at once. It works within the existing loss, duplication, jitter and delay parameters of netem. Some amount of inherent latency must be specified, regardless. The new "slot" parameter specifies a minimum and maximum delay between transmission attempts. The "bytes" and "packets" parameters can be used to limit the amount of information transferred per slot. Examples of use: tc qdisc add dev eth0 root netem delay 200us \ slot 800us 10ms bytes 64k packets 42 A more correct example, using stacked netem instances and a packet limit to emulate a tail drop wifi queue with slots and variable packet delivery, with a 200Mbit isochronous underlying rate, and 20ms path delay: tc qdisc add dev eth0 root handle 1: netem delay 20ms rate 200mbit \ limit 10000 tc qdisc add dev eth0 parent 1:1 handle 10:1 netem delay 200us \ slot 800us 10ms bytes 64k packets 42 limit 512 Signed-off-by: Yousuk Seung Signed-off-by: Dave Taht Signed-off-by: Neal Cardwell --- man/man8/tc-netem.8 | 32 ++++++++++++++++++++++- tc/q_netem.c | 63 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/man/man8/tc-netem.8 b/man/man8/tc-netem.8 index f2cd86b6ed8a..8d485b026751 100644 --- a/man/man8/tc-netem.8 +++ b/man/man8/tc-netem.8 @@ -8,7 +8,8 @@ NetEm \- Network Emulator .I OPTIONS .IR OPTIONS " := [ " LIMIT " ] [ " DELAY " ] [ " LOSS \ -" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ][ " RATE " ]" +" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ] [ " RATE \ +" ] [ " SLOT " ]" .IR LIMIT " := " .B limit @@ -51,6 +52,14 @@ NetEm \- Network Emulator .B rate .IR RATE " [ " PACKETOVERHEAD " [ " CELLSIZE " [ " CELLOVERHEAD " ]]]]" +.IR SLOT " := " +.BR slot +.IR MIN_DELAY " [ " MAX_DELAY " ] [" +.BR packets +.IR PACKETS " ] [ " +.BR bytes +.IR BYTES " ]" + .SH DESCRIPTION NetEm is an enhancement of the Linux traffic control facilities @@ -162,6 +171,27 @@ granularity avoid a perfect shaping at a specific level. This will show up in an artificial packet compression (bursts). Another influence factor are network adapter buffers which can also add artificial delay. +.SS slot +defer delivering accumulated packets to within a slot, with each available slot +configured with a minimum delay to acquire, and an optional maximum delay. Slot +delays can be specified in nanoseconds, microseconds, milliseconds or seconds +(e.g. 800us). Values for the optional parameters +.I BYTES +will limit the number of bytes delivered per slot, and/or +.I PACKETS +will limit the number of packets delivered per slot. + +These slot options can provide a crude approximation of bursty MACs such as +DOCSIS, WiFi, and LTE. + +Note that slotting is limited by several factors: the kernel clock granularity, +as with a rate, and attempts to deliver many packets within a slot will be +smeared by the timer resolution, and by the underlying native bandwidth also. + +It is possible to combine slotting with a rate, in which case complex behaviors +where either the rate, or the slot limits on bytes or packets per slot, govern +the actual delivered rate. + .SH LIMITATIONS The main known limitation of Netem are related to timer granularity, since Linux is not a real-time operating system. diff --git a/tc/q_netem.c b/tc/q_netem.c index 9f9a9b3df255..f52a36b6c31c 100644 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@ -40,7 +40,10 @@ static void explain(void) " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ " [ ecn ]\n" \ " [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ -" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n"); +" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \ +" [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \ +" [bytes MAX_BYTES]]\n" \ + ); } static void explain1(const char *arg) @@ -164,6 +167,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct tc_netem_gimodel gimodel; struct tc_netem_gemodel gemodel; struct tc_netem_rate rate = {}; + struct tc_netem_slot slot = {}; __s16 *dist_data = NULL; __u16 loss_type = NETEM_LOSS_UNSPEC; int present[__TCA_NETEM_MAX] = {}; @@ -412,6 +416,44 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, return -1; } } + } else if (matches(*argv, "slot") == 0) { + NEXT_ARG(); + present[TCA_NETEM_SLOT] = 1; + if (get_time64(&slot.min_delay, *argv)) { + explain1("slot min_delay"); + return -1; + } + if (NEXT_IS_NUMBER()) { + NEXT_ARG(); + if (get_time64(&slot.max_delay, *argv)) { + explain1("slot min_delay max_delay"); + return -1; + } + } + if (slot.max_delay < slot.min_delay) + slot.max_delay = slot.min_delay; + if (NEXT_ARG_OK() && + matches(*(argv+1), "packets") == 0) { + NEXT_ARG(); + if (!NEXT_ARG_OK() || + get_s32(&slot.max_packets, *(argv+1), 0)) { + explain1("slot packets"); + return -1; + } + NEXT_ARG(); + } + if (NEXT_ARG_OK() && + matches(*(argv+1), "bytes") == 0) { + unsigned int max_bytes; + NEXT_ARG(); + if (!NEXT_ARG_OK() || + get_size(&max_bytes, *(argv+1))) { + explain1("slot bytes"); + return -1; + } + slot.max_bytes = (int) max_bytes; + NEXT_ARG(); + } } else if (strcmp(*argv, "help") == 0) { explain(); return -1; @@ -472,6 +514,10 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv, addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0) return -1; + if (present[TCA_NETEM_SLOT] && + addattr_l(n, 1024, TCA_NETEM_SLOT, &slot, sizeof(slot)) < 0) + return -1; + if (loss_type != NETEM_LOSS_UNSPEC) { struct rtattr *start; @@ -526,6 +572,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) int *ecn = NULL; struct tc_netem_qopt qopt; const struct tc_netem_rate *rate = NULL; + const struct tc_netem_slot *slot = NULL; int len; __u64 rate64 = 0; @@ -586,6 +633,11 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) return -1; rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]); } + if (tb[TCA_NETEM_SLOT]) { + if (RTA_PAYLOAD(tb[TCA_NETEM_SLOT]) < sizeof(*slot)) + return -1; + slot = RTA_DATA(tb[TCA_NETEM_SLOT]); + } } fprintf(f, "limit %d", qopt.limit); @@ -659,6 +711,15 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) fprintf(f, " celloverhead %d", rate->cell_overhead); } + if (slot) { + fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1)); + fprintf(f, " %s", sprint_time64(slot->max_delay, b1)); + if(slot->max_packets) + fprintf(f, " packets %d", slot->max_packets); + if(slot->max_bytes) + fprintf(f, " bytes %d", slot->max_bytes); + } + if (ecn) fprintf(f, " ecn ");