Cover Letter Detail
Show a cover letter.
GET /api/covers/826675/?format=api
{ "id": 826675, "url": "http://patchwork.ozlabs.org/api/covers/826675/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/cover/20171017010128.22141-1-vinicius.gomes@intel.com/", "project": { "id": 46, "url": "http://patchwork.ozlabs.org/api/projects/46/?format=api", "name": "Intel Wired Ethernet development", "link_name": "intel-wired-lan", "list_id": "intel-wired-lan.osuosl.org", "list_email": "intel-wired-lan@osuosl.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20171017010128.22141-1-vinicius.gomes@intel.com>", "list_archive_url": null, "date": "2017-10-17T01:01:22", "name": "[next-queue,v9,0/6] TSN: Add qdisc based config interface for CBS", "submitter": { "id": 72272, "url": "http://patchwork.ozlabs.org/api/people/72272/?format=api", "name": "Vinicius Costa Gomes", "email": "vinicius.gomes@intel.com" }, "mbox": "http://patchwork.ozlabs.org/project/intel-wired-lan/cover/20171017010128.22141-1-vinicius.gomes@intel.com/mbox/", "series": [ { "id": 8543, "url": "http://patchwork.ozlabs.org/api/series/8543/?format=api", "web_url": "http://patchwork.ozlabs.org/project/intel-wired-lan/list/?series=8543", "date": "2017-10-17T01:01:23", "name": "TSN: Add qdisc based config interface for CBS", "version": 9, "mbox": "http://patchwork.ozlabs.org/series/8543/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/covers/826675/comments/", "headers": { "Return-Path": "<intel-wired-lan-bounces@osuosl.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Delivered-To": [ "patchwork-incoming@bilbo.ozlabs.org", "intel-wired-lan@lists.osuosl.org" ], "Authentication-Results": "ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.133; helo=hemlock.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)", "Received": [ "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3yGH2t6xrZz9sP1\n\tfor <incoming@patchwork.ozlabs.org>;\n\tTue, 17 Oct 2017 12:01:58 +1100 (AEDT)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 81AC7873DB;\n\tTue, 17 Oct 2017 01:01:57 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id N8m1mxEBr0ge; Tue, 17 Oct 2017 01:01:49 +0000 (UTC)", "from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id A551086E28;\n\tTue, 17 Oct 2017 01:01:48 +0000 (UTC)", "from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id 1F5EC1CEF32\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 17 Oct 2017 01:01:46 +0000 (UTC)", "from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 135CE86DA6\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 17 Oct 2017 01:01:46 +0000 (UTC)", "from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id cWyura79GDvs for <intel-wired-lan@lists.osuosl.org>;\n\tTue, 17 Oct 2017 01:01:43 +0000 (UTC)", "from mga03.intel.com (mga03.intel.com [134.134.136.65])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 8AA3286C4B\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tTue, 17 Oct 2017 01:01:43 +0000 (UTC)", "from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby orsmga103.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t16 Oct 2017 18:01:42 -0700", "from ellie.jf.intel.com (HELO localhost.localdomain)\n\t([10.24.13.70])\n\tby fmsmga002.fm.intel.com with ESMTP; 16 Oct 2017 18:01:41 -0700" ], "X-Virus-Scanned": [ "amavisd-new at osuosl.org", "amavisd-new at osuosl.org" ], "X-Greylist": "domain auto-whitelisted by SQLgrey-1.7.6", "X-ExtLoop1": "1", "X-IronPort-AV": "E=Sophos; i=\"5.43,389,1503385200\"; d=\"scan'208\";\n\ta=\"1231539017\"", "From": "Vinicius Costa Gomes <vinicius.gomes@intel.com>", "To": "netdev@vger.kernel.org,\n\tintel-wired-lan@lists.osuosl.org", "Date": "Mon, 16 Oct 2017 18:01:22 -0700", "Message-Id": "<20171017010128.22141-1-vinicius.gomes@intel.com>", "X-Mailer": "git-send-email 2.14.2", "Cc": "rodney.cummings@ni.com, andre.guedes@intel.com, jiri@resnulli.us,\n\tivan.briano@intel.com, richardcochran@gmail.com, henrik@austad.us,\n\tjhs@mojatatu.com, levipearson@gmail.com, boon.leong.ong@intel.com,\n\txiyou.wangcong@gmail.com, jesus.sanchez-palencia@intel.com", "Subject": "[Intel-wired-lan] [next-queue PATCH v9 0/6] TSN: Add qdisc based\n\tconfig interface for CBS", "X-BeenThere": "intel-wired-lan@osuosl.org", "X-Mailman-Version": "2.1.18-1", "Precedence": "list", "List-Id": "Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>", "List-Unsubscribe": "<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>", "List-Archive": "<http://lists.osuosl.org/pipermail/intel-wired-lan/>", "List-Post": "<mailto:intel-wired-lan@osuosl.org>", "List-Help": "<mailto:intel-wired-lan-request@osuosl.org?subject=help>", "List-Subscribe": "<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "intel-wired-lan-bounces@osuosl.org", "Sender": "\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>" }, "content": "Hi,\n\nChanges from v8:\n - Add an explicit padding field to the tc_cbs_qopt struct, as pointed\n out by David Laight;\n\nChanges from v7:\n - Fixed comments from Eric Dumazet and Ivan Khoronzhuk;\n\nChanges since v6:\n - Fixed compilation for 32bit arches;\n - Aligned the behaviour of .select_queue() of the mq qdisc to be the\n same as mqprio;\n\nChanges since v5:\n - Fixed comments from Jiri Pirko;\n\nChanges since v4:\n - Added a software implementation of the CBS algorithm;\n\nChanges since v3:\n - None, only a clean patchset without old patches;\n\nChanges since v2:\n - squashed the patch introducing the userspace API into the patch\n implementing CBS;\n\nChanges since v1:\n - Solved the mqprio dependency;\n - Fixed a mqprio bug, that caused the inner qdisc to have a wrong\n dev_queue associated with it;\n\nChanges from the RFC:\n - Fixed comments from Henrik Austad;\n - Simplified the Qdisc, using the generic implementation of callbacks\n where possible;\n - Small refactor on the driver (igb) code;\n\nThis patchset is a proposal of how the Traffic Control subsystem can\nbe used to offload the configuration of the Credit Based Shaper\n(defined in the IEEE 802.1Q-2014 Section 8.6.8.2) into supported\nnetwork devices.\n\nAs part of this work, we've assessed previous public discussions\nrelated to TSN enabling: patches from Henrik Austad (Cisco), the\npresentation from Eric Mann at Linux Plumbers 2012, patches from\nGangfeng Huang (National Instruments) and the current state of the\nOpenAVNU project (https://github.com/AVnu/OpenAvnu/).\n\nOverview\n========\n\nTime-sensitive Networking (TSN) is a set of standards that aim to\naddress resources availability for providing bandwidth reservation and\nbounded latency on Ethernet based LANs. The proposal described here\naims to cover mainly what is needed to enable the following standards:\n802.1Qat and 802.1Qav.\n\nThe initial target of this work is the Intel i210 NIC, but other\ncontrollers' datasheet were also taken into account, like the Renesas\nRZ/A1H RZ/A1M group and the Synopsis DesignWare Ethernet QoS\ncontroller.\n\n\nProposal\n========\n\nFeature-wise, what is covered here is the configuration interfaces for\nHW implementations of the Credit-Based shaper (CBS, 802.1Qav). CBS is\na per-queue shaper. Given that this feature is related to traffic\nshaping, and that the traffic control subsystem already provides a\nqueueing discipline that offloads config into the device driver (i.e.\nmqprio), designing a new qdisc for the specific purpose of offloading\nthe config for the CBS shaper seemed like a good fit.\n\nFor steering traffic into the correct queues, we use the socket option\nSO_PRIORITY and then a mechanism to map priority to traffic classes /\nTx queues. The qdisc mqprio is currently used in our tests.\n\nAs for the CBS config interface, this patchset is proposing a new\nqdisc called 'cbs'. Its 'tc' cmd line is:\n\n$ tc qdisc add dev IFACE parent ID cbs locredit N hicredit M sendslope S \\\n idleslope I\n\n Note that the parameters for this qdisc are the ones defined by the\n 802.1Q-2014 spec, so no hardware specific functionality is exposed here.\n\nPer-stream shaping, as defined by IEEE 802.1Q-2014 Section 34.6.1, is\nnot yet covered by this proposal.\n\n\nTesting this RFC\n================\n\nAttached to this cover letter are:\n - calculate_cbs_params.py: A Python script to calculate the\n parameters to the CBS queueing discipline;\n - tsn-talker.c: A sample C implementation of the talker side of a stream;\n - tsn-listener.c: A sample C implementation of the listener side of a\n stream;\n\nFor testing the patches of this series, you may want to use the\nattached samples to this cover letter and use the 'mqprio' qdisc to\nsetup the priorities to Tx queues mapping, together with the 'cbs'\nqdisc to configure the HW shaper of the i210 controller:\n\n1) Setup priorities to traffic classes to hardware queues mapping\n$ tc qdisc replace dev ens4 handle 100: parent root mqprio num_tc 3 \\\n map 2 2 1 0 2 2 2 2 2 2 2 2 2 2 2 2 queues 1@0 1@1 2@2 hw 0\n\nFor a more detailed explanation, see mqprio(8), in short, this command\nwill map traffic with priority 3 to the hardware queue 0, traffic with\npriority 2 to hardware queue 1, and the rest will be mapped to\nhardware queues 2 and 3.\n\n2) Check scheme. You want to get the inner qdiscs ID from the bottom up\n$ tc -g class show dev ens4\n\nEx.:\n+---(100:3) mqprio\n| +---(100:6) mqprio\n| +---(100:7) mqprio\n|\n+---(100:2) mqprio\n| +---(100:5) mqprio\n|\n+---(100:1) mqprio\n +---(100:4) mqprio\n\n* Here '100:4' is Tx Queue #0 and '100:5' is Tx Queue #1.\n\n3) Calculate CBS parameters for classes A and B. i.e. BW for A is 20Mbps and\n for B is 10Mbps:\n$ calc_cbs_params.py -A 20000 -a 1500 -B 10000 -b 1500\n\n4) Configure CBS for traffic class A (priority 3) as provided by the script:\n$ tc qdisc replace dev ens4 parent 100:4 cbs locredit -1470 \\\n hicredit 30 sendslope -980000 idleslope 20000\n\n5) Configure CBS for traffic class B (priority 2):\n$ tc qdisc replace dev ens4 parent 100:5 cbs \\\n locredit -1485 hicredit 31 sendslope -990000 idleslope 10000\n\n6) Run Listener:\n$ ./tsn-listener -d 01:AA:AA:AA:AA:AA -i ens4 -s 1500\n\n7) Run Talker for class A (prio 3 here), compiled from samples/tsn/talker.c\n$ ./tsn-talker -d 01:AA:AA:AA:AA:AA -i ens4 -p 3 -s 1500\n\n * The bandwidth displayed on the listener output at this stage should be very\n close to the one configured for class A.\n\n8) You can also run a Talker for class B (prio 2 here and using a\ndifferent address):\n$ ./tsn-talker -d 01:BB:BB:BB:BB:BB -i ens4 -p 2 -s 1500\n\n\nAuthors\n=======\n - Andre Guedes <andre.guedes@intel.com>\n - Ivan Briano <ivan.briano@intel.com>\n - Jesus Sanchez-Palencia <jesus.sanchez-palencia@intel.com>\n - Vinicius Gomes <vinicius.gomes@intel.com>\n\n\nAndre Guedes (1):\n igb: Add support for CBS offload\n\nJesus Sanchez-Palencia (3):\n net/sched: Check for null dev_queue on create flow\n net/sched: Change behavior of mq select_queue()\n net/sched: Add select_queue() class_ops for mqprio\n\nVinicius Costa Gomes (2):\n net/sched: Introduce Credit Based Shaper (CBS) qdisc\n net/sched: Add support for HW offloading for CBS\n\n drivers/net/ethernet/intel/igb/e1000_defines.h | 23 ++\n drivers/net/ethernet/intel/igb/e1000_regs.h | 8 +\n drivers/net/ethernet/intel/igb/igb.h | 6 +\n drivers/net/ethernet/intel/igb/igb_main.c | 347 +++++++++++++++++++++++\n include/linux/netdevice.h | 1 +\n include/net/pkt_sched.h | 9 +\n include/uapi/linux/pkt_sched.h | 19 ++\n net/sched/Kconfig | 11 +\n net/sched/Makefile | 1 +\n net/sched/sch_cbs.c | 373 +++++++++++++++++++++++++\n net/sched/sch_generic.c | 8 +-\n net/sched/sch_mq.c | 10 +-\n net/sched/sch_mqprio.c | 7 +\n 13 files changed, 813 insertions(+), 10 deletions(-)\n create mode 100644 net/sched/sch_cbs.c\n\n\nAnnex: Sample files\n===================\n\ncalc_cbs_params.py\n--8<---------------cut here---------------start------------->8---\n#!/usr/bin/env python\n#\n# Copyright (c) 2017, Intel Corporation\n#\n# Redistribution and use in source and binary forms, with or without\n# modification, are permitted provided that the following conditions are met:\n#\n# * Redistributions of source code must retain the above copyright notice,\n# this list of conditions and the following disclaimer.\n# * Redistributions in binary form must reproduce the above copyright\n# notice, this list of conditions and the following disclaimer in the\n# documentation and/or other materials provided with the distribution.\n# * Neither the name of Intel Corporation nor the names of its contributors\n# may be used to endorse or promote products derived from this software\n# without specific prior written permission.\n#\n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nimport argparse\nimport math\n\ndef print_cbs_params_for_class_a(args):\n idleslope = args.idleslope_a\n sendslope = idleslope - args.link_speed\n\n # According to 802.1Q-2014 spec, Annex L, hiCredit and\n # loCredit for SR class A are calculated following the\n # equations L-10 and L-12, respectively.\n hicredit = math.ceil(idleslope * args.frame_non_sr / args.link_speed)\n locredit = math.ceil(sendslope * args.frame_a / args.link_speed)\n\n print(\"tc qdisc add dev <IFNAME> parent <QDISC-ID> cbs idleslope %d sendslope %d hicredit %d locredit %d\" % \\\n (idleslope, sendslope, hicredit, locredit))\n\ndef print_cbs_params_for_class_b(args):\n idleslope = args.idleslope_b\n sendslope = idleslope - args.link_speed\n\n # Annex L doesn't present a straightforward equation to\n # calculate hiCredit for Class B so we have to derive it\n # based on generic equations presented in that Annex.\n #\n # L-3 is the primary equation to calculate hiCredit. Section\n # L.2 states that the 'maxInterferenceSize' for SR class B\n # is the maximum burst size for SR class A plus the\n # maxInterferenceSize from SR class A (which is equal to the\n # maximum frame from non-SR traffic).\n #\n # The maximum burst size for SR class A equation is shown in\n # L-16. Merging L-16 into L-3 we get the resulting equation\n # which calculates hiCredit B (refer to section L.3 in case\n # you're not familiar with the legend):\n #\n # hiCredit B = Rb * ( Mo Ma )\n # ---------- + ------\n # Ro - Ra Ro\n #\n hicredit = math.ceil(idleslope * \\\n ((args.frame_non_sr / (args.link_speed - args.idleslope_a)) + \\\n (args.frame_a / args.link_speed)))\n\n # loCredit B is calculated following equation L-2.\n locredit = math.ceil(sendslope * args.frame_b / args.link_speed)\n\n print(\"tc qdisc add dev <IFNAME> parent <QDISC-ID> cbs idleslope %d sendslope %d hicredit %d locredit %d\" % \\\n (idleslope, sendslope, hicredit, locredit))\n\ndef main():\n parser = argparse.ArgumentParser()\n\n parser.add_argument('-S', dest='link_speed', default=1000000.0, type=float,\n help='Link speed in kbps')\n parser.add_argument('-s', dest='frame_non_sr', default=1500.0, type=float,\n help='Maximum frame size from non-SR traffic (MTU size'\n 'usually')\n parser.add_argument('-A', dest='idleslope_a', default=0, type=float,\n help='Idleslope for SR class A in kbps')\n parser.add_argument('-a', dest='frame_a', default=0, type=float,\n help='Maximum frame size for SR class A traffic')\n parser.add_argument('-B', dest='idleslope_b', default=0, type=float,\n help='Idleslope for SR class B in kbps')\n parser.add_argument('-b', dest='frame_b', default=0, type=float,\n help='Maximum frame size for SR class B traffic')\n\n args = parser.parse_args()\n\n if args.idleslope_a > 0:\n print_cbs_params_for_class_a(args)\n\n if args.idleslope_b > 0:\n print_cbs_params_for_class_b(args)\n\nif __name__ == \"__main__\":\n main()\n--8<---------------cut here---------------end--------------->8---\n\ntsn-talker.c\n--8<---------------cut here---------------start------------->8---\n/*\n * Copyright (c) 2017, Intel Corporation\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * * Neither the name of Intel Corporation nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <alloca.h>\n#include <argp.h>\n#include <arpa/inet.h>\n#include <inttypes.h>\n#include <linux/if.h>\n#include <linux/if_ether.h>\n#include <linux/if_packet.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <unistd.h>\n\n#define MAGIC 0xCC\n\nstatic uint8_t ifname[IFNAMSIZ];\nstatic uint8_t macaddr[ETH_ALEN];\nstatic int priority = -1;\nstatic size_t size = 1500;\nstatic uint64_t seq;\nstatic int delay = -1;\n\nstatic struct argp_option options[] = {\n\t{\"dst-addr\", 'd', \"MACADDR\", 0, \"Stream Destination MAC address\" },\n\t{\"delay\", 'D', \"NUM\", 0, \"Delay (in us) between packet transmission\" },\n\t{\"ifname\", 'i', \"IFNAME\", 0, \"Network Interface\" },\n\t{\"prio\", 'p', \"NUM\", 0, \"SO_PRIORITY to be set in socket\" },\n\t{\"packet-size\", 's', \"NUM\", 0, \"Size of packets to be transmitted\" },\n\t{ 0 }\n};\n\nstatic error_t parser(int key, char *arg, struct argp_state *state)\n{\n\tint res;\n\n\tswitch (key) {\n\tcase 'd':\n\t\tres = sscanf(arg, \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t\t\t&macaddr[0], &macaddr[1], &macaddr[2],\n\t\t\t\t\t&macaddr[3], &macaddr[4], &macaddr[5]);\n\t\tif (res != 6) {\n\t\t\tprintf(\"Invalid address\\n\");\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\n\t\tbreak;\n\tcase 'D':\n\t\tdelay = atoi(arg);\n\t\tbreak;\n\tcase 'i':\n\t\tstrncpy(ifname, arg, sizeof(ifname) - 1);\n\t\tbreak;\n\tcase 'p':\n\t\tpriority = atoi(arg);\n\t\tbreak;\n\tcase 's':\n\t\tsize = atoi(arg);\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstatic struct argp argp = { options, parser };\n\nint main(int argc, char *argv[])\n{\n\tint fd, res;\n\tstruct ifreq req;\n\tuint8_t *data;\n\tstruct sockaddr_ll sk_addr = {\n\t\t.sll_family = AF_PACKET,\n\t\t.sll_protocol = htons(ETH_P_TSN),\n\t\t.sll_halen = ETH_ALEN,\n\t};\n\n\targp_parse(&argp, argc, argv, 0, NULL, NULL);\n\n\tfd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN));\n\tif (fd < 0) {\n\t\tperror(\"Couldn't open socket\");\n\t\treturn 1;\n\t}\n\n\tstrncpy(req.ifr_name, ifname, sizeof(req.ifr_name));\n\tres = ioctl(fd, SIOCGIFINDEX, &req);\n\tif (res < 0) {\n\t\tperror(\"Couldn't get interface index\");\n\t\tgoto err;\n\t}\n\n\tsk_addr.sll_ifindex = req.ifr_ifindex;\n\tmemcpy(&sk_addr.sll_addr, macaddr, ETH_ALEN);\n\n\tif (priority != -1) {\n\t\tres = setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &priority,\n\t\t\t\t\t\t\tsizeof(priority));\n\t\tif (res < 0) {\n\t\t\tperror(\"Couldn't set priority\");\n\t\t\tgoto err;\n\t\t}\n\n\t}\n\n\tdata = alloca(size);\n\tmemset(data, MAGIC, size);\n\n\tprintf(\"Sending packets...\\n\");\n\n\twhile (1) {\n\t\tuint64_t *seq_ptr = (uint64_t *) &data[0];\n\t\tssize_t n;\n\n\t\t*seq_ptr = seq++;\n\n\t\tn = sendto(fd, data, size, 0, (struct sockaddr *) &sk_addr,\n\t\t\t\t\t\t\tsizeof(sk_addr));\n\t\tif (n < 0)\n\t\t\tperror(\"Failed to send data\");\n\n\t\tif (delay > 0)\n\t\t\tusleep(delay);\n\t}\n\n\tclose(fd);\n\treturn 0;\n\nerr:\n\tclose(fd);\n\treturn 1;\n}\n--8<---------------cut here---------------end--------------->8---\n\ntsn-listener.c\n--8<---------------cut here---------------start------------->8---\n/*\n * Copyright (c) 2017, Intel Corporation\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are met:\n *\n * * Redistributions of source code must retain the above copyright notice,\n * this list of conditions and the following disclaimer.\n * * Redistributions in binary form must reproduce the above copyright\n * notice, this list of conditions and the following disclaimer in the\n * documentation and/or other materials provided with the distribution.\n * * Neither the name of Intel Corporation nor the names of its contributors\n * may be used to endorse or promote products derived from this software\n * without specific prior written permission.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\n * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE\n * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\n * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include <alloca.h>\n#include <argp.h>\n#include <arpa/inet.h>\n#include <inttypes.h>\n#include <linux/if.h>\n#include <linux/if_ether.h>\n#include <linux/if_packet.h>\n#include <poll.h>\n#include <stdbool.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <sys/timerfd.h>\n#include <unistd.h>\n\nstatic uint8_t ifname[IFNAMSIZ];\nstatic uint8_t macaddr[ETH_ALEN];\nstatic uint64_t data_count;\nstatic int size = 1500;\nstatic time_t interval = 1;\nstatic bool check_seq = false;\nstatic uint64_t expected_seq;\n\nstatic struct argp_option options[] = {\n\t{\"check-seq\", 'c', NULL, 0, \"Check sequence number within packet\" },\n\t{\"dst-addr\", 'd', \"MACADDR\", 0, \"Stream Destination MAC address\" },\n\t{\"ifname\", 'i', \"IFNAME\", 0, \"Network Interface\" },\n\t{\"interval\", 'I', \"SEC\", 0, \"Interval between bandwidth reports\" },\n\t{\"packet-size\", 's', \"NUM\", 0, \"Expected packet size\" },\n\t{ 0 }\n};\n\nstatic error_t parser(int key, char *arg, struct argp_state *state)\n{\n\tint res;\n\n\tswitch (key) {\n\tcase 'c':\n\t\tcheck_seq = true;\n\t\tbreak;\n\tcase 'd':\n\t\tres = sscanf(arg, \"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx\",\n\t\t\t\t\t&macaddr[0], &macaddr[1], &macaddr[2],\n\t\t\t\t\t&macaddr[3], &macaddr[4], &macaddr[5]);\n\t\tif (res != 6) {\n\t\t\tprintf(\"Invalid address\\n\");\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\n\t\tbreak;\n\tcase 'i':\n\t\tstrncpy(ifname, arg, sizeof(ifname) - 1);\n\t\tbreak;\n\tcase 'I':\n\t\tinterval = atoi(arg);\n\t\tbreak;\n\tcase 's':\n\t\tsize = atoi(arg);\n\t\tbreak;\n\t}\n\n\treturn 0;\n}\n\nstatic struct argp argp = { options, parser };\n\nstatic int setup_timer(void)\n{\n\tint fd, res;\n\tstruct itimerspec tspec = { 0 };\n\n\tfd = timerfd_create(CLOCK_MONOTONIC, 0);\n\tif (fd < 0) {\n\t\tperror(\"Couldn't create timer\");\n\t\treturn -1;\n\t}\n\n\ttspec.it_value.tv_sec = interval;\n\ttspec.it_interval.tv_sec = interval;\n\n\tres = timerfd_settime(fd, 0, &tspec, NULL);\n\tif (res < 0) {\n\t\tperror(\"Couldn't set timer\");\n\t\tclose(fd);\n\t\treturn -1;\n\t}\n\n\treturn fd;\n}\n\nstatic int setup_socket(void)\n{\n\tint fd, res;\n\tstruct sockaddr_ll sk_addr = {\n\t\t.sll_family = AF_PACKET,\n\t\t.sll_protocol = htons(ETH_P_TSN),\n\t};\n\n\tfd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_TSN));\n\tif (fd < 0) {\n\t\tperror(\"Couldn't open socket\");\n\t\treturn -1;\n\t}\n\n\t/* If user provided a network interface, bind() to it. */\n\tif (ifname[0] != '\\0') {\n\t\tstruct ifreq req;\n\n\t\tstrncpy(req.ifr_name, ifname, sizeof(req.ifr_name));\n\t\tres = ioctl(fd, SIOCGIFINDEX, &req);\n\t\tif (res < 0) {\n\t\t\tperror(\"Couldn't get interface index\");\n\t\t\tgoto err;\n\t\t}\n\n\t\tsk_addr.sll_ifindex = req.ifr_ifindex;\n\n\t\tres = bind(fd, (struct sockaddr *) &sk_addr, sizeof(sk_addr));\n\t\tif (res < 0) {\n\t\t\tperror(\"Couldn't bind() to interface\");\n\t\t\tgoto err;\n\t\t}\n\t}\n\n\t/* If user provided the stream destination address, set it as multicast\n\t * address.\n\t */\n\tif (macaddr[0] != '\\0') {\n\t\tstruct packet_mreq mreq;\n\n\t\tmreq.mr_ifindex = sk_addr.sll_ifindex;\n\t\tmreq.mr_type = PACKET_MR_MULTICAST;\n\t\tmreq.mr_alen = ETH_ALEN;\n\t\tmemcpy(&mreq.mr_address, macaddr, ETH_ALEN);\n\n\t\tres = setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,\n\t\t\t\t\t&mreq, sizeof(struct packet_mreq));\n\t\tif (res < 0) {\n\t\t\tperror(\"Couldn't set PACKET_ADD_MEMBERSHIP\");\n\t\t\tgoto err;\n\t\t}\n\t}\n\n\treturn fd;\n\nerr:\n\tclose(fd);\n\treturn -1;\n}\n\nstatic void recv_packet(int fd)\n{\n\tuint8_t *data = alloca(size);\n\tssize_t n = recv(fd, data, size, 0);\n\n\tif (n < 0) {\n\t\tperror(\"Failed to receive data\");\n\t\treturn;\n\t}\n\n\tif (n != size)\n\t\tprintf(\"Size mismatch: expected %d, got %d\\n\", size, n);\n\n\tif (check_seq) {\n\t\tuint64_t *seq = (uint64_t *) &data[0];\n\n\t\t/* If 'expected_seq' is equal to zero, it means this is the\n\t\t * first packet we received so we don't know what sequence\n\t\t * number to expect.\n\t\t */\n\t\tif (expected_seq == 0)\n\t\t\texpected_seq = *seq;\n\n\t\tif (*seq != expected_seq) {\n\t\t\tprintf(\"Sequence mismatch: expected %llu, got %llu\\n\",\n\t\t\t\t\texpected_seq, *seq);\n\n\t\t\texpected_seq = *seq;\n\t\t}\n\n\t\texpected_seq++;\n\t}\n\n\tdata_count += n;\n}\n\nstatic void report_bw(int fd)\n{\n\tuint64_t expirations;\n\tssize_t n = read(fd, &expirations, sizeof(uint64_t));\n\n\tif (n < 0) {\n\t\tperror(\"Couldn't read timerfd\");\n\t\treturn;\n\t}\n\n\tif (expirations != 1)\n\t\tprintf(\"Some went wrong with timerfd\\n\");\n\n\tprintf(\"Receiving data rate: %llu kbps\\n\", (data_count * 8) / (1000 * interval));\n\n\tdata_count = 0;\n}\n\nint main(int argc, char *argv[])\n{\n\tint sk_fd, timer_fd, res;\n\tstruct pollfd fds[2];\n\n\targp_parse(&argp, argc, argv, 0, NULL, NULL);\n\n\tsk_fd = setup_socket();\n\tif (sk_fd < 0)\n\t\treturn 1;\n\n\ttimer_fd = setup_timer();\n\tif (timer_fd < 0) {\n\t\tclose(sk_fd);\n\t\treturn 1;\n\t}\n\n\tfds[0].fd = sk_fd;\n\tfds[0].events = POLLIN;\n\tfds[1].fd = timer_fd;\n\tfds[1].events = POLLIN;\n\n\tprintf(\"Waiting for packets...\\n\");\n\n\twhile (1) {\n\t\tres = poll(fds, 2, -1);\n\t\tif (res < 0) {\n\t\t\tperror(\"Error on poll()\");\n\t\t\tgoto err;\n\t\t}\n\n\t\tif (fds[0].revents & POLLIN)\n\t\t\trecv_packet(fds[0].fd);\n\n\t\tif (fds[1].revents & POLLIN) {\n\t\t\treport_bw(fds[1].fd);\n\t\t}\n\t}\n\n\tclose(timer_fd);\n\tclose(sk_fd);\n\treturn 0;\n\nerr:\n\tclose(timer_fd);\n\tclose(sk_fd);\n\treturn 1;\n}\n--8<---------------cut here---------------end--------------->8---\n\n--\n2.14.2" }