History

Merge branch 'net-ethtool-support-including-flow-label-in-the-flow-hash-for-rss'

Jakub Kicinski says: ==================== net: ethtool: support including Flow Label in the flow hash for RSS Add support for using IPv6 Flow Label in Rx hash computation and therefore RSS queue selection. v3: https://lore.kernel.org/20250724015101.186608-1-kuba@kernel.org v2: https://lore.kernel.org/20250722014915.3365370-1-kuba@kernel.org RFC: https://lore.kernel.org/20250609173442.1745856-1-kuba@kernel.org ====================

Paolo Abeni committed 1 year ago

Commit 875c5412 parents 40e8197 26dbe0311 files · +233 −18Browse files

Unified · Split

11 files
  1. Documentation/netlink/specs/ethtool.yaml +3 −0
  2. drivers/net/ethernet/broadcom/bnxt/bnxt.c +2 −0
  3. drivers/net/ethernet/broadcom/bnxt/bnxt.h +1 −0
  4. drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +16 −4
  5. drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +1 −1
  6. drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +2 −0
  7. include/uapi/linux/ethtool.h +1 −0
  8. net/ethtool/ioctl.c +25 −0
  9. net/ethtool/rss.c +14 −13
  10. tools/testing/selftests/drivers/net/hw/Makefile +1 −0
  11. tools/testing/selftests/drivers/net/hw/rss_flow_label.py +167 −0
