const char *host;
        const char *service;
        unsigned int size;
+       unsigned int num_pkt;
        struct {
                unsigned int mark;
                unsigned int dontfrag;
                unsigned int tclass;
                unsigned int hlimit;
+               unsigned int priority;
        } sockopt;
        struct {
                unsigned int family;
        } v6;
 } opt = {
        .size = 13,
+       .num_pkt = 1,
        .sock = {
                .family = AF_UNSPEC,
                .type   = SOCK_DGRAM,
 {
        int o;
 
-       while ((o = getopt(argc, argv, "46sS:p:m:M:d:tf:F:c:C:l:L:H:")) != -1) {
+       while ((o = getopt(argc, argv, "46sS:p:P:m:M:n:d:tf:F:c:C:l:L:H:")) != -1) {
                switch (o) {
                case 's':
                        opt.silent_send = true;
                                cs_usage(argv[0]);
                        }
                        break;
-
+               case 'P':
+                       opt.sockopt.priority = atoi(optarg);
+                       break;
                case 'm':
                        opt.mark.ena = true;
                        opt.mark.val = atoi(optarg);
                case 'M':
                        opt.sockopt.mark = atoi(optarg);
                        break;
+               case 'n':
+                       opt.num_pkt = atoi(optarg);
+                       break;
                case 'd':
                        opt.txtime.ena = true;
                        opt.txtime.delay = atoi(optarg);
            setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS,
                       &opt.sockopt.hlimit, sizeof(opt.sockopt.hlimit)))
                error(ERN_SOCKOPT, errno, "setsockopt IPV6_HOPLIMIT");
+       if (opt.sockopt.priority &&
+           setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
+                      &opt.sockopt.priority, sizeof(opt.sockopt.priority)))
+               error(ERN_SOCKOPT, errno, "setsockopt SO_PRIORITY");
 }
 
 int main(int argc, char *argv[])
        char *buf;
        int err;
        int fd;
+       int i;
 
        cs_parse_args(argc, argv);
 
 
        cs_write_cmsg(fd, &msg, cbuf, sizeof(cbuf));
 
-       err = sendmsg(fd, &msg, 0);
-       if (err < 0) {
-               if (!opt.silent_send)
-                       fprintf(stderr, "send failed: %s\n", strerror(errno));
-               err = ERN_SEND;
-               goto err_out;
-       } else if (err != (int)opt.size) {
-               fprintf(stderr, "short send\n");
-               err = ERN_SEND_SHORT;
-               goto err_out;
-       } else {
-               err = ERN_SUCCESS;
+       for (i = 0; i < opt.num_pkt; i++) {
+               err = sendmsg(fd, &msg, 0);
+               if (err < 0) {
+                       if (!opt.silent_send)
+                               fprintf(stderr, "send failed: %s\n", strerror(errno));
+                       err = ERN_SEND;
+                       goto err_out;
+               } else if (err != (int)opt.size) {
+                       fprintf(stderr, "short send\n");
+                       err = ERN_SEND_SHORT;
+                       goto err_out;
+               }
        }
+       err = ERN_SUCCESS;
 
-       /* Make sure all timestamps have time to loop back */
-       usleep(opt.txtime.delay);
+       if (opt.ts.ena) {
+               /* Make sure all timestamps have time to loop back */
+               usleep(opt.txtime.delay);
 
-       cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf));
+               cs_read_cmsg(fd, &msg, cbuf, sizeof(cbuf));
+       }
 
 err_out:
        close(fd);
 
--- /dev/null
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify that FQ has a packet limit per band:
+#
+# 1. set the limit to 10 per band
+# 2. send 20 pkts on band A: verify that 10 are queued, 10 dropped
+# 3. send 20 pkts on band A: verify that  0 are queued, 20 dropped
+# 4. send 20 pkts on band B: verify that 10 are queued, 10 dropped
+#
+# Send packets with a 100ms delay to ensure that previously sent
+# packets are still queued when later ones are sent.
+# Use SO_TXTIME for this.
+
+die() {
+       echo "$1"
+       exit 1
+}
+
+# run inside private netns
+if [[ $# -eq 0 ]]; then
+       ./in_netns.sh "$0" __subprocess
+       exit
+fi
+
+ip link add type dummy
+ip link set dev dummy0 up
+ip -6 addr add fdaa::1/128 dev dummy0
+ip -6 route add fdaa::/64 dev dummy0
+tc qdisc replace dev dummy0 root handle 1: fq quantum 1514 initial_quantum 1514 limit 10
+
+./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000
+OUT1="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
+
+./cmsg_sender -6 -p u -d 100000 -n 20 fdaa::2 8000
+OUT2="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
+
+./cmsg_sender -6 -p u -d 100000 -n 20 -P 7 fdaa::2 8000
+OUT3="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
+
+# Initial stats will report zero sent, as all packets are still
+# queued in FQ. Sleep for the delay period (100ms) and see that
+# twenty are now sent.
+sleep 0.1
+OUT4="$(tc -s qdisc show dev dummy0 | grep '^\ Sent')"
+
+# Log the output after the test
+echo "${OUT1}"
+echo "${OUT2}"
+echo "${OUT3}"
+echo "${OUT4}"
+
+# Test the output for expected values
+echo "${OUT1}" | grep -q '0\ pkt\ (dropped\ 10'  || die "unexpected drop count at 1"
+echo "${OUT2}" | grep -q '0\ pkt\ (dropped\ 30'  || die "unexpected drop count at 2"
+echo "${OUT3}" | grep -q '0\ pkt\ (dropped\ 40'  || die "unexpected drop count at 3"
+echo "${OUT4}" | grep -q '20\ pkt\ (dropped\ 40' || die "unexpected accept count at 4"