Documentation/netlink/specs/ethtool.yaml+3−0
@@ -204,6 +204,9 @@ definitions: · 203 unmodified lines
204204 doc: dst port in case of TCP/UDP/SCTP
205205 -
206206 name: gtp-teid
207+ -
208+ name: ip6-fl
209+ doc: IPv6 Flow Label
207210 -
208211 name: discard
209212 value: 31
drivers/net/ethernet/broadcom/bnxt/bnxt.c+2−0
@@ -6957,6 +6957,8 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp) · 6956 unmodified lines
69576957 bp->rss_cap |= BNXT_RSS_CAP_ESP_V4_RSS_CAP;
69586958 if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP)
69596959 bp->rss_cap |= BNXT_RSS_CAP_ESP_V6_RSS_CAP;
6960+ if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPV6_FLOW_LABEL_CAP)
6961+ bp->rss_cap |= BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP;
69606962 if (flags & VNIC_QCAPS_RESP_FLAGS_RE_FLUSH_CAP)
69616963 bp->fw_cap |= BNXT_FW_CAP_VNIC_RE_FLUSH;
69626964 }
drivers/net/ethernet/broadcom/bnxt/bnxt.h+1−0
@@ -2407,6 +2407,7 @@ struct bnxt { · 2406 unmodified lines
24072407 #define BNXT_RSS_CAP_ESP_V4_RSS_CAP BIT(6)
24082408 #define BNXT_RSS_CAP_ESP_V6_RSS_CAP BIT(7)
24092409 #define BNXT_RSS_CAP_MULTI_RSS_CTX BIT(8)
2410+#define BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP BIT(9)
24102411
24112412 u8 rss_hash_key[HW_HASH_KEY_SIZE];
24122413 u8 rss_hash_key_valid:1;
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c+16−4
@@ -1584,6 +1584,8 @@ static u64 get_ethtool_ipv6_rss(struct bnxt *bp) · 1583 unmodified lines
15841584 {
15851585 if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6)
15861586 return RXH_IP_SRC | RXH_IP_DST;
1587+ if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL)
1588+ return RXH_IP_SRC | RXH_IP_DST | RXH_IP6_FL;
15871589 return 0;
15881590 }
15891591
@@ -1662,13 +1664,18 @@ static int bnxt_set_rxfh_fields(struct net_device *dev, · 72 unmodified lines
16621664
16631665 if (cmd->data == RXH_4TUPLE)
16641666 tuple = 4;
1665− else if (cmd->data == RXH_2TUPLE)
1667+ else if (cmd->data == RXH_2TUPLE ||
1668+ cmd->data == (RXH_2TUPLE | RXH_IP6_FL))
16661669 tuple = 2;
16671670 else if (!cmd->data)
16681671 tuple = 0;
16691672 else
16701673 return -EINVAL;
16711674
1675+ if (cmd->data & RXH_IP6_FL &&
1676+ !(bp->rss_cap & BNXT_RSS_CAP_IPV6_FLOW_LABEL_RSS_CAP))
1677+ return -EINVAL;
1678+
16721679 if (cmd->flow_type == TCP_V4_FLOW) {
16731680 rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4;
16741681 if (tuple == 4)
@@ -1732,10 +1739,15 @@ static int bnxt_set_rxfh_fields(struct net_device *dev, · 57 unmodified lines
17321739 case AH_V6_FLOW:
17331740 case ESP_V6_FLOW:
17341741 case IPV6_FLOW:
1735− if (tuple == 2)
1742+ rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6 |
1743+ VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL);
1744+ if (!tuple)
1745+ break;
1746+ if (cmd->data & RXH_IP6_FL)
1747+ rss_hash_cfg |=
1748+ VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6_FLOW_LABEL;
1749+ else if (tuple == 2)
17361750 rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
1737− else if (!tuple)
1738− rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6;
17391751 break;
17401752 }
17411753
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c+1−1
@@ -1310,7 +1310,7 @@ fbnic_get_rss_hash_opts(struct net_device *netdev, · 1309 unmodified lines
13101310 #define FBNIC_L2_HASH_OPTIONS \
13111311 (RXH_L2DA | RXH_DISCARD)
13121312 #define FBNIC_L3_HASH_OPTIONS \
1313− (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST)
1313+ (FBNIC_L2_HASH_OPTIONS | RXH_IP_SRC | RXH_IP_DST | RXH_IP6_FL)
13141314 #define FBNIC_L4_HASH_OPTIONS \
13151315 (FBNIC_L3_HASH_OPTIONS | RXH_L4_B_0_1 | RXH_L4_B_2_3)
13161316
drivers/net/ethernet/meta/fbnic/fbnic_rpc.c+2−0
@@ -71,6 +71,8 @@ u16 fbnic_flow_hash_2_rss_en_mask(struct fbnic_net *fbn, int flow_type) · 70 unmodified lines
7171 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP_DST, IP_DST, flow_hash);
7272 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_0_1, L4_SRC, flow_hash);
7373 rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(L4_B_2_3, L4_DST, flow_hash);
74+ rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP6_FL, OV6_FL_LBL, flow_hash);
75+ rss_en_mask |= FBNIC_FH_2_RSSEM_BIT(IP6_FL, IV6_FL_LBL, flow_hash);
7476
7577 return rss_en_mask;
7678 }
include/uapi/linux/ethtool.h+1−0
@@ -2380,6 +2380,7 @@ enum { · 2379 unmodified lines
23802380 #define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */
23812381 #define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */
23822382 #define RXH_GTP_TEID (1 << 8) /* teid in case of GTP */
2383+#define RXH_IP6_FL (1 << 9) /* IPv6 flow label */
23832384 #define RXH_DISCARD (1 << 31)
23842385
23852386 #define RX_CLS_FLOW_DISC 0xffffffffffffffffULL
net/ethtool/ioctl.c+25−0
@@ -1014,6 +1014,28 @@ static bool flow_type_hashable(u32 flow_type) · 1013 unmodified lines
10141014 return false;
10151015 }
10161016
1017+static bool flow_type_v6(u32 flow_type)
1018+{
1019+ switch (flow_type) {
1020+ case TCP_V6_FLOW:
1021+ case UDP_V6_FLOW:
1022+ case SCTP_V6_FLOW:
1023+ case AH_ESP_V6_FLOW:
1024+ case AH_V6_FLOW:
1025+ case ESP_V6_FLOW:
1026+ case IPV6_FLOW:
1027+ case GTPU_V6_FLOW:
1028+ case GTPC_V6_FLOW:
1029+ case GTPC_TEID_V6_FLOW:
1030+ case GTPU_EH_V6_FLOW:
1031+ case GTPU_UL_V6_FLOW:
1032+ case GTPU_DL_V6_FLOW:
1033+ return true;
1034+ }
1035+
1036+ return false;
1037+}
1038+
10171039 /* When adding a new type, update the assert and, if it's hashable, add it to
10181040 * the flow_type_hashable switch case.
10191041 */
@@ -1077,6 +1099,9 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr) · 57 unmodified lines
10771099 if (rc)
10781100 return rc;
10791101
1102+ if (info.data & RXH_IP6_FL && !flow_type_v6(info.flow_type))
1103+ return -EINVAL;
1104+
10801105 if (info.flow_type & FLOW_RSS && info.rss_context &&
10811106 !ops->rxfh_per_ctx_fields)
10821107 return -EINVAL;
net/ethtool/rss.c+14−13
@@ -536,35 +536,36 @@ void ethtool_rss_notify(struct net_device *dev, u32 type, u32 rss_context) · 535 unmodified lines
536536 #define RFH_MASK (RXH_L2DA | RXH_VLAN | RXH_IP_SRC | RXH_IP_DST | \
537537 RXH_L3_PROTO | RXH_L4_B_0_1 | RXH_L4_B_2_3 | \
538538 RXH_GTP_TEID | RXH_DISCARD)
539+#define RFH_MASKv6 (RFH_MASK | RXH_IP6_FL)
539540
540541 static const struct nla_policy ethnl_rss_flows_policy[] = {
541542 [ETHTOOL_A_FLOW_ETHER] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
542543 [ETHTOOL_A_FLOW_IP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
543− [ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
544+ [ETHTOOL_A_FLOW_IP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
544545 [ETHTOOL_A_FLOW_TCP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
545546 [ETHTOOL_A_FLOW_UDP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
546547 [ETHTOOL_A_FLOW_SCTP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
547548 [ETHTOOL_A_FLOW_AH_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
548− [ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
549− [ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
550− [ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
551− [ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
549+ [ETHTOOL_A_FLOW_TCP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
550+ [ETHTOOL_A_FLOW_UDP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
551+ [ETHTOOL_A_FLOW_SCTP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
552+ [ETHTOOL_A_FLOW_AH_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
552553 [ETHTOOL_A_FLOW_AH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
553554 [ETHTOOL_A_FLOW_ESP4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
554− [ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
555− [ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
555+ [ETHTOOL_A_FLOW_AH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
556+ [ETHTOOL_A_FLOW_ESP6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
556557 [ETHTOOL_A_FLOW_GTPU4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
557− [ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
558+ [ETHTOOL_A_FLOW_GTPU6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
558559 [ETHTOOL_A_FLOW_GTPC4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
559− [ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
560+ [ETHTOOL_A_FLOW_GTPC6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
560561 [ETHTOOL_A_FLOW_GTPC_TEID4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
561− [ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
562+ [ETHTOOL_A_FLOW_GTPC_TEID6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
562563 [ETHTOOL_A_FLOW_GTPU_EH4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
563− [ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
564+ [ETHTOOL_A_FLOW_GTPU_EH6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
564565 [ETHTOOL_A_FLOW_GTPU_UL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
565− [ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
566+ [ETHTOOL_A_FLOW_GTPU_UL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
566567 [ETHTOOL_A_FLOW_GTPU_DL4] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
567− [ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASK),
568+ [ETHTOOL_A_FLOW_GTPU_DL6] = NLA_POLICY_MASK(NLA_UINT, RFH_MASKv6),
568569 };
569570
570571 const struct nla_policy ethnl_rss_set_policy[ETHTOOL_A_RSS_FLOW_HASH + 1] = {
tools/testing/selftests/drivers/net/hw/Makefile+1−0
@@ -18,6 +18,7 @@ TEST_PROGS = \ · 17 unmodified lines
1818 pp_alloc_fail.py \
1919 rss_api.py \
2020 rss_ctx.py \
21+ rss_flow_label.py \
2122 rss_input_xfrm.py \
2223 tso.py \
2324 xsk_reconfig.py \
tools/testing/selftests/drivers/net/hw/rss_flow_label.py+167−0
@@ -0,0 +1,167 @@
1+#!/usr/bin/env python3
2+# SPDX-License-Identifier: GPL-2.0
3+
4+"""
5+Tests for RSS hashing on IPv6 Flow Label.
6+"""
7+
8+import glob
9+import os
10+import socket
11+from lib.py import CmdExitFailure
12+from lib.py import ksft_run, ksft_exit, ksft_eq, ksft_ge, ksft_in, \
13+ ksft_not_in, ksft_raises, KsftSkipEx
14+from lib.py import bkg, cmd, defer, fd_read_timeout, rand_port
15+from lib.py import NetDrvEpEnv
16+
17+
18+def _check_system(cfg):
19+ if not hasattr(socket, "SO_INCOMING_CPU"):
20+ raise KsftSkipEx("socket.SO_INCOMING_CPU was added in Python 3.11")
21+
22+ qcnt = len(glob.glob(f"/sys/class/net/{cfg.ifname}/queues/rx-*"))
23+ if qcnt < 2:
24+ raise KsftSkipEx(f"Local has only {qcnt} queues")
25+
26+ for f in [f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_flow_cnt",
27+ f"/sys/class/net/{cfg.ifname}/queues/rx-0/rps_cpus"]:
28+ try:
29+ with open(f, 'r') as fp:
30+ setting = fp.read().strip()
31+ # CPU mask will be zeros and commas
32+ if setting.replace("0", "").replace(",", ""):
33+ raise KsftSkipEx(f"RPS/RFS is configured: {f}: {setting}")
34+ except FileNotFoundError:
35+ pass
36+
37+ # 1 is the default, if someone changed it we probably shouldn"t mess with it
38+ af = cmd("cat /proc/sys/net/ipv6/auto_flowlabels", host=cfg.remote).stdout
39+ if af.strip() != "1":
40+ raise KsftSkipEx("Remote does not have auto_flowlabels enabled")
41+
42+
43+def _ethtool_get_cfg(cfg, fl_type):
44+ descr = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout
45+
46+ converter = {
47+ "IP SA": "s",
48+ "IP DA": "d",
49+ "L3 proto": "t",
50+ "L4 bytes 0 & 1 [TCP/UDP src port]": "f",
51+ "L4 bytes 2 & 3 [TCP/UDP dst port]": "n",
52+ "IPv6 Flow Label": "l",
53+ }
54+
55+ ret = ""
56+ for line in descr.split("\n")[1:-2]:
57+ # if this raises we probably need to add more keys to converter above
58+ ret += converter[line]
59+ return ret
60+
61+
62+def _traffic(cfg, one_sock, one_cpu):
63+ local_port = rand_port(socket.SOCK_DGRAM)
64+ remote_port = rand_port(socket.SOCK_DGRAM)
65+
66+ sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
67+ sock.bind(("", local_port))
68+ sock.connect((cfg.remote_addr_v["6"], 0))
69+ if one_sock:
70+ send = f"exec 5<>/dev/udp/{cfg.addr_v['6']}/{local_port}; " \
71+ "for i in `seq 20`; do echo a >&5; sleep 0.02; done; exec 5>&-"
72+ else:
73+ send = "for i in `seq 20`; do echo a | socat -t0.02 - UDP6:" \
74+ f"[{cfg.addr_v['6']}]:{local_port},sourceport={remote_port}; done"
75+
76+ cpus = set()
77+ with bkg(send, shell=True, host=cfg.remote, exit_wait=True):
78+ for _ in range(20):
79+ fd_read_timeout(sock.fileno(), 1)
80+ cpu = sock.getsockopt(socket.SOL_SOCKET, socket.SO_INCOMING_CPU)
81+ cpus.add(cpu)
82+
83+ if one_cpu:
84+ ksft_eq(len(cpus), 1,
85+ f"{one_sock=} - expected one CPU, got traffic on: {cpus=}")
86+ else:
87+ ksft_ge(len(cpus), 2,
88+ f"{one_sock=} - expected many CPUs, got traffic on: {cpus=}")
89+
90+
91+def test_rss_flow_label(cfg):
92+ """
93+ Test hashing on IPv6 flow label. Send traffic over a single socket
94+ and over multiple sockets. Depend on the remote having auto-label
95+ enabled so that it randomizes the label per socket.
96+ """
97+
98+ cfg.require_ipver("6")
99+ cfg.require_cmd("socat", remote=True)
100+ _check_system(cfg)
101+
102+ # Enable flow label hashing for UDP6
103+ initial = _ethtool_get_cfg(cfg, "udp6")
104+ no_lbl = initial.replace("l", "")
105+ if "l" not in initial:
106+ try:
107+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 l{no_lbl}")
108+ except CmdExitFailure as exc:
109+ raise KsftSkipEx("Device doesn't support Flow Label for UDP6") from exc
110+
111+ defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}")
112+
113+ _traffic(cfg, one_sock=True, one_cpu=True)
114+ _traffic(cfg, one_sock=False, one_cpu=False)
115+
116+ # Disable it, we should see no hashing (reset was already defer()ed)
117+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {no_lbl}")
118+
119+ _traffic(cfg, one_sock=False, one_cpu=True)
120+
121+
122+def _check_v4_flow_types(cfg):
123+ for fl_type in ["tcp4", "udp4", "ah4", "esp4", "sctp4"]:
124+ try:
125+ cur = cmd(f"ethtool -n {cfg.ifname} rx-flow-hash {fl_type}").stdout
126+ ksft_not_in("Flow Label", cur,
127+ comment=f"{fl_type=} has Flow Label:" + cur)
128+ except CmdExitFailure:
129+ # Probably does not support this flow type
130+ pass
131+
132+
133+def test_rss_flow_label_6only(cfg):
134+ """
135+ Test interactions with IPv4 flow types. It should not be possible to set
136+ IPv6 Flow Label hashing for an IPv4 flow type. The Flow Label should also
137+ not appear in the IPv4 "current config".
138+ """
139+
140+ with ksft_raises(CmdExitFailure) as cm:
141+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash tcp4 sdfnl")
142+ ksft_in("Invalid argument", cm.exception.cmd.stderr)
143+
144+ _check_v4_flow_types(cfg)
145+
146+ # Try to enable Flow Labels and check again, in case it leaks thru
147+ initial = _ethtool_get_cfg(cfg, "udp6")
148+ changed = initial.replace("l", "") if "l" in initial else initial + "l"
149+
150+ cmd(f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {changed}")
151+ restore = defer(cmd, f"ethtool -N {cfg.ifname} rx-flow-hash udp6 {initial}")
152+
153+ _check_v4_flow_types(cfg)
154+ restore.exec()
155+ _check_v4_flow_types(cfg)
156+
157+
158+def main() -> None:
159+ with NetDrvEpEnv(__file__, nsim_test=False) as cfg:
160+ ksft_run([test_rss_flow_label,
161+ test_rss_flow_label_6only],
162+ args=(cfg, ))
163+ ksft_exit()
164+
165+
166+if __name__ == "__main__":
167+ main()

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t