Merge tag 'net-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Sep 2023 01:33:07 +0000 (18:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 8 Sep 2023 01:33:07 +0000 (18:33 -0700)
Pull networking updates from Jakub Kicinski:
 "Including fixes from netfilter and bpf.

  Current release - regressions:

   - eth: stmmac: fix failure to probe without MAC interface specified

  Current release - new code bugs:

   - docs: netlink: fix missing classic_netlink doc reference

  Previous releases - regressions:

   - deal with integer overflows in kmalloc_reserve()

   - use sk_forward_alloc_get() in sk_get_meminfo()

   - bpf_sk_storage: fix the missing uncharge in sk_omem_alloc

   - fib: avoid warn splat in flow dissector after packet mangling

   - skb_segment: call zero copy functions before using skbuff frags

   - eth: sfc: check for zero length in EF10 RX prefix

  Previous releases - always broken:

   - af_unix: fix msg_controllen test in scm_pidfd_recv() for
     MSG_CMSG_COMPAT

   - xsk: fix xsk_build_skb() dereferencing possible ERR_PTR()

   - netfilter:
      - nft_exthdr: fix non-linear header modification
      - xt_u32, xt_sctp: validate user space input
      - nftables: exthdr: fix 4-byte stack OOB write
      - nfnetlink_osf: avoid OOB read
      - one more fix for the garbage collection work from last release

   - igmp: limit igmpv3_newpack() packet size to IP_MAX_MTU

   - bpf, sockmap: fix preempt_rt splat when using raw_spin_lock_t

   - handshake: fix null-deref in handshake_nl_done_doit()

   - ip: ignore dst hint for multipath routes to ensure packets are
     hashed across the nexthops

   - phy: micrel:
      - correct bit assignments for cable test errata
      - disable EEE according to the KSZ9477 errata

  Misc:

   - docs/bpf: document compile-once-run-everywhere (CO-RE) relocations

   - Revert "net: macsec: preserve ingress frame ordering", it appears
     to have been developed against an older kernel, problem doesn't
     exist upstream"

* tag 'net-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (95 commits)
  net: enetc: distinguish error from valid pointers in enetc_fixup_clear_rss_rfs()
  Revert "net: team: do not use dynamic lockdep key"
  net: hns3: remove GSO partial feature bit
  net: hns3: fix the port information display when sfp is absent
  net: hns3: fix invalid mutex between tc qdisc and dcb ets command issue
  net: hns3: fix debugfs concurrency issue between kfree buffer and read
  net: hns3: fix byte order conversion issue in hclge_dbg_fd_tcam_read()
  net: hns3: Support query tx timeout threshold by debugfs
  net: hns3: fix tx timeout issue
  net: phy: Provide Module 4 KSZ9477 errata (DS80000754C)
  netfilter: nf_tables: Unbreak audit log reset
  netfilter: ipset: add the missing IP_SET_HASH_WITH_NET0 macro for ip_set_hash_netportnet.c
  netfilter: nft_set_rbtree: skip sync GC for new elements in this transaction
  netfilter: nf_tables: uapi: Describe NFTA_RULE_CHAIN_ID
  netfilter: nfnetlink_osf: avoid OOB read
  netfilter: nftables: exthdr: fix 4-byte stack OOB write
  selftests/bpf: Check bpf_sk_storage has uncharged sk_omem_alloc
  bpf: bpf_sk_storage: Fix the missing uncharge in sk_omem_alloc
  bpf: bpf_sk_storage: Fix invalid wait context lockdep report
  s390/bpf: Pass through tail call counter in trampolines
  ...

118 files changed:
Documentation/bpf/btf.rst
Documentation/bpf/index.rst
Documentation/bpf/linux-notes.rst [moved from Documentation/bpf/standardization/linux-notes.rst with 100% similarity]
Documentation/bpf/llvm_reloc.rst
Documentation/bpf/standardization/abi.rst [new file with mode: 0644]
Documentation/bpf/standardization/index.rst
Documentation/bpf/standardization/instruction-set.rst
Documentation/process/maintainer-netdev.rst
Documentation/userspace-api/netlink/intro.rst
arch/s390/net/bpf_jit_comp.c
drivers/net/dsa/microchip/ksz_common.c
drivers/net/dsa/sja1105/sja1105.h
drivers/net/dsa/sja1105/sja1105_main.c
drivers/net/dsa/sja1105/sja1105_spi.c
drivers/net/ethernet/freescale/enetc/enetc_pf.c
drivers/net/ethernet/google/gve/gve_rx_dqo.c
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3_enet.c
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_debugfs.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
drivers/net/ethernet/intel/igb/igb.h
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/igbvf.h
drivers/net/ethernet/intel/igc/igc.h
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/ct.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/mirred.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/pedit.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/redirect_ingress.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/vlan.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/vlan_mangle.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c
drivers/net/ethernet/sfc/rx.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/macsec.c
drivers/net/phy/micrel.c
drivers/net/veth.c
drivers/nfc/nxp-nci/i2c.c
include/linux/audit.h
include/linux/bpf.h
include/linux/ipv6.h
include/linux/micrel_phy.h
include/linux/phylink.h
include/net/ip.h
include/net/ip6_fib.h
include/net/ip_fib.h
include/net/ip_tunnels.h
include/net/scm.h
include/net/sock.h
include/uapi/linux/netfilter/nf_tables.h
kernel/auditsc.c
kernel/bpf/bpf_local_storage.c
kernel/bpf/syscall.c
kernel/bpf/trampoline.c
net/bpf/test_run.c
net/can/j1939/socket.c
net/core/flow_dissector.c
net/core/skbuff.c
net/core/skmsg.c
net/core/sock.c
net/core/sock_map.c
net/handshake/netlink.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/ip_forward.c
net/ipv4/ip_input.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ipmr.c
net/ipv4/route.c
net/ipv4/tcp.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/ip6_input.c
net/ipv6/ip6_output.c
net/ipv6/ip6mr.c
net/ipv6/ping.c
net/ipv6/raw.c
net/ipv6/route.c
net/ipv6/udp.c
net/kcm/kcmsock.c
net/mptcp/protocol.c
net/netfilter/ipset/ip_set_hash_netportnet.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_osf.c
net/netfilter/nft_exthdr.c
net/netfilter/nft_set_rbtree.c
net/netfilter/xt_sctp.c
net/netfilter/xt_u32.c
net/sched/sch_fq_pie.c
net/sched/sch_plug.c
net/sched/sch_qfq.c
net/sctp/proc.c
net/sctp/socket.c
net/socket.c
net/unix/af_unix.c
net/unix/scm.c
net/xdp/xsk.c
net/xdp/xsk_diag.c
scripts/bpf_doc.py
tools/bpf/bpftool/link.c
tools/testing/selftests/bpf/Makefile
tools/testing/selftests/bpf/prog_tests/bpf_obj_pinning.c
tools/testing/selftests/bpf/prog_tests/d_path.c
tools/testing/selftests/bpf/prog_tests/sk_storage_omem_uncharge.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/sockmap_helpers.h
tools/testing/selftests/bpf/prog_tests/sockmap_listen.c
tools/testing/selftests/bpf/progs/bpf_tracing_net.h
tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c [new file with mode: 0644]
tools/testing/selftests/net/fib_tests.sh

index f32db1f44ae90fc2f2004e1e84145430f5089e96..e43c2fdafcd785f4f259a9b3d79abc9467051ddc 100644 (file)
@@ -726,8 +726,8 @@ same as the one describe in :ref:`BTF_Type_String`.
 4.2 .BTF.ext section
 --------------------
 
-The .BTF.ext section encodes func_info and line_info which needs loader
-manipulation before loading into the kernel.
+The .BTF.ext section encodes func_info, line_info and CO-RE relocations
+which needs loader manipulation before loading into the kernel.
 
 The specification for .BTF.ext section is defined at ``tools/lib/bpf/btf.h``
 and ``tools/lib/bpf/btf.c``.
@@ -745,15 +745,20 @@ The current header of .BTF.ext section::
         __u32   func_info_len;
         __u32   line_info_off;
         __u32   line_info_len;
+
+        /* optional part of .BTF.ext header */
+        __u32   core_relo_off;
+        __u32   core_relo_len;
     };
 
 It is very similar to .BTF section. Instead of type/string section, it
-contains func_info and line_info section. See :ref:`BPF_Prog_Load` for details
-about func_info and line_info record format.
+contains func_info, line_info and core_relo sub-sections.
+See :ref:`BPF_Prog_Load` for details about func_info and line_info
+record format.
 
 The func_info is organized as below.::
 
-     func_info_rec_size
+     func_info_rec_size              /* __u32 value */
      btf_ext_info_sec for section #1 /* func_info for section #1 */
      btf_ext_info_sec for section #2 /* func_info for section #2 */
      ...
@@ -773,7 +778,7 @@ Here, num_info must be greater than 0.
 
 The line_info is organized as below.::
 
-     line_info_rec_size
+     line_info_rec_size              /* __u32 value */
      btf_ext_info_sec for section #1 /* line_info for section #1 */
      btf_ext_info_sec for section #2 /* line_info for section #2 */
      ...
@@ -787,6 +792,20 @@ kernel API, the ``insn_off`` is the instruction offset in the unit of ``struct
 bpf_insn``. For ELF API, the ``insn_off`` is the byte offset from the
 beginning of section (``btf_ext_info_sec->sec_name_off``).
 
+The core_relo is organized as below.::
+
+     core_relo_rec_size              /* __u32 value */
+     btf_ext_info_sec for section #1 /* core_relo for section #1 */
+     btf_ext_info_sec for section #2 /* core_relo for section #2 */
+
+``core_relo_rec_size`` specifies the size of ``bpf_core_relo``
+structure when .BTF.ext is generated. All ``bpf_core_relo`` structures
+within a single ``btf_ext_info_sec`` describe relocations applied to
+section named by ``btf_ext_info_sec->sec_name_off``.
+
+See :ref:`Documentation/bpf/llvm_reloc.rst <btf-co-re-relocations>`
+for more information on CO-RE relocations.
+
 4.2 .BTF_ids section
 --------------------
 
index 1ff177b89d66bc19c86b4d8c0faa0c4278d27b91..aeaeb35e6d4a70265e1552b272ca5b2707fabdfc 100644 (file)
@@ -29,6 +29,7 @@ that goes into great technical depth about the BPF Architecture.
    bpf_licensing
    test_debug
    clang-notes
+   linux-notes
    other
    redirect
 
index 450e6403fe3dec0edf983b582b426a420c09075e..44188e219d32d5efe8a79c08bcc0b2b6f5ef00d6 100644 (file)
@@ -240,3 +240,307 @@ The .BTF/.BTF.ext sections has R_BPF_64_NODYLD32 relocations::
       Offset             Info             Type               Symbol's Value  Symbol's Name
   000000000000002c  0000000200000004 R_BPF_64_NODYLD32      0000000000000000 .text
   0000000000000040  0000000200000004 R_BPF_64_NODYLD32      0000000000000000 .text
+
+.. _btf-co-re-relocations:
+
+=================
+CO-RE Relocations
+=================
+
+From object file point of view CO-RE mechanism is implemented as a set
+of CO-RE specific relocation records. These relocation records are not
+related to ELF relocations and are encoded in .BTF.ext section.
+See :ref:`Documentation/bpf/btf.rst <BTF_Ext_Section>` for more
+information on .BTF.ext structure.
+
+CO-RE relocations are applied to BPF instructions to update immediate
+or offset fields of the instruction at load time with information
+relevant for target kernel.
+
+Field to patch is selected basing on the instruction class:
+
+* For BPF_ALU, BPF_ALU64, BPF_LD `immediate` field is patched;
+* For BPF_LDX, BPF_STX, BPF_ST `offset` field is patched;
+* BPF_JMP, BPF_JMP32 instructions **should not** be patched.
+
+Relocation kinds
+================
+
+There are several kinds of CO-RE relocations that could be split in
+three groups:
+
+* Field-based - patch instruction with field related information, e.g.
+  change offset field of the BPF_LDX instruction to reflect offset
+  of a specific structure field in the target kernel.
+
+* Type-based - patch instruction with type related information, e.g.
+  change immediate field of the BPF_ALU move instruction to 0 or 1 to
+  reflect if specific type is present in the target kernel.
+
+* Enum-based - patch instruction with enum related information, e.g.
+  change immediate field of the BPF_LD_IMM64 instruction to reflect
+  value of a specific enum literal in the target kernel.
+
+The complete list of relocation kinds is represented by the following enum:
+
+.. code-block:: c
+
+ enum bpf_core_relo_kind {
+       BPF_CORE_FIELD_BYTE_OFFSET = 0,  /* field byte offset */
+       BPF_CORE_FIELD_BYTE_SIZE   = 1,  /* field size in bytes */
+       BPF_CORE_FIELD_EXISTS      = 2,  /* field existence in target kernel */
+       BPF_CORE_FIELD_SIGNED      = 3,  /* field signedness (0 - unsigned, 1 - signed) */
+       BPF_CORE_FIELD_LSHIFT_U64  = 4,  /* bitfield-specific left bitshift */
+       BPF_CORE_FIELD_RSHIFT_U64  = 5,  /* bitfield-specific right bitshift */
+       BPF_CORE_TYPE_ID_LOCAL     = 6,  /* type ID in local BPF object */
+       BPF_CORE_TYPE_ID_TARGET    = 7,  /* type ID in target kernel */
+       BPF_CORE_TYPE_EXISTS       = 8,  /* type existence in target kernel */
+       BPF_CORE_TYPE_SIZE         = 9,  /* type size in bytes */
+       BPF_CORE_ENUMVAL_EXISTS    = 10, /* enum value existence in target kernel */
+       BPF_CORE_ENUMVAL_VALUE     = 11, /* enum value integer value */
+       BPF_CORE_TYPE_MATCHES      = 12, /* type match in target kernel */
+ };
+
+Notes:
+
+* ``BPF_CORE_FIELD_LSHIFT_U64`` and ``BPF_CORE_FIELD_RSHIFT_U64`` are
+  supposed to be used to read bitfield values using the following
+  algorithm:
+
+  .. code-block:: c
+
+     // To read bitfield ``f`` from ``struct s``
+     is_signed = relo(s->f, BPF_CORE_FIELD_SIGNED)
+     off = relo(s->f, BPF_CORE_FIELD_BYTE_OFFSET)
+     sz  = relo(s->f, BPF_CORE_FIELD_BYTE_SIZE)
+     l   = relo(s->f, BPF_CORE_FIELD_LSHIFT_U64)
+     r   = relo(s->f, BPF_CORE_FIELD_RSHIFT_U64)
+     // define ``v`` as signed or unsigned integer of size ``sz``
+     v = *({s|u}<sz> *)((void *)s + off)
+     v <<= l
+     v >>= r
+
+* The ``BPF_CORE_TYPE_MATCHES`` queries matching relation, defined as
+  follows:
+
+  * for integers: types match if size and signedness match;
+  * for arrays & pointers: target types are recursively matched;
+  * for structs & unions:
+
+    * local members need to exist in target with the same name;
+
+    * for each member we recursively check match unless it is already behind a
+      pointer, in which case we only check matching names and compatible kind;
+
+  * for enums:
+
+    * local variants have to have a match in target by symbolic name (but not
+      numeric value);
+
+    * size has to match (but enum may match enum64 and vice versa);
+
+  * for function pointers:
+
+    * number and position of arguments in local type has to match target;
+    * for each argument and the return value we recursively check match.
+
+CO-RE Relocation Record
+=======================
+
+Relocation record is encoded as the following structure:
+
+.. code-block:: c
+
+ struct bpf_core_relo {
+       __u32 insn_off;
+       __u32 type_id;
+       __u32 access_str_off;
+       enum bpf_core_relo_kind kind;
+ };
+
+* ``insn_off`` - instruction offset (in bytes) within a code section
+  associated with this relocation;
+
+* ``type_id`` - BTF type ID of the "root" (containing) entity of a
+  relocatable type or field;
+
+* ``access_str_off`` - offset into corresponding .BTF string section.
+  String interpretation depends on specific relocation kind:
+
+  * for field-based relocations, string encodes an accessed field using
+    a sequence of field and array indices, separated by colon (:). It's
+    conceptually very close to LLVM's `getelementptr <GEP_>`_ instruction's
+    arguments for identifying offset to a field. For example, consider the
+    following C code:
+
+    .. code-block:: c
+
+       struct sample {
+           int a;
+           int b;
+           struct { int c[10]; };
+       } __attribute__((preserve_access_index));
+       struct sample *s;
+
+    * Access to ``s[0].a`` would be encoded as ``0:0``:
+
+      * ``0``: first element of ``s`` (as if ``s`` is an array);
+      * ``0``: index of field ``a`` in ``struct sample``.
+
+    * Access to ``s->a`` would be encoded as ``0:0`` as well.
+    * Access to ``s->b`` would be encoded as ``0:1``:
+
+      * ``0``: first element of ``s``;
+      * ``1``: index of field ``b`` in ``struct sample``.
+
+    * Access to ``s[1].c[5]`` would be encoded as ``1:2:0:5``:
+
+      * ``1``: second element of ``s``;
+      * ``2``: index of anonymous structure field in ``struct sample``;
+      * ``0``: index of field ``c`` in anonymous structure;
+      * ``5``: access to array element #5.
+
+  * for type-based relocations, string is expected to be just "0";
+
+  * for enum value-based relocations, string contains an index of enum
+     value within its enum type;
+
+* ``kind`` - one of ``enum bpf_core_relo_kind``.
+
+.. _GEP: https://llvm.org/docs/LangRef.html#getelementptr-instruction
+
+.. _btf_co_re_relocation_examples:
+
+CO-RE Relocation Examples
+=========================
+
+For the following C code:
+
+.. code-block:: c
+
+ struct foo {
+   int a;
+   int b;
+   unsigned c:15;
+ } __attribute__((preserve_access_index));
+
+ enum bar { U, V };
+
+With the following BTF definitions:
+
+.. code-block::
+
+ ...
+ [2] STRUCT 'foo' size=8 vlen=2
+        'a' type_id=3 bits_offset=0
+        'b' type_id=3 bits_offset=32
+        'c' type_id=4 bits_offset=64 bitfield_size=15
+ [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
+ [4] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
+ ...
+ [16] ENUM 'bar' encoding=UNSIGNED size=4 vlen=2
+        'U' val=0
+        'V' val=1
+
+Field offset relocations are generated automatically when
+``__attribute__((preserve_access_index))`` is used, for example:
+
+.. code-block:: c
+
+  void alpha(struct foo *s, volatile unsigned long *g) {
+    *g = s->a;
+    s->a = 1;
+  }
+
+  00 <alpha>:
+    0:  r3 = *(s32 *)(r1 + 0x0)
+           00:  CO-RE <byte_off> [2] struct foo::a (0:0)
+    1:  *(u64 *)(r2 + 0x0) = r3
+    2:  *(u32 *)(r1 + 0x0) = 0x1
+           10:  CO-RE <byte_off> [2] struct foo::a (0:0)
+    3:  exit
+
+
+All relocation kinds could be requested via built-in functions.
+E.g. field-based relocations:
+
+.. code-block:: c
+
+  void bravo(struct foo *s, volatile unsigned long *g) {
+    *g = __builtin_preserve_field_info(s->b, 0 /* field byte offset */);
+    *g = __builtin_preserve_field_info(s->b, 1 /* field byte size */);
+    *g = __builtin_preserve_field_info(s->b, 2 /* field existence */);
+    *g = __builtin_preserve_field_info(s->b, 3 /* field signedness */);
+    *g = __builtin_preserve_field_info(s->c, 4 /* bitfield left shift */);
+    *g = __builtin_preserve_field_info(s->c, 5 /* bitfield right shift */);
+  }
+
+  20 <bravo>:
+     4:     r1 = 0x4
+            20:  CO-RE <byte_off> [2] struct foo::b (0:1)
+     5:     *(u64 *)(r2 + 0x0) = r1
+     6:     r1 = 0x4
+            30:  CO-RE <byte_sz> [2] struct foo::b (0:1)
+     7:     *(u64 *)(r2 + 0x0) = r1
+     8:     r1 = 0x1
+            40:  CO-RE <field_exists> [2] struct foo::b (0:1)
+     9:     *(u64 *)(r2 + 0x0) = r1
+    10:     r1 = 0x1
+            50:  CO-RE <signed> [2] struct foo::b (0:1)
+    11:     *(u64 *)(r2 + 0x0) = r1
+    12:     r1 = 0x31
+            60:  CO-RE <lshift_u64> [2] struct foo::c (0:2)
+    13:     *(u64 *)(r2 + 0x0) = r1
+    14:     r1 = 0x31
+            70:  CO-RE <rshift_u64> [2] struct foo::c (0:2)
+    15:     *(u64 *)(r2 + 0x0) = r1
+    16:     exit
+
+
+Type-based relocations:
+
+.. code-block:: c
+
+  void charlie(struct foo *s, volatile unsigned long *g) {
+    *g = __builtin_preserve_type_info(*s, 0 /* type existence */);
+    *g = __builtin_preserve_type_info(*s, 1 /* type size */);
+    *g = __builtin_preserve_type_info(*s, 2 /* type matches */);
+    *g = __builtin_btf_type_id(*s, 0 /* type id in this object file */);
+    *g = __builtin_btf_type_id(*s, 1 /* type id in target kernel */);
+  }
+
+  88 <charlie>:
+    17:     r1 = 0x1
+            88:  CO-RE <type_exists> [2] struct foo
+    18:     *(u64 *)(r2 + 0x0) = r1
+    19:     r1 = 0xc
+            98:  CO-RE <type_size> [2] struct foo
+    20:     *(u64 *)(r2 + 0x0) = r1
+    21:     r1 = 0x1
+            a8:  CO-RE <type_matches> [2] struct foo
+    22:     *(u64 *)(r2 + 0x0) = r1
+    23:     r1 = 0x2 ll
+            b8:  CO-RE <local_type_id> [2] struct foo
+    25:     *(u64 *)(r2 + 0x0) = r1
+    26:     r1 = 0x2 ll
+            d0:  CO-RE <target_type_id> [2] struct foo
+    28:     *(u64 *)(r2 + 0x0) = r1
+    29:     exit
+
+Enum-based relocations:
+
+.. code-block:: c
+
+  void delta(struct foo *s, volatile unsigned long *g) {
+    *g = __builtin_preserve_enum_value(*(enum bar *)U, 0 /* enum literal existence */);
+    *g = __builtin_preserve_enum_value(*(enum bar *)V, 1 /* enum literal value */);
+  }
+
+  f0 <delta>:
+    30:     r1 = 0x1 ll
+            f0:  CO-RE <enumval_exists> [16] enum bar::U = 0
+    32:     *(u64 *)(r2 + 0x0) = r1
+    33:     r1 = 0x1 ll
+            108:  CO-RE <enumval_value> [16] enum bar::V = 1
+    35:     *(u64 *)(r2 + 0x0) = r1
+    36:     exit
diff --git a/Documentation/bpf/standardization/abi.rst b/Documentation/bpf/standardization/abi.rst
new file mode 100644 (file)
index 0000000..0c2e10e
--- /dev/null
@@ -0,0 +1,25 @@
+.. contents::
+.. sectnum::
+
+===================================================
+BPF ABI Recommended Conventions and Guidelines v1.0
+===================================================
+
+This is version 1.0 of an informational document containing recommended
+conventions and guidelines for producing portable BPF program binaries.
+
+Registers and calling convention
+================================
+
+BPF has 10 general purpose registers and a read-only frame pointer register,
+all of which are 64-bits wide.
+
+The BPF calling convention is defined as:
+
+* R0: return value from function calls, and exit value for BPF programs
+* R1 - R5: arguments for function calls
+* R6 - R9: callee saved registers that function calls will preserve
+* R10: read-only frame pointer to access stack
+
+R0 - R5 are scratch registers and BPF programs needs to spill/fill them if
+necessary across calls.
index 09c6ba055fd70148932c0d7ae3201dc13af1e4e7..a50c3baf6345aaba72aeea25768a8713431e4bf7 100644 (file)
@@ -12,7 +12,7 @@ for the working group charter, documents, and more.
    :maxdepth: 1
 
    instruction-set
-   linux-notes
+   abi
 
 .. Links:
 .. _IETF BPF Working Group: https://datatracker.ietf.org/wg/bpf/about/
index 4f73e9dc8d9eedea974ead0f46485b572db7de79..c5d53a6e8c79f1a6c2d42b66b53d3b62796fff62 100644 (file)
@@ -1,11 +1,11 @@
 .. contents::
 .. sectnum::
 
-========================================
-eBPF Instruction Set Specification, v1.0
-========================================
+=======================================
+BPF Instruction Set Specification, v1.0
+=======================================
 
-This document specifies version 1.0 of the eBPF instruction set.
+This document specifies version 1.0 of the BPF instruction set.
 
 Documentation conventions
 =========================
@@ -97,26 +97,10 @@ Definitions
     A:          10000110
     B: 11111111 10000110
 
-Registers and calling convention
-================================
-
-eBPF has 10 general purpose registers and a read-only frame pointer register,
-all of which are 64-bits wide.
-
-The eBPF calling convention is defined as:
-
-* R0: return value from function calls, and exit value for eBPF programs
-* R1 - R5: arguments for function calls
-* R6 - R9: callee saved registers that function calls will preserve
-* R10: read-only frame pointer to access stack
-
-R0 - R5 are scratch registers and eBPF programs needs to spill/fill them if
-necessary across calls.
-
 Instruction encoding
 ====================
 
-eBPF has two instruction encodings:
+BPF has two instruction encodings:
 
 * the basic instruction encoding, which uses 64 bits to encode an instruction
 * the wide instruction encoding, which appends a second 64-bit immediate (i.e.,
@@ -260,7 +244,7 @@ BPF_END    0xd0   0        byte swap operations (see `Byte swap instructions`_ b
 =========  =====  =======  ==========================================================
 
 Underflow and overflow are allowed during arithmetic operations, meaning
-the 64-bit or 32-bit value will wrap. If eBPF program execution would
+the 64-bit or 32-bit value will wrap. If BPF program execution would
 result in division by zero, the destination register is instead set to zero.
 If execution would result in modulo by zero, for ``BPF_ALU64`` the value of
 the destination register is unchanged whereas for ``BPF_ALU`` the upper
@@ -373,7 +357,7 @@ BPF_JNE   0x5    any  PC += offset if dst != src
 BPF_JSGT  0x6    any  PC += offset if dst > src                    signed
 BPF_JSGE  0x7    any  PC += offset if dst >= src                   signed
 BPF_CALL  0x8    0x0  call helper function by address              see `Helper functions`_
-BPF_CALL  0x8    0x1  call PC += offset                            see `Program-local functions`_
+BPF_CALL  0x8    0x1  call PC += imm                               see `Program-local functions`_
 BPF_CALL  0x8    0x2  call helper function by BTF ID               see `Helper functions`_
 BPF_EXIT  0x9    0x0  return                                       BPF_JMP only
 BPF_JLT   0xa    any  PC += offset if dst < src                    unsigned
@@ -382,7 +366,7 @@ BPF_JSLT  0xc    any  PC += offset if dst < src                    signed
 BPF_JSLE  0xd    any  PC += offset if dst <= src                   signed
 ========  =====  ===  ===========================================  =========================================
 
-The eBPF program needs to store the return value into register R0 before doing a
+The BPF program needs to store the return value into register R0 before doing a
 ``BPF_EXIT``.
 
 Example:
@@ -424,8 +408,8 @@ Program-local functions
 ~~~~~~~~~~~~~~~~~~~~~~~
 Program-local functions are functions exposed by the same BPF program as the
 caller, and are referenced by offset from the call instruction, similar to
-``BPF_JA``.  A ``BPF_EXIT`` within the program-local function will return to
-the caller.
+``BPF_JA``.  The offset is encoded in the imm field of the call instruction.
+A ``BPF_EXIT`` within the program-local function will return to the caller.
 
 Load and store instructions
 ===========================
@@ -502,9 +486,9 @@ Atomic operations
 
 Atomic operations are operations that operate on memory and can not be
 interrupted or corrupted by other access to the same memory region
-by other eBPF programs or means outside of this specification.
+by other BPF programs or means outside of this specification.
 
-All atomic operations supported by eBPF are encoded as store operations
+All atomic operations supported by BPF are encoded as store operations
 that use the ``BPF_ATOMIC`` mode modifier as follows:
 
 * ``BPF_ATOMIC | BPF_W | BPF_STX`` for 32-bit operations
@@ -594,7 +578,7 @@ where
 Maps
 ~~~~
 
-Maps are shared memory regions accessible by eBPF programs on some platforms.
+Maps are shared memory regions accessible by BPF programs on some platforms.
 A map can have various semantics as defined in a separate document, and may or
 may not have a single contiguous memory region, but the 'map_val(map)' is
 currently only defined for maps that do have a single contiguous memory region.
@@ -616,6 +600,6 @@ identified by the given id.
 Legacy BPF Packet access instructions
 -------------------------------------
 
-eBPF previously introduced special instructions for access to packet data that were
+BPF previously introduced special instructions for access to packet data that were
 carried over from classic BPF. However, these instructions are
 deprecated and should no longer be used.
index c1c732e9748bd918e9c05406f07d0afc051578cd..09dcf6377c272023a6894d5c10dfc3368d6f44aa 100644 (file)
@@ -98,7 +98,7 @@ If you aren't subscribed to netdev and/or are simply unsure if
 repository link above for any new networking-related commits.  You may
 also check the following website for the current status:
 
-  https://patchwork.hopto.org/net-next.html
+  https://netdev.bots.linux.dev/net-next.html
 
 The ``net`` tree continues to collect fixes for the vX.Y content, and is
 fed back to Linus at regular (~weekly) intervals.  Meaning that the
@@ -120,7 +120,37 @@ queue for netdev:
   https://patchwork.kernel.org/project/netdevbpf/list/
 
 The "State" field will tell you exactly where things are at with your
-patch. Patches are indexed by the ``Message-ID`` header of the emails
+patch:
+
+================== =============================================================
+Patch state        Description
+================== =============================================================
+New, Under review  pending review, patch is in the maintainer’s queue for
+                   review; the two states are used interchangeably (depending on
+                   the exact co-maintainer handling patchwork at the time)
+Accepted           patch was applied to the appropriate networking tree, this is
+                   usually set automatically by the pw-bot
+Needs ACK          waiting for an ack from an area expert or testing
+Changes requested  patch has not passed the review, new revision is expected
+                   with appropriate code and commit message changes
+Rejected           patch has been rejected and new revision is not expected
+Not applicable     patch is expected to be applied outside of the networking
+                   subsystem
+Awaiting upstream  patch should be reviewed and handled by appropriate
+                   sub-maintainer, who will send it on to the networking trees;
+                   patches set to ``Awaiting upstream`` in netdev's patchwork
+                   will usually remain in this state, whether the sub-maintainer
+                   requested changes, accepted or rejected the patch
+Deferred           patch needs to be reposted later, usually due to dependency
+                   or because it was posted for a closed tree
+Superseded         new version of the patch was posted, usually set by the
+                   pw-bot
+RFC                not to be applied, usually not in maintainer’s review queue,
+                   pw-bot can automatically set patches to this state based
+                   on subject tags
+================== =============================================================
+
+Patches are indexed by the ``Message-ID`` header of the emails
 which carried them so if you have trouble finding your patch append
 the value of ``Message-ID`` to the URL above.
 
@@ -155,7 +185,7 @@ must match the MAINTAINERS entry) and a handful of senior reviewers.
 
 Bot records its activity here:
 
-  https://patchwork.hopto.org/pw-bot.html
+  https://netdev.bots.linux.dev/pw-bot.html
 
 Review timelines
 ~~~~~~~~~~~~~~~~
index af94e71761ec5b0a68880e6902bbdf2b79aac058..7b1d401210efb4ed5ba0ffa5e7c1e25f413926d0 100644 (file)
@@ -528,6 +528,8 @@ families may, however, require a larger buffer. 32kB buffer is recommended
 for most efficient handling of dumps (larger buffer fits more dumped
 objects and therefore fewer recvmsg() calls are needed).
 
+.. _classic_netlink:
+
 Classic Netlink
 ===============
 
index 5e9371fbf3d5f3c39f6e98126c0ba8c1d28eb777..de2fb12120d2ed85c330c19bf8d8f3c735e5ecec 100644 (file)
@@ -2088,6 +2088,7 @@ struct bpf_tramp_jit {
                                 */
        int r14_off;            /* Offset of saved %r14 */
        int run_ctx_off;        /* Offset of struct bpf_tramp_run_ctx */
+       int tccnt_off;          /* Offset of saved tailcall counter */
        int do_fexit;           /* do_fexit: label */
 };
 
@@ -2258,12 +2259,16 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
        tjit->r14_off = alloc_stack(tjit, sizeof(u64));
        tjit->run_ctx_off = alloc_stack(tjit,
                                        sizeof(struct bpf_tramp_run_ctx));
+       tjit->tccnt_off = alloc_stack(tjit, sizeof(u64));
        /* The caller has already reserved STACK_FRAME_OVERHEAD bytes. */
        tjit->stack_size -= STACK_FRAME_OVERHEAD;
        tjit->orig_stack_args_off = tjit->stack_size + STACK_FRAME_OVERHEAD;
 
        /* aghi %r15,-stack_size */
        EMIT4_IMM(0xa70b0000, REG_15, -tjit->stack_size);
+       /* mvc tccnt_off(4,%r15),stack_size+STK_OFF_TCCNT(%r15) */
+       _EMIT6(0xd203f000 | tjit->tccnt_off,
+              0xf000 | (tjit->stack_size + STK_OFF_TCCNT));
        /* stmg %r2,%rN,fwd_reg_args_off(%r15) */
        if (nr_reg_args)
                EMIT6_DISP_LH(0xeb000000, 0x0024, REG_2,
@@ -2400,6 +2405,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
                                       (nr_stack_args * sizeof(u64) - 1) << 16 |
                                       tjit->stack_args_off,
                               0xf000 | tjit->orig_stack_args_off);
+               /* mvc STK_OFF_TCCNT(4,%r15),tccnt_off(%r15) */
+               _EMIT6(0xd203f000 | STK_OFF_TCCNT, 0xf000 | tjit->tccnt_off);
                /* lgr %r1,%r8 */
                EMIT4(0xb9040000, REG_1, REG_8);
                /* %r1() */
@@ -2456,6 +2463,9 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
        if (flags & (BPF_TRAMP_F_CALL_ORIG | BPF_TRAMP_F_RET_FENTRY_RET))
                EMIT6_DISP_LH(0xe3000000, 0x0004, REG_2, REG_0, REG_15,
                              tjit->retval_off);
+       /* mvc stack_size+STK_OFF_TCCNT(4,%r15),tccnt_off(%r15) */
+       _EMIT6(0xd203f000 | (tjit->stack_size + STK_OFF_TCCNT),
+              0xf000 | tjit->tccnt_off);
        /* aghi %r15,stack_size */
        EMIT4_IMM(0xa70b0000, REG_15, tjit->stack_size);
        /* Emit an expoline for the following indirect jump. */
index 6673122266b7a0b51c98dc6b86488794fe44933b..42db7679c3606840df19045a46ec2f7148a8ffcb 100644 (file)
@@ -2335,13 +2335,27 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
 {
        struct ksz_device *dev = ds->priv;
 
-       if (dev->chip_id == KSZ8830_CHIP_ID) {
+       switch (dev->chip_id) {
+       case KSZ8830_CHIP_ID:
                /* Silicon Errata Sheet (DS80000830A):
                 * Port 1 does not work with LinkMD Cable-Testing.
                 * Port 1 does not respond to received PAUSE control frames.
                 */
                if (!port)
                        return MICREL_KSZ8_P1_ERRATA;
+               break;
+       case KSZ9477_CHIP_ID:
+               /* KSZ9477 Errata DS80000754C
+                *
+                * Module 4: Energy Efficient Ethernet (EEE) feature select must
+                * be manually disabled
+                *   The EEE feature is enabled by default, but it is not fully
+                *   operational. It must be manually disabled through register
+                *   controls. If not disabled, the PHY ports can auto-negotiate
+                *   to enable EEE, and this feature can cause link drops when
+                *   linked to another device supporting EEE.
+                */
+               return MICREL_NO_EEE;
        }
 
        return 0;
index dee35ba924ad2f5fe97be4865be825393f42bc58..0617d5ccd3ff104b63bac4711a8686f2ad2179f2 100644 (file)
@@ -132,6 +132,8 @@ struct sja1105_info {
        int max_frame_mem;
        int num_ports;
        bool multiple_cascade_ports;
+       /* Every {port, TXQ} has its own CBS shaper */
+       bool fixed_cbs_mapping;
        enum dsa_tag_protocol tag_proto;
        const struct sja1105_dynamic_table_ops *dyn_ops;
        const struct sja1105_table_ops *static_ops;
index 331bb1c6676aca8940aafcc956ef8769ccca5ae3..a23d980d28f5d190de5896ff79b106f529db566b 100644 (file)
@@ -2115,11 +2115,36 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port,
 }
 
 #define BYTES_PER_KBIT (1000LL / 8)
+/* Port 0 (the uC port) does not have CBS shapers */
+#define SJA1110_FIXED_CBS(port, prio) ((((port) - 1) * SJA1105_NUM_TC) + (prio))
+
+static int sja1105_find_cbs_shaper(struct sja1105_private *priv,
+                                  int port, int prio)
+{
+       int i;
+
+       if (priv->info->fixed_cbs_mapping) {
+               i = SJA1110_FIXED_CBS(port, prio);
+               if (i >= 0 && i < priv->info->num_cbs_shapers)
+                       return i;
+
+               return -1;
+       }
+
+       for (i = 0; i < priv->info->num_cbs_shapers; i++)
+               if (priv->cbs[i].port == port && priv->cbs[i].prio == prio)
+                       return i;
+
+       return -1;
+}
 
 static int sja1105_find_unused_cbs_shaper(struct sja1105_private *priv)
 {
        int i;
 
+       if (priv->info->fixed_cbs_mapping)
+               return -1;
+
        for (i = 0; i < priv->info->num_cbs_shapers; i++)
                if (!priv->cbs[i].idle_slope && !priv->cbs[i].send_slope)
                        return i;
@@ -2150,14 +2175,20 @@ static int sja1105_setup_tc_cbs(struct dsa_switch *ds, int port,
 {
        struct sja1105_private *priv = ds->priv;
        struct sja1105_cbs_entry *cbs;
+       s64 port_transmit_rate_kbps;
        int index;
 
        if (!offload->enable)
                return sja1105_delete_cbs_shaper(priv, port, offload->queue);
 
-       index = sja1105_find_unused_cbs_shaper(priv);
-       if (index < 0)
-               return -ENOSPC;
+       /* The user may be replacing an existing shaper */
+       index = sja1105_find_cbs_shaper(priv, port, offload->queue);
+       if (index < 0) {
+               /* That isn't the case - see if we can allocate a new one */
+               index = sja1105_find_unused_cbs_shaper(priv);
+               if (index < 0)
+                       return -ENOSPC;
+       }
 
        cbs = &priv->cbs[index];
        cbs->port = port;
@@ -2167,9 +2198,17 @@ static int sja1105_setup_tc_cbs(struct dsa_switch *ds, int port,
         */
        cbs->credit_hi = offload->hicredit;
        cbs->credit_lo = abs(offload->locredit);
-       /* User space is in kbits/sec, hardware in bytes/sec */
-       cbs->idle_slope = offload->idleslope * BYTES_PER_KBIT;
-       cbs->send_slope = abs(offload->sendslope * BYTES_PER_KBIT);
+       /* User space is in kbits/sec, while the hardware in bytes/sec times
+        * link speed. Since the given offload->sendslope is good only for the
+        * current link speed anyway, and user space is likely to reprogram it
+        * when that changes, don't even bother to track the port's link speed,
+        * but deduce the port transmit rate from idleslope - sendslope.
+        */
+       port_transmit_rate_kbps = offload->idleslope - offload->sendslope;
+       cbs->idle_slope = div_s64(offload->idleslope * BYTES_PER_KBIT,
+                                 port_transmit_rate_kbps);
+       cbs->send_slope = div_s64(abs(offload->sendslope * BYTES_PER_KBIT),
+                                 port_transmit_rate_kbps);
        /* Convert the negative values from 64-bit 2's complement
         * to 32-bit 2's complement (for the case of 0x80000000 whose
         * negative is still negative).
index 5ce29c8057a4181510abcb7397cc5ddc3a45d84c..834b5c1b4db0cbeb180d0c6118d589e4a5bba292 100644 (file)
@@ -781,6 +781,7 @@ const struct sja1105_info sja1110a_info = {
        .tag_proto              = DSA_TAG_PROTO_SJA1110,
        .can_limit_mcast_flood  = true,
        .multiple_cascade_ports = true,
+       .fixed_cbs_mapping      = true,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
        .max_frame_mem          = SJA1110_MAX_FRAME_MEMORY,
@@ -831,6 +832,7 @@ const struct sja1105_info sja1110b_info = {
        .tag_proto              = DSA_TAG_PROTO_SJA1110,
        .can_limit_mcast_flood  = true,
        .multiple_cascade_ports = true,
+       .fixed_cbs_mapping      = true,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
        .max_frame_mem          = SJA1110_MAX_FRAME_MEMORY,
@@ -881,6 +883,7 @@ const struct sja1105_info sja1110c_info = {
        .tag_proto              = DSA_TAG_PROTO_SJA1110,
        .can_limit_mcast_flood  = true,
        .multiple_cascade_ports = true,
+       .fixed_cbs_mapping      = true,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
        .max_frame_mem          = SJA1110_MAX_FRAME_MEMORY,
@@ -931,6 +934,7 @@ const struct sja1105_info sja1110d_info = {
        .tag_proto              = DSA_TAG_PROTO_SJA1110,
        .can_limit_mcast_flood  = true,
        .multiple_cascade_ports = true,
+       .fixed_cbs_mapping      = true,
        .ptp_ts_bits            = 32,
        .ptpegr_ts_bytes        = 8,
        .max_frame_mem          = SJA1110_MAX_FRAME_MEMORY,
index e0a4cb7e3f501732ea1001fb96474dfb57590718..c153dc083aff0fe618563d2161cdf8ae90b6682c 100644 (file)
@@ -1402,7 +1402,7 @@ static void enetc_fixup_clear_rss_rfs(struct pci_dev *pdev)
                return;
 
        si = enetc_psi_create(pdev);
-       if (si)
+       if (!IS_ERR(si))
                enetc_psi_destroy(pdev);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PF,
index ea0e38b4d9e9f6c41441729d6ae5693186f03040..f281e42a7ef9680e2049a185782a37d402c7f886 100644 (file)
@@ -570,7 +570,10 @@ static int gve_rx_append_frags(struct napi_struct *napi,
                if (!skb)
                        return -1;
 
-               skb_shinfo(rx->ctx.skb_tail)->frag_list = skb;
+               if (rx->ctx.skb_tail == rx->ctx.skb_head)
+                       skb_shinfo(rx->ctx.skb_head)->frag_list = skb;
+               else
+                       rx->ctx.skb_tail->next = skb;
                rx->ctx.skb_tail = skb;
                num_frags = 0;
        }
index a4b43bcd2f0c9c80ed96d529f988231dd456abe0..aaf1f42624a79b609e617b2700b0af82a2c5d81b 100644 (file)
@@ -814,6 +814,7 @@ struct hnae3_tc_info {
        u8 max_tc; /* Total number of TCs */
        u8 num_tc; /* Total number of enabled TCs */
        bool mqprio_active;
+       bool dcb_ets_active;
 };
 
 #define HNAE3_MAX_DSCP                 64
index f276b5ecb431fc7adade443d122cb5c13a3c53f3..b8508533878bea377eb055fcaa29b330f03c2626 100644 (file)
@@ -1045,6 +1045,7 @@ hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
        struct hnae3_ae_dev *ae_dev = pci_get_drvdata(h->pdev);
        struct hnae3_dev_specs *dev_specs = &ae_dev->dev_specs;
        struct hnae3_knic_private_info *kinfo = &h->kinfo;
+       struct net_device *dev = kinfo->netdev;
 
        *pos += scnprintf(buf + *pos, len - *pos, "dev_spec:\n");
        *pos += scnprintf(buf + *pos, len - *pos, "MAC entry num: %u\n",
@@ -1087,6 +1088,9 @@ hns3_dbg_dev_specs(struct hnae3_handle *h, char *buf, int len, int *pos)
                          dev_specs->mc_mac_size);
        *pos += scnprintf(buf + *pos, len - *pos, "MAC statistics number: %u\n",
                          dev_specs->mac_stats_num);
+       *pos += scnprintf(buf + *pos, len - *pos,
+                         "TX timeout threshold: %d seconds\n",
+                         dev->watchdog_timeo / HZ);
 }
 
 static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len)
@@ -1411,9 +1415,9 @@ int hns3_dbg_init(struct hnae3_handle *handle)
        return 0;
 
 out:
-       mutex_destroy(&handle->dbgfs_lock);
        debugfs_remove_recursive(handle->hnae3_dbgfs);
        handle->hnae3_dbgfs = NULL;
+       mutex_destroy(&handle->dbgfs_lock);
        return ret;
 }
 
@@ -1421,6 +1425,9 @@ void hns3_dbg_uninit(struct hnae3_handle *handle)
 {
        u32 i;
 
+       debugfs_remove_recursive(handle->hnae3_dbgfs);
+       handle->hnae3_dbgfs = NULL;
+
        for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++)
                if (handle->dbgfs_buf[i]) {
                        kvfree(handle->dbgfs_buf[i]);
@@ -1428,8 +1435,6 @@ void hns3_dbg_uninit(struct hnae3_handle *handle)
                }
 
        mutex_destroy(&handle->dbgfs_lock);
-       debugfs_remove_recursive(handle->hnae3_dbgfs);
-       handle->hnae3_dbgfs = NULL;
 }
 
 void hns3_dbg_register_debugfs(const char *debugfs_dir_name)
index eac2d05732415c3948239919c0431aaad09edb08..b4895c7b3efd1216209653002fca98f1d7f1c897 100644 (file)
@@ -2103,8 +2103,12 @@ static void hns3_tx_doorbell(struct hns3_enet_ring *ring, int num,
         */
        if (test_bit(HNS3_NIC_STATE_TX_PUSH_ENABLE, &priv->state) && num &&
            !ring->pending_buf && num <= HNS3_MAX_PUSH_BD_NUM && doorbell) {
+               /* This smp_store_release() pairs with smp_load_aquire() in
+                * hns3_nic_reclaim_desc(). Ensure that the BD valid bit
+                * is updated.
+                */
+               smp_store_release(&ring->last_to_use, ring->next_to_use);
                hns3_tx_push_bd(ring, num);
-               WRITE_ONCE(ring->last_to_use, ring->next_to_use);
                return;
        }
 
@@ -2115,6 +2119,11 @@ static void hns3_tx_doorbell(struct hns3_enet_ring *ring, int num,
                return;
        }
 
+       /* This smp_store_release() pairs with smp_load_aquire() in
+        * hns3_nic_reclaim_desc(). Ensure that the BD valid bit is updated.
+        */
+       smp_store_release(&ring->last_to_use, ring->next_to_use);
+
        if (ring->tqp->mem_base)
                hns3_tx_mem_doorbell(ring);
        else
@@ -2122,7 +2131,6 @@ static void hns3_tx_doorbell(struct hns3_enet_ring *ring, int num,
                       ring->tqp->io_base + HNS3_RING_TX_RING_TAIL_REG);
 
        ring->pending_buf = 0;
-       WRITE_ONCE(ring->last_to_use, ring->next_to_use);
 }
 
 static void hns3_tsyn(struct net_device *netdev, struct sk_buff *skb,
@@ -3308,8 +3316,6 @@ static void hns3_set_default_feature(struct net_device *netdev)
 
        netdev->priv_flags |= IFF_UNICAST_FLT;
 
-       netdev->gso_partial_features |= NETIF_F_GSO_GRE_CSUM;
-
        netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
                NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
                NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_GSO |
@@ -3563,9 +3569,8 @@ static void hns3_reuse_buffer(struct hns3_enet_ring *ring, int i)
 static bool hns3_nic_reclaim_desc(struct hns3_enet_ring *ring,
                                  int *bytes, int *pkts, int budget)
 {
-       /* pair with ring->last_to_use update in hns3_tx_doorbell(),
-        * smp_store_release() is not used in hns3_tx_doorbell() because
-        * the doorbell operation already have the needed barrier operation.
+       /* This smp_load_acquire() pairs with smp_store_release() in
+        * hns3_tx_doorbell().
         */
        int ltu = smp_load_acquire(&ring->last_to_use);
        int ntc = ring->next_to_clean;
index 36858a72d771e13af621ca354a4fcc739197a025..682239f33082b0b27b7ef866e15220f88b177fc3 100644 (file)
@@ -773,7 +773,9 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
                hns3_get_ksettings(h, cmd);
                break;
        case HNAE3_MEDIA_TYPE_FIBER:
-               if (module_type == HNAE3_MODULE_TYPE_CR)
+               if (module_type == HNAE3_MODULE_TYPE_UNKNOWN)
+                       cmd->base.port = PORT_OTHER;
+               else if (module_type == HNAE3_MODULE_TYPE_CR)
                        cmd->base.port = PORT_DA;
                else
                        cmd->base.port = PORT_FIBRE;
index fad5a5ff3cda54f5dfd4717a362d83cbac9e6358..b98301e205f7fff69b21f36a96e93ec358a371c1 100644 (file)
@@ -259,7 +259,7 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
        int ret;
 
        if (!(hdev->dcbx_cap & DCB_CAP_DCBX_VER_IEEE) ||
-           hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
+           h->kinfo.tc_info.mqprio_active)
                return -EINVAL;
 
        ret = hclge_ets_validate(hdev, ets, &num_tc, &map_changed);
@@ -275,10 +275,7 @@ static int hclge_ieee_setets(struct hnae3_handle *h, struct ieee_ets *ets)
        }
 
        hclge_tm_schd_info_update(hdev, num_tc);
-       if (num_tc > 1)
-               hdev->flag |= HCLGE_FLAG_DCB_ENABLE;
-       else
-               hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
+       h->kinfo.tc_info.dcb_ets_active = num_tc > 1;
 
        ret = hclge_ieee_ets_to_tm_info(hdev, ets);
        if (ret)
@@ -487,7 +484,7 @@ static u8 hclge_getdcbx(struct hnae3_handle *h)
        struct hclge_vport *vport = hclge_get_vport(h);
        struct hclge_dev *hdev = vport->back;
 
-       if (hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE)
+       if (h->kinfo.tc_info.mqprio_active)
                return 0;
 
        return hdev->dcbx_cap;
@@ -611,7 +608,8 @@ static int hclge_setup_tc(struct hnae3_handle *h,
        if (!test_bit(HCLGE_STATE_NIC_REGISTERED, &hdev->state))
                return -EBUSY;
 
-       if (hdev->flag & HCLGE_FLAG_DCB_ENABLE)
+       kinfo = &vport->nic.kinfo;
+       if (kinfo->tc_info.dcb_ets_active)
                return -EINVAL;
 
        ret = hclge_mqprio_qopt_check(hdev, mqprio_qopt);
@@ -625,7 +623,6 @@ static int hclge_setup_tc(struct hnae3_handle *h,
        if (ret)
                return ret;
 
-       kinfo = &vport->nic.kinfo;
        memcpy(&old_tc_info, &kinfo->tc_info, sizeof(old_tc_info));
        hclge_sync_mqprio_qopt(&kinfo->tc_info, mqprio_qopt);
        kinfo->tc_info.mqprio_active = tc > 0;
@@ -634,13 +631,6 @@ static int hclge_setup_tc(struct hnae3_handle *h,
        if (ret)
                goto err_out;
 
-       hdev->flag &= ~HCLGE_FLAG_DCB_ENABLE;
-
-       if (tc > 1)
-               hdev->flag |= HCLGE_FLAG_MQPRIO_ENABLE;
-       else
-               hdev->flag &= ~HCLGE_FLAG_MQPRIO_ENABLE;
-
        return hclge_notify_init_up(hdev);
 
 err_out:
index f01a7a9ee02ca149e05096fbbf47abc2d3f231e9..ff3f8f424ad9004bbd549bc32cc43abca3ea2610 100644 (file)
@@ -1519,7 +1519,7 @@ static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x,
        struct hclge_desc desc[3];
        int pos = 0;
        int ret, i;
-       u32 *req;
+       __le32 *req;
 
        hclge_cmd_setup_basic_desc(&desc[0], HCLGE_OPC_FD_TCAM_OP, true);
        desc[0].flag |= cpu_to_le16(HCLGE_COMM_CMD_FLAG_NEXT);
@@ -1544,22 +1544,22 @@ static int hclge_dbg_fd_tcam_read(struct hclge_dev *hdev, bool sel_x,
                         tcam_msg.loc);
 
        /* tcam_data0 ~ tcam_data1 */
-       req = (u32 *)req1->tcam_data;
+       req = (__le32 *)req1->tcam_data;
        for (i = 0; i < 2; i++)
                pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
-                                "%08x\n", *req++);
+                                "%08x\n", le32_to_cpu(*req++));
 
        /* tcam_data2 ~ tcam_data7 */
-       req = (u32 *)req2->tcam_data;
+       req = (__le32 *)req2->tcam_data;
        for (i = 0; i < 6; i++)
                pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
-                                "%08x\n", *req++);
+                                "%08x\n", le32_to_cpu(*req++));
 
        /* tcam_data8 ~ tcam_data12 */
-       req = (u32 *)req3->tcam_data;
+       req = (__le32 *)req3->tcam_data;
        for (i = 0; i < 5; i++)
                pos += scnprintf(tcam_buf + pos, HCLGE_DBG_TCAM_BUF_SIZE - pos,
-                                "%08x\n", *req++);
+                                "%08x\n", le32_to_cpu(*req++));
 
        return ret;
 }
index 0f50dba6cc4780792b88b077df493daf89225434..8ca368424436205c00951112a2ed7abaf4700153 100644 (file)
@@ -11026,6 +11026,7 @@ static void hclge_get_mdix_mode(struct hnae3_handle *handle,
 
 static void hclge_info_show(struct hclge_dev *hdev)
 {
+       struct hnae3_handle *handle = &hdev->vport->nic;
        struct device *dev = &hdev->pdev->dev;
 
        dev_info(dev, "PF info begin:\n");
@@ -11042,9 +11043,9 @@ static void hclge_info_show(struct hclge_dev *hdev)
        dev_info(dev, "This is %s PF\n",
                 hdev->flag & HCLGE_FLAG_MAIN ? "main" : "not main");
        dev_info(dev, "DCB %s\n",
-                hdev->flag & HCLGE_FLAG_DCB_ENABLE ? "enable" : "disable");
+                handle->kinfo.tc_info.dcb_ets_active ? "enable" : "disable");
        dev_info(dev, "MQPRIO %s\n",
-                hdev->flag & HCLGE_FLAG_MQPRIO_ENABLE ? "enable" : "disable");
+                handle->kinfo.tc_info.mqprio_active ? "enable" : "disable");
        dev_info(dev, "Default tx spare buffer size: %u\n",
                 hdev->tx_spare_buf_size);
 
index ec233ec57222aa8e76adcda2bce6e941b9e4129b..7bc2049b723daa387aba2a083dc526a2e68083ba 100644 (file)
@@ -919,8 +919,6 @@ struct hclge_dev {
 
 #define HCLGE_FLAG_MAIN                        BIT(0)
 #define HCLGE_FLAG_DCB_CAPABLE         BIT(1)
-#define HCLGE_FLAG_DCB_ENABLE          BIT(2)
-#define HCLGE_FLAG_MQPRIO_ENABLE       BIT(3)
        u32 flag;
 
        u32 pkt_buf_size; /* Total pf buf size for tx/rx */
index 015b781441149b0d03fed5a340b2323083b4eba8..a2b759531cb7ba44720f000018597d5222bec900 100644 (file)
@@ -34,11 +34,11 @@ struct igb_adapter;
 /* TX/RX descriptor defines */
 #define IGB_DEFAULT_TXD                256
 #define IGB_DEFAULT_TX_WORK    128
-#define IGB_MIN_TXD            80
+#define IGB_MIN_TXD            64
 #define IGB_MAX_TXD            4096
 
 #define IGB_DEFAULT_RXD                256
-#define IGB_MIN_RXD            80
+#define IGB_MIN_RXD            64
 #define IGB_MAX_RXD            4096
 
 #define IGB_DEFAULT_ITR                3 /* dynamic */
index 1ab787ed254df35ea738752d779f35fab54e4183..13ba9c74bd848e5eb26248abc378776a3cc1fc96 100644 (file)
@@ -3933,8 +3933,9 @@ static void igb_probe_vfs(struct igb_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
        struct e1000_hw *hw = &adapter->hw;
 
-       /* Virtualization features not supported on i210 family. */
-       if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211))
+       /* Virtualization features not supported on i210 and 82580 family. */
+       if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211) ||
+           (hw->mac.type == e1000_82580))
                return;
 
        /* Of the below we really only want the effect of getting
index 57d39ee00b58540aaf7ea919951a51f8fd30a934..7b83678ba83a695cfea6eaafbcac8efdda148415 100644 (file)
@@ -39,11 +39,11 @@ enum latency_range {
 /* Tx/Rx descriptor defines */
 #define IGBVF_DEFAULT_TXD      256
 #define IGBVF_MAX_TXD          4096
-#define IGBVF_MIN_TXD          80
+#define IGBVF_MIN_TXD          64
 
 #define IGBVF_DEFAULT_RXD      256
 #define IGBVF_MAX_RXD          4096
-#define IGBVF_MIN_RXD          80
+#define IGBVF_MIN_RXD          64
 
 #define IGBVF_MIN_ITR_USECS    10 /* 100000 irq/sec */
 #define IGBVF_MAX_ITR_USECS    10000 /* 100    irq/sec */
index 8ebe6999a528cd44a77f9e83b5babe5dc675af31..f48f82d5e274b1dc55052d8a86824d42db8264a7 100644 (file)
@@ -379,11 +379,11 @@ static inline u32 igc_rss_type(const union igc_adv_rx_desc *rx_desc)
 /* TX/RX descriptor defines */
 #define IGC_DEFAULT_TXD                256
 #define IGC_DEFAULT_TX_WORK    128
-#define IGC_MIN_TXD            80
+#define IGC_MIN_TXD            64
 #define IGC_MAX_TXD            4096
 
 #define IGC_DEFAULT_RXD                256
-#define IGC_MIN_RXD            80
+#define IGC_MIN_RXD            64
 #define IGC_MAX_RXD            4096
 
 /* Supported Rx Buffer Sizes */
index c2f68678e947e8019aa53a13c290080ebc488d0a..23c2f2ed2fb83294f4345cf55e9b5252d280b376 100644 (file)
@@ -846,6 +846,21 @@ static int nix_aq_enqueue_wait(struct rvu *rvu, struct rvu_block *block,
        return 0;
 }
 
+static void nix_get_aq_req_smq(struct rvu *rvu, struct nix_aq_enq_req *req,
+                              u16 *smq, u16 *smq_mask)
+{
+       struct nix_cn10k_aq_enq_req *aq_req;
+
+       if (!is_rvu_otx2(rvu)) {
+               aq_req = (struct nix_cn10k_aq_enq_req *)req;
+               *smq = aq_req->sq.smq;
+               *smq_mask = aq_req->sq_mask.smq;
+       } else {
+               *smq = req->sq.smq;
+               *smq_mask = req->sq_mask.smq;
+       }
+}
+
 static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
                                   struct nix_aq_enq_req *req,
                                   struct nix_aq_enq_rsp *rsp)
@@ -857,6 +872,7 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
        struct rvu_block *block;
        struct admin_queue *aq;
        struct rvu_pfvf *pfvf;
+       u16 smq, smq_mask;
        void *ctx, *mask;
        bool ena;
        u64 cfg;
@@ -928,13 +944,14 @@ static int rvu_nix_blk_aq_enq_inst(struct rvu *rvu, struct nix_hw *nix_hw,
        if (rc)
                return rc;
 
+       nix_get_aq_req_smq(rvu, req, &smq, &smq_mask);
        /* Check if SQ pointed SMQ belongs to this PF/VF or not */
        if (req->ctype == NIX_AQ_CTYPE_SQ &&
            ((req->op == NIX_AQ_INSTOP_INIT && req->sq.ena) ||
             (req->op == NIX_AQ_INSTOP_WRITE &&
-             req->sq_mask.ena && req->sq_mask.smq && req->sq.ena))) {
+             req->sq_mask.ena && req->sq.ena && smq_mask))) {
                if (!is_valid_txschq(rvu, blkaddr, NIX_TXSCH_LVL_SMQ,
-                                    pcifunc, req->sq.smq))
+                                    pcifunc, smq))
                        return NIX_AF_ERR_AQ_ENQUEUE;
        }
 
index 92d3952dfa8b78fc067e515cd1c78b9662fea038..feeb41693c176eaeb805251d328610c23b4707d7 100644 (file)
@@ -17,8 +17,10 @@ tc_act_parse_ct(struct mlx5e_tc_act_parse_state *parse_state,
        if (err)
                return err;
 
-       if (mlx5e_is_eswitch_flow(parse_state->flow))
+       if (mlx5e_is_eswitch_flow(parse_state->flow)) {
                attr->esw_attr->split_count = attr->esw_attr->out_count;
+               parse_state->if_count = 0;
+       }
 
        attr->flags |= MLX5_ATTR_FLAG_CT;
 
index 291193f7120d5f68f982f75ccbb1e7238db1999b..f63402c480280c735dac1e219b14f4ca8ed0b5b2 100644 (file)
@@ -294,6 +294,7 @@ parse_mirred_ovs_master(struct mlx5e_tc_act_parse_state *parse_state,
        if (err)
                return err;
 
+       parse_state->if_count = 0;
        esw_attr->out_count++;
        return 0;
 }
index 3b272bbf4c53806ffc5559126ebe44491bc4d906..368a95fa77d3263faa2749c2c33e61ddbbc1aa91 100644 (file)
@@ -98,8 +98,10 @@ tc_act_parse_pedit(struct mlx5e_tc_act_parse_state *parse_state,
 
        attr->action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
 
-       if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
+       if (ns_type == MLX5_FLOW_NAMESPACE_FDB) {
                esw_attr->split_count = esw_attr->out_count;
+               parse_state->if_count = 0;
+       }
 
        return 0;
 }
index ad09a8a5f36e0441f53cc039c27da72c4091b0a5..2d1d4a04501b47b85613cfc876d694b64e78442f 100644 (file)
@@ -66,6 +66,7 @@ tc_act_parse_redirect_ingress(struct mlx5e_tc_act_parse_state *parse_state,
        if (err)
                return err;
 
+       parse_state->if_count = 0;
        esw_attr->out_count++;
 
        return 0;
index c8a3eaf189f6ace825aff2c9641e61a0285ddb91..a13c5e707b83cfe62593cae080a3b880172fb6b8 100644 (file)
@@ -166,6 +166,7 @@ tc_act_parse_vlan(struct mlx5e_tc_act_parse_state *parse_state,
                return err;
 
        esw_attr->split_count = esw_attr->out_count;
+       parse_state->if_count = 0;
 
        return 0;
 }
index 310b992307607cc86a626c834195506308d64694..f17575b09788db241a3a39e0ca75a8a17c925346 100644 (file)
@@ -65,8 +65,10 @@ tc_act_parse_vlan_mangle(struct mlx5e_tc_act_parse_state *parse_state,
        if (err)
                return err;
 
-       if (ns_type == MLX5_FLOW_NAMESPACE_FDB)
+       if (ns_type == MLX5_FLOW_NAMESPACE_FDB) {
                attr->esw_attr->split_count = attr->esw_attr->out_count;
+               parse_state->if_count = 0;
+       }
 
        return 0;
 }
index 318083690fcd26a8134bbbc56edb6ef3dd3eabf2..c24828b688ac0aa049f3518aefdf21251da4e8d9 100644 (file)
@@ -3936,6 +3936,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
                        }
 
                        i_split = i + 1;
+                       parse_state->if_count = 0;
                        list_add(&attr->list, &flow->attrs);
                }
 
index 6cd7d6497e10996f891774d5406f10dfce2ba889..d4cde655506323deac75918aa1429b8e6ce4d721 100644 (file)
@@ -1276,12 +1276,19 @@ int
 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
                                 enum mlx5_eswitch_vport_event enabled_events)
 {
+       bool pf_needed;
        int ret;
 
+       pf_needed = mlx5_core_is_ecpf_esw_manager(esw->dev) ||
+                   esw->mode == MLX5_ESWITCH_LEGACY;
+
        /* Enable PF vport */
-       ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_PF, enabled_events);
-       if (ret)
-               return ret;
+       if (pf_needed) {
+               ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_PF,
+                                                   enabled_events);
+               if (ret)
+                       return ret;
+       }
 
        /* Enable external host PF HCA */
        ret = host_pf_enable_hca(esw->dev);
@@ -1317,7 +1324,8 @@ ec_vf_err:
 ecpf_err:
        host_pf_disable_hca(esw->dev);
 pf_hca_err:
-       mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
+       if (pf_needed)
+               mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
        return ret;
 }
 
@@ -1335,7 +1343,10 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
        }
 
        host_pf_disable_hca(esw->dev);
-       mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
+
+       if (mlx5_core_is_ecpf_esw_manager(esw->dev) ||
+           esw->mode == MLX5_ESWITCH_LEGACY)
+               mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_PF);
 }
 
 static void mlx5_eswitch_get_devlink_param(struct mlx5_eswitch *esw)
index 752fb0dfb111b27075cd1ead2688d83bb6d1bac7..b296ac52a43974fc17e372a403a981a9220ab273 100644 (file)
@@ -3216,26 +3216,47 @@ esw_vport_destroy_offloads_acl_tables(struct mlx5_eswitch *esw,
        esw_acl_ingress_ofld_cleanup(esw, vport);
 }
 
-static int esw_create_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
+static int esw_create_offloads_acl_tables(struct mlx5_eswitch *esw)
 {
-       struct mlx5_vport *vport;
+       struct mlx5_vport *uplink, *manager;
+       int ret;
 
-       vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
-       if (IS_ERR(vport))
-               return PTR_ERR(vport);
+       uplink = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
+       if (IS_ERR(uplink))
+               return PTR_ERR(uplink);
+
+       ret = esw_vport_create_offloads_acl_tables(esw, uplink);
+       if (ret)
+               return ret;
+
+       manager = mlx5_eswitch_get_vport(esw, esw->manager_vport);
+       if (IS_ERR(manager)) {
+               ret = PTR_ERR(manager);
+               goto err_manager;
+       }
 
-       return esw_vport_create_offloads_acl_tables(esw, vport);
+       ret = esw_vport_create_offloads_acl_tables(esw, manager);
+       if (ret)
+               goto err_manager;
+
+       return 0;
+
+err_manager:
+       esw_vport_destroy_offloads_acl_tables(esw, uplink);
+       return ret;
 }
 
-static void esw_destroy_uplink_offloads_acl_tables(struct mlx5_eswitch *esw)
+static void esw_destroy_offloads_acl_tables(struct mlx5_eswitch *esw)
 {
        struct mlx5_vport *vport;
 
-       vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
-       if (IS_ERR(vport))
-               return;
+       vport = mlx5_eswitch_get_vport(esw, esw->manager_vport);
+       if (!IS_ERR(vport))
+               esw_vport_destroy_offloads_acl_tables(esw, vport);
 
-       esw_vport_destroy_offloads_acl_tables(esw, vport);
+       vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_UPLINK);
+       if (!IS_ERR(vport))
+               esw_vport_destroy_offloads_acl_tables(esw, vport);
 }
 
 int mlx5_eswitch_reload_reps(struct mlx5_eswitch *esw)
@@ -3280,7 +3301,7 @@ static int esw_offloads_steering_init(struct mlx5_eswitch *esw)
        }
        esw->fdb_table.offloads.indir = indir;
 
-       err = esw_create_uplink_offloads_acl_tables(esw);
+       err = esw_create_offloads_acl_tables(esw);
        if (err)
                goto create_acl_err;
 
@@ -3321,7 +3342,7 @@ create_fdb_err:
 create_restore_err:
        esw_destroy_offloads_table(esw);
 create_offloads_err:
-       esw_destroy_uplink_offloads_acl_tables(esw);
+       esw_destroy_offloads_acl_tables(esw);
 create_acl_err:
        mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
 create_indir_err:
@@ -3337,7 +3358,7 @@ static void esw_offloads_steering_cleanup(struct mlx5_eswitch *esw)
        esw_destroy_offloads_fdb_tables(esw);
        esw_destroy_restore_table(esw);
        esw_destroy_offloads_table(esw);
-       esw_destroy_uplink_offloads_acl_tables(esw);
+       esw_destroy_offloads_acl_tables(esw);
        mlx5_esw_indir_table_destroy(esw->fdb_table.offloads.indir);
        mutex_destroy(&esw->fdb_table.offloads.vports.lock);
 }
index 2375cef577e44e2db689a24bb50f9d37cdcce33a..f77a2d3ef37ecaa566be2458df36b56499984818 100644 (file)
@@ -359,26 +359,36 @@ static bool efx_do_xdp(struct efx_nic *efx, struct efx_channel *channel,
 /* Handle a received packet.  Second half: Touches packet payload. */
 void __efx_rx_packet(struct efx_channel *channel)
 {
+       struct efx_rx_queue *rx_queue = efx_channel_get_rx_queue(channel);
        struct efx_nic *efx = channel->efx;
        struct efx_rx_buffer *rx_buf =
-               efx_rx_buffer(&channel->rx_queue, channel->rx_pkt_index);
+               efx_rx_buffer(rx_queue, channel->rx_pkt_index);
        u8 *eh = efx_rx_buf_va(rx_buf);
 
        /* Read length from the prefix if necessary.  This already
         * excludes the length of the prefix itself.
         */
-       if (rx_buf->flags & EFX_RX_PKT_PREFIX_LEN)
+       if (rx_buf->flags & EFX_RX_PKT_PREFIX_LEN) {
                rx_buf->len = le16_to_cpup((__le16 *)
                                           (eh + efx->rx_packet_len_offset));
+               /* A known issue may prevent this being filled in;
+                * if that happens, just drop the packet.
+                * Must do that in the driver since passing a zero-length
+                * packet up to the stack may cause a crash.
+                */
+               if (unlikely(!rx_buf->len)) {
+                       efx_free_rx_buffers(rx_queue, rx_buf,
+                                           channel->rx_pkt_n_frags);
+                       channel->n_rx_frm_trunc++;
+                       goto out;
+               }
+       }
 
        /* If we're in loopback test, then pass the packet directly to the
         * loopback layer, and free the rx_buf here
         */
        if (unlikely(efx->loopback_selftest)) {
-               struct efx_rx_queue *rx_queue;
-
                efx_loopback_rx_packet(efx, eh, rx_buf->len);
-               rx_queue = efx_channel_get_rx_queue(channel);
                efx_free_rx_buffers(rx_queue, rx_buf,
                                    channel->rx_pkt_n_frags);
                goto out;
index 35f4b1484029ba4b9d6d87260b831fa3df7953d8..0f28795e581c23957fba5c81c83ba9d248521a97 100644 (file)
@@ -419,9 +419,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac)
                return ERR_PTR(phy_mode);
 
        plat->phy_interface = phy_mode;
-       plat->mac_interface = stmmac_of_get_mac_mode(np);
-       if (plat->mac_interface < 0)
-               plat->mac_interface = plat->phy_interface;
+       rc = stmmac_of_get_mac_mode(np);
+       plat->mac_interface = rc < 0 ? plat->phy_interface : rc;
 
        /* Some wrapper drivers still rely on phy_node. Let's save it while
         * they are not converted to phylink. */
index c3f30663070f9496e6f574ea83e189ae85cfb6de..b7e151439c4886f851ba87e27a34e33cd834069a 100644 (file)
@@ -1330,8 +1330,7 @@ static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len)
        struct crypto_aead *tfm;
        int ret;
 
-       /* Pick a sync gcm(aes) cipher to ensure order is preserved. */
-       tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
+       tfm = crypto_alloc_aead("gcm(aes)", 0, 0);
 
        if (IS_ERR(tfm))
                return tfm;
index b6d7981b2d1ee7f295b9ed9346a1f77489311360..927d3d54658ef825f57cadfc21e31c1fca0896d4 100644 (file)
@@ -1800,9 +1800,6 @@ static const struct ksz9477_errata_write ksz9477_errata_writes[] = {
        /* Transmit waveform amplitude can be improved (1000BASE-T, 100BASE-TX, 10BASE-Te) */
        {0x1c, 0x04, 0x00d0},
 
-       /* Energy Efficient Ethernet (EEE) feature select must be manually disabled */
-       {0x07, 0x3c, 0x0000},
-
        /* Register settings are required to meet data sheet supply current specifications */
        {0x1c, 0x13, 0x6eff},
        {0x1c, 0x14, 0xe6ff},
@@ -1847,6 +1844,12 @@ static int ksz9477_config_init(struct phy_device *phydev)
                        return err;
        }
 
+       /* According to KSZ9477 Errata DS80000754C (Module 4) all EEE modes
+        * in this switch shall be regarded as broken.
+        */
+       if (phydev->dev_flags & MICREL_NO_EEE)
+               phydev->eee_broken_modes = -1;
+
        err = genphy_restart_aneg(phydev);
        if (err)
                return err;
index d43e62ebc2fcd5d30f4717454ab5c9d089502d15..9c6f4f83f22b0750cec1313a8746cb8c9dbcd7be 100644 (file)
@@ -344,6 +344,7 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct veth_priv *rcv_priv, *priv = netdev_priv(dev);
        struct veth_rq *rq = NULL;
+       int ret = NETDEV_TX_OK;
        struct net_device *rcv;
        int length = skb->len;
        bool use_napi = false;
@@ -378,11 +379,12 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
        } else {
 drop:
                atomic64_inc(&priv->dropped);
+               ret = NET_XMIT_DROP;
        }
 
        rcu_read_unlock();
 
-       return NETDEV_TX_OK;
+       return ret;
 }
 
 static u64 veth_stats_tx(struct net_device *dev, u64 *packets, u64 *bytes)
index dca25a0c2f33ccbd3ae88a2b4ae1b9ffdffaf72a..3ae4b41c59ac3d64c77fe9479c303756e0b441bb 100644 (file)
@@ -336,6 +336,7 @@ MODULE_DEVICE_TABLE(of, of_nxp_nci_i2c_match);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id acpi_id[] = {
        { "NXP1001" },
+       { "NXP1002" },
        { "NXP7471" },
        { }
 };
index 6a3a9e122bb5ef005f7c50f98185a44b289de844..51b1b7054a233a167fa29a6461cce4bc5202a75e 100644 (file)
@@ -117,6 +117,8 @@ enum audit_nfcfgop {
        AUDIT_NFT_OP_OBJ_RESET,
        AUDIT_NFT_OP_FLOWTABLE_REGISTER,
        AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
+       AUDIT_NFT_OP_SETELEM_RESET,
+       AUDIT_NFT_OP_RULE_RESET,
        AUDIT_NFT_OP_INVALID,
 };
 
index 12596af59c0049a04039d117f3c98bb269413d6b..024e8b28c34b813296d6fd015bc0047702258193 100644 (file)
@@ -438,7 +438,7 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size)
 
        size /= sizeof(long);
        while (size--)
-               *ldst++ = *lsrc++;
+               data_race(*ldst++ = *lsrc++);
 }
 
 /* copy everything but bpf_spin_lock, bpf_timer, and kptrs. There could be one of each. */
index 5883551b1ee874b8c217bbefa5cb5feeb8e894c1..af8a771a053c51eed297516f927a5fd003315ef4 100644 (file)
@@ -147,6 +147,7 @@ struct inet6_skb_parm {
 #define IP6SKB_JUMBOGRAM      128
 #define IP6SKB_SEG6          256
 #define IP6SKB_FAKEJUMBO      512
+#define IP6SKB_MULTIPATH      1024
 };
 
 #if defined(CONFIG_NET_L3_MASTER_DEV)
index 8bef1ab62bba3778ead0711bfb292fa0d6f74e9c..4e27ca7c49defec2668884e52dc4a76da5afb8d6 100644 (file)
 #define        PHY_ID_KSZ9477          0x00221631
 
 /* struct phy_device dev_flags definitions */
-#define MICREL_PHY_50MHZ_CLK   0x00000001
-#define MICREL_PHY_FXEN                0x00000002
-#define MICREL_KSZ8_P1_ERRATA  0x00000003
+#define MICREL_PHY_50MHZ_CLK   BIT(0)
+#define MICREL_PHY_FXEN                BIT(1)
+#define MICREL_KSZ8_P1_ERRATA  BIT(2)
+#define MICREL_NO_EEE          BIT(3)
 
 #define MICREL_KSZ9021_EXTREG_CTRL     0xB
 #define MICREL_KSZ9021_EXTREG_DATA_WRITE       0xC
index 7d07f8736431349cd946c00fb9a79e8f0c972c4f..2b886ea654bb36ede4e06accf13a6f257fd19f42 100644 (file)
@@ -600,7 +600,7 @@ void pcs_get_state(struct phylink_pcs *pcs,
  *
  * The %neg_mode argument should be tested via the phylink_mode_*() family of
  * functions, or for PCS that set pcs->neg_mode true, should be tested
- * against the %PHYLINK_PCS_NEG_* definitions.
+ * against the PHYLINK_PCS_NEG_* definitions.
  */
 int pcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
               phy_interface_t interface, const unsigned long *advertising,
@@ -630,7 +630,7 @@ void pcs_an_restart(struct phylink_pcs *pcs);
  *
  * The %mode argument should be tested via the phylink_mode_*() family of
  * functions, or for PCS that set pcs->neg_mode true, should be tested
- * against the %PHYLINK_PCS_NEG_* definitions.
+ * against the PHYLINK_PCS_NEG_* definitions.
  */
 void pcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
                 phy_interface_t interface, int speed, int duplex);
index 19adacd5ece031547e3ad70d524e89d8a6301a55..3489a1cca5e7bc315ba646f6bc125b2b6ded9416 100644 (file)
@@ -57,6 +57,7 @@ struct inet_skb_parm {
 #define IPSKB_FRAG_PMTU                BIT(6)
 #define IPSKB_L3SLAVE          BIT(7)
 #define IPSKB_NOPOLICY         BIT(8)
+#define IPSKB_MULTIPATH                BIT(9)
 
        u16                     frag_max_size;
 };
@@ -94,7 +95,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm,
        ipcm_init(ipcm);
 
        ipcm->sockc.mark = READ_ONCE(inet->sk.sk_mark);
-       ipcm->sockc.tsflags = inet->sk.sk_tsflags;
+       ipcm->sockc.tsflags = READ_ONCE(inet->sk.sk_tsflags);
        ipcm->oif = READ_ONCE(inet->sk.sk_bound_dev_if);
        ipcm->addr = inet->inet_saddr;
        ipcm->protocol = inet->inet_num;
index c9ff23cf313e4efd4afd889a38aa7872c08118ea..1ba9f4ddf2f6db6c6ebf0a0675ca74fea2273fd9 100644 (file)
@@ -642,7 +642,10 @@ static inline bool fib6_rules_early_flow_dissect(struct net *net,
        if (!net->ipv6.fib6_rules_require_fldissect)
                return false;
 
-       skb_flow_dissect_flow_keys(skb, flkeys, flag);
+       memset(flkeys, 0, sizeof(*flkeys));
+       __skb_flow_dissect(net, skb, &flow_keys_dissector,
+                          flkeys, NULL, 0, 0, 0, flag);
+
        fl6->fl6_sport = flkeys->ports.src;
        fl6->fl6_dport = flkeys->ports.dst;
        fl6->flowi6_proto = flkeys->basic.ip_proto;
index a378eff827c7484937084c4e4cbbe3f96e2a67d5..f0c13864180e23e43fe065494fe4e42114c6ecd1 100644 (file)
@@ -418,7 +418,10 @@ static inline bool fib4_rules_early_flow_dissect(struct net *net,
        if (!net->ipv4.fib_rules_require_fldissect)
                return false;
 
-       skb_flow_dissect_flow_keys(skb, flkeys, flag);
+       memset(flkeys, 0, sizeof(*flkeys));
+       __skb_flow_dissect(net, skb, &flow_keys_dissector,
+                          flkeys, NULL, 0, 0, 0, flag);
+
        fl4->fl4_sport = flkeys->ports.src;
        fl4->fl4_dport = flkeys->ports.dst;
        fl4->flowi4_proto = flkeys->basic.ip_proto;
index e8750b4ef7e17ad85c88ec1db73242795ede0281..f346b4efbc307bcca8893775d9bd4c12f5917293 100644 (file)
@@ -483,15 +483,14 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len)
                u64_stats_inc(&tstats->tx_packets);
                u64_stats_update_end(&tstats->syncp);
                put_cpu_ptr(tstats);
+               return;
+       }
+
+       if (pkt_len < 0) {
+               DEV_STATS_INC(dev, tx_errors);
+               DEV_STATS_INC(dev, tx_aborted_errors);
        } else {
-               struct net_device_stats *err_stats = &dev->stats;
-
-               if (pkt_len < 0) {
-                       err_stats->tx_errors++;
-                       err_stats->tx_aborted_errors++;
-               } else {
-                       err_stats->tx_dropped++;
-               }
+               DEV_STATS_INC(dev, tx_dropped);
        }
 }
 
index c5bcdf65f55c964388ac11bb8d3236e9c045e3ee..e8c76b4be2fe71c62f841a8cbc27aa97acf670b3 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/pid.h>
 #include <linux/nsproxy.h>
 #include <linux/sched/signal.h>
+#include <net/compat.h>
 
 /* Well, we should have at least one descriptor open
  * to accept passed FDs 8)
@@ -123,14 +124,17 @@ static inline bool scm_has_secdata(struct socket *sock)
 static __inline__ void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
 {
        struct file *pidfd_file = NULL;
-       int pidfd;
+       int len, pidfd;
 
-       /*
-        * put_cmsg() doesn't return an error if CMSG is truncated,
+       /* put_cmsg() doesn't return an error if CMSG is truncated,
         * that's why we need to opencode these checks here.
         */
-       if ((msg->msg_controllen <= sizeof(struct cmsghdr)) ||
-           (msg->msg_controllen - sizeof(struct cmsghdr)) < sizeof(int)) {
+       if (msg->msg_flags & MSG_CMSG_COMPAT)
+               len = sizeof(struct compat_cmsghdr) + sizeof(int);
+       else
+               len = sizeof(struct cmsghdr) + sizeof(int);
+
+       if (msg->msg_controllen < len) {
                msg->msg_flags |= MSG_CTRUNC;
                return;
        }
index 11d503417591ed758fe2b2acbf7d3a9d0f07b660..b770261fbdaf59d4d1c0b30adb2592c56442e9e3 100644 (file)
@@ -1053,6 +1053,12 @@ static inline void sk_wmem_queued_add(struct sock *sk, int val)
        WRITE_ONCE(sk->sk_wmem_queued, sk->sk_wmem_queued + val);
 }
 
+static inline void sk_forward_alloc_add(struct sock *sk, int val)
+{
+       /* Paired with lockless reads of sk->sk_forward_alloc */
+       WRITE_ONCE(sk->sk_forward_alloc, sk->sk_forward_alloc + val);
+}
+
 void sk_stream_write_space(struct sock *sk);
 
 /* OOB backlog add */
@@ -1377,7 +1383,7 @@ static inline int sk_forward_alloc_get(const struct sock *sk)
        if (sk->sk_prot->forward_alloc_get)
                return sk->sk_prot->forward_alloc_get(sk);
 #endif
-       return sk->sk_forward_alloc;
+       return READ_ONCE(sk->sk_forward_alloc);
 }
 
 static inline bool __sk_stream_memory_free(const struct sock *sk, int wake)
@@ -1673,14 +1679,14 @@ static inline void sk_mem_charge(struct sock *sk, int size)
 {
        if (!sk_has_account(sk))
                return;
-       sk->sk_forward_alloc -= size;
+       sk_forward_alloc_add(sk, -size);
 }
 
 static inline void sk_mem_uncharge(struct sock *sk, int size)
 {
        if (!sk_has_account(sk))
                return;
-       sk->sk_forward_alloc += size;
+       sk_forward_alloc_add(sk, size);
        sk_mem_reclaim(sk);
 }
 
@@ -1900,7 +1906,9 @@ struct sockcm_cookie {
 static inline void sockcm_init(struct sockcm_cookie *sockc,
                               const struct sock *sk)
 {
-       *sockc = (struct sockcm_cookie) { .tsflags = sk->sk_tsflags };
+       *sockc = (struct sockcm_cookie) {
+               .tsflags = READ_ONCE(sk->sk_tsflags)
+       };
 }
 
 int __sock_cmsg_send(struct sock *sk, struct cmsghdr *cmsg,
@@ -2695,9 +2703,9 @@ void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
 static inline void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
-       ktime_t kt = skb->tstamp;
        struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
-
+       u32 tsflags = READ_ONCE(sk->sk_tsflags);
+       ktime_t kt = skb->tstamp;
        /*
         * generate control messages if
         * - receive time stamping in software requested
@@ -2705,10 +2713,10 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
         * - hardware time stamps available and wanted
         */
        if (sock_flag(sk, SOCK_RCVTSTAMP) ||
-           (sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) ||
-           (kt && sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) ||
+           (tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) ||
+           (kt && tsflags & SOF_TIMESTAMPING_SOFTWARE) ||
            (hwtstamps->hwtstamp &&
-            (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)))
+            (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)))
                __sock_recv_timestamp(msg, sk, skb);
        else
                sock_write_timestamp(sk, kt);
@@ -2730,7 +2738,8 @@ static inline void sock_recv_cmsgs(struct msghdr *msg, struct sock *sk,
 #define TSFLAGS_ANY      (SOF_TIMESTAMPING_SOFTWARE                    | \
                           SOF_TIMESTAMPING_RAW_HARDWARE)
 
-       if (sk->sk_flags & FLAGS_RECV_CMSGS || sk->sk_tsflags & TSFLAGS_ANY)
+       if (sk->sk_flags & FLAGS_RECV_CMSGS ||
+           READ_ONCE(sk->sk_tsflags) & TSFLAGS_ANY)
                __sock_recv_cmsgs(msg, sk, skb);
        else if (unlikely(sock_flag(sk, SOCK_TIMESTAMP)))
                sock_write_timestamp(sk, skb->tstamp);
index 8466c2a9938f3d429b37cbf64923039d13912964..ca30232b7bc8af49a6c3dd1c03e105628aafabf9 100644 (file)
@@ -263,6 +263,7 @@ enum nft_chain_attributes {
  * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN)
  * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32)
  * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32)
+ * @NFTA_RULE_CHAIN_ID: add the rule to chain by ID, alternative to @NFTA_RULE_CHAIN (NLA_U32)
  */
 enum nft_rule_attributes {
        NFTA_RULE_UNSPEC,
index b0cb7631e48ba12e8bd8408e2cbaa1dc4cb0e910..21d2fa815e782afddb5b2c56110fadf7e83376bc 100644 (file)
@@ -143,6 +143,8 @@ static const struct audit_nfcfgop_tab audit_nfcfgs[] = {
        { AUDIT_NFT_OP_OBJ_RESET,               "nft_reset_obj"            },
        { AUDIT_NFT_OP_FLOWTABLE_REGISTER,      "nft_register_flowtable"   },
        { AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,    "nft_unregister_flowtable" },
+       { AUDIT_NFT_OP_SETELEM_RESET,           "nft_reset_setelem"        },
+       { AUDIT_NFT_OP_RULE_RESET,              "nft_reset_rule"           },
        { AUDIT_NFT_OP_INVALID,                 "nft_invalid"              },
 };
 
index b5149cfce7d4defaac057a095cb2b055f888384b..146824cc96893c784f8a838f4ebca1760a05744d 100644 (file)
@@ -553,7 +553,7 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
                         void *value, u64 map_flags, gfp_t gfp_flags)
 {
        struct bpf_local_storage_data *old_sdata = NULL;
-       struct bpf_local_storage_elem *selem = NULL;
+       struct bpf_local_storage_elem *alloc_selem, *selem = NULL;
        struct bpf_local_storage *local_storage;
        unsigned long flags;
        int err;
@@ -607,11 +607,12 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
                }
        }
 
-       if (gfp_flags == GFP_KERNEL) {
-               selem = bpf_selem_alloc(smap, owner, value, true, gfp_flags);
-               if (!selem)
-                       return ERR_PTR(-ENOMEM);
-       }
+       /* A lookup has just been done before and concluded a new selem is
+        * needed. The chance of an unnecessary alloc is unlikely.
+        */
+       alloc_selem = selem = bpf_selem_alloc(smap, owner, value, true, gfp_flags);
+       if (!alloc_selem)
+               return ERR_PTR(-ENOMEM);
 
        raw_spin_lock_irqsave(&local_storage->lock, flags);
 
@@ -623,13 +624,13 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
                 * simple.
                 */
                err = -EAGAIN;
-               goto unlock_err;
+               goto unlock;
        }
 
        old_sdata = bpf_local_storage_lookup(local_storage, smap, false);
        err = check_flags(old_sdata, map_flags);
        if (err)
-               goto unlock_err;
+               goto unlock;
 
        if (old_sdata && (map_flags & BPF_F_LOCK)) {
                copy_map_value_locked(&smap->map, old_sdata->data, value,
@@ -638,23 +639,7 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
                goto unlock;
        }
 
-       if (gfp_flags != GFP_KERNEL) {
-               /* local_storage->lock is held.  Hence, we are sure
-                * we can unlink and uncharge the old_sdata successfully
-                * later.  Hence, instead of charging the new selem now
-                * and then uncharge the old selem later (which may cause
-                * a potential but unnecessary charge failure),  avoid taking
-                * a charge at all here (the "!old_sdata" check) and the
-                * old_sdata will not be uncharged later during
-                * bpf_selem_unlink_storage_nolock().
-                */
-               selem = bpf_selem_alloc(smap, owner, value, !old_sdata, gfp_flags);
-               if (!selem) {
-                       err = -ENOMEM;
-                       goto unlock_err;
-               }
-       }
-
+       alloc_selem = NULL;
        /* First, link the new selem to the map */
        bpf_selem_link_map(smap, selem);
 
@@ -665,20 +650,16 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
        if (old_sdata) {
                bpf_selem_unlink_map(SELEM(old_sdata));
                bpf_selem_unlink_storage_nolock(local_storage, SELEM(old_sdata),
-                                               false, false);
+                                               true, false);
        }
 
 unlock:
        raw_spin_unlock_irqrestore(&local_storage->lock, flags);
-       return SDATA(selem);
-
-unlock_err:
-       raw_spin_unlock_irqrestore(&local_storage->lock, flags);
-       if (selem) {
+       if (alloc_selem) {
                mem_uncharge(smap, owner, smap->elem_size);
-               bpf_selem_free(selem, smap, true);
+               bpf_selem_free(alloc_selem, smap, true);
        }
-       return ERR_PTR(err);
+       return err ? ERR_PTR(err) : SDATA(selem);
 }
 
 static u16 bpf_local_storage_cache_idx_get(struct bpf_local_storage_cache *cache)
@@ -779,7 +760,7 @@ void bpf_local_storage_destroy(struct bpf_local_storage *local_storage)
                 * of the loop will set the free_cgroup_storage to true.
                 */
                free_storage = bpf_selem_unlink_storage_nolock(
-                       local_storage, selem, false, true);
+                       local_storage, selem, true, true);
        }
        raw_spin_unlock_irqrestore(&local_storage->lock, flags);
 
index ebeb0695305a7a5b2df7bed6f40b415531b2c37f..eb01c31ed591dde57dc8463a7d701dc46132c8f7 100644 (file)
@@ -5502,9 +5502,9 @@ int kern_sys_bpf(int cmd, union bpf_attr *attr, unsigned int size)
                }
 
                run_ctx.bpf_cookie = 0;
-               run_ctx.saved_run_ctx = NULL;
                if (!__bpf_prog_enter_sleepable_recur(prog, &run_ctx)) {
                        /* recursion detected */
+                       __bpf_prog_exit_sleepable_recur(prog, 0, &run_ctx);
                        bpf_prog_put(prog);
                        return -EBUSY;
                }
index 78acf28d4873294e038c40d1a3ff873fce6319d1..53ff50cac61eaa5bf0aebe4425ced5b44d2086c7 100644 (file)
@@ -926,13 +926,12 @@ u64 notrace __bpf_prog_enter_sleepable_recur(struct bpf_prog *prog,
        migrate_disable();
        might_fault();
 
+       run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
+
        if (unlikely(this_cpu_inc_return(*(prog->active)) != 1)) {
                bpf_prog_inc_misses_counter(prog);
                return 0;
        }
-
-       run_ctx->saved_run_ctx = bpf_set_run_ctx(&run_ctx->run_ctx);
-
        return bpf_prog_start_time();
 }
 
index 57a7a64b84ede57b842c04a4adef34725858d5d2..0841f8d824198d0409d68aa178f2fba4d8ebb11d 100644 (file)
@@ -543,6 +543,7 @@ struct bpf_fentry_test_t {
 
 int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg)
 {
+       asm volatile ("");
        return (long)arg;
 }
 
index feaec4ad6d163d6c898f7e63671a3e264bb2cd1b..b28c976f52a0a16e13e23aee7c6fe4a7a8c844af 100644 (file)
@@ -974,6 +974,7 @@ static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
        struct sock_exterr_skb *serr;
        struct sk_buff *skb;
        char *state = "UNK";
+       u32 tsflags;
        int err;
 
        jsk = j1939_sk(sk);
@@ -981,13 +982,14 @@ static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
        if (!(jsk->state & J1939_SOCK_ERRQUEUE))
                return;
 
+       tsflags = READ_ONCE(sk->sk_tsflags);
        switch (type) {
        case J1939_ERRQUEUE_TX_ACK:
-               if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK))
+               if (!(tsflags & SOF_TIMESTAMPING_TX_ACK))
                        return;
                break;
        case J1939_ERRQUEUE_TX_SCHED:
-               if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED))
+               if (!(tsflags & SOF_TIMESTAMPING_TX_SCHED))
                        return;
                break;
        case J1939_ERRQUEUE_TX_ABORT:
@@ -997,7 +999,7 @@ static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
        case J1939_ERRQUEUE_RX_DPO:
                fallthrough;
        case J1939_ERRQUEUE_RX_ABORT:
-               if (!(sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE))
+               if (!(tsflags & SOF_TIMESTAMPING_RX_SOFTWARE))
                        return;
                break;
        default:
@@ -1054,7 +1056,7 @@ static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
        }
 
        serr->opt_stats = true;
-       if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
+       if (tsflags & SOF_TIMESTAMPING_OPT_ID)
                serr->ee.ee_data = session->tskey;
 
        netdev_dbg(session->priv->ndev, "%s: 0x%p tskey: %i, state: %s\n",
index 89d15ceaf9afd40cbcb4e2dbf8ab0f9bff14c7d8..b3b3af0e78448ad399489f670a642eba12f8020c 100644 (file)
@@ -1831,8 +1831,7 @@ u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
 
        memset(&keys, 0, sizeof(keys));
        __skb_flow_dissect(NULL, skb, &flow_keys_dissector_symmetric,
-                          &keys, NULL, 0, 0, 0,
-                          FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
+                          &keys, NULL, 0, 0, 0, 0);
 
        return __flow_hash_from_keys(&keys, &hashrnd);
 }
index 45707059082f2d706a9820f4484d0d4636aaa930..4eaf7ed0d1f44e8305109da2da2835013786a857 100644 (file)
@@ -550,7 +550,7 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node,
                             bool *pfmemalloc)
 {
        bool ret_pfmemalloc = false;
-       unsigned int obj_size;
+       size_t obj_size;
        void *obj;
 
        obj_size = SKB_HEAD_ALIGN(*size);
@@ -567,7 +567,13 @@ static void *kmalloc_reserve(unsigned int *size, gfp_t flags, int node,
                obj = kmem_cache_alloc_node(skb_small_head_cache, flags, node);
                goto out;
        }
-       *size = obj_size = kmalloc_size_roundup(obj_size);
+
+       obj_size = kmalloc_size_roundup(obj_size);
+       /* The following cast might truncate high-order bits of obj_size, this
+        * is harmless because kmalloc(obj_size >= 2^32) will fail anyway.
+        */
+       *size = (unsigned int)obj_size;
+
        /*
         * Try a regular allocation, when that fails and we're not entitled
         * to the reserves, fail.
@@ -4423,21 +4429,20 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
        struct sk_buff *segs = NULL;
        struct sk_buff *tail = NULL;
        struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list;
-       skb_frag_t *frag = skb_shinfo(head_skb)->frags;
        unsigned int mss = skb_shinfo(head_skb)->gso_size;
        unsigned int doffset = head_skb->data - skb_mac_header(head_skb);
-       struct sk_buff *frag_skb = head_skb;
        unsigned int offset = doffset;
        unsigned int tnl_hlen = skb_tnl_header_len(head_skb);
        unsigned int partial_segs = 0;
        unsigned int headroom;
        unsigned int len = head_skb->len;
+       struct sk_buff *frag_skb;
+       skb_frag_t *frag;
        __be16 proto;
        bool csum, sg;
-       int nfrags = skb_shinfo(head_skb)->nr_frags;
        int err = -ENOMEM;
        int i = 0;
-       int pos;
+       int nfrags, pos;
 
        if ((skb_shinfo(head_skb)->gso_type & SKB_GSO_DODGY) &&
            mss != GSO_BY_FRAGS && mss != skb_headlen(head_skb)) {
@@ -4514,6 +4519,13 @@ normal:
        headroom = skb_headroom(head_skb);
        pos = skb_headlen(head_skb);
 
+       if (skb_orphan_frags(head_skb, GFP_ATOMIC))
+               return ERR_PTR(-ENOMEM);
+
+       nfrags = skb_shinfo(head_skb)->nr_frags;
+       frag = skb_shinfo(head_skb)->frags;
+       frag_skb = head_skb;
+
        do {
                struct sk_buff *nskb;
                skb_frag_t *nskb_frag;
@@ -4534,6 +4546,10 @@ normal:
                    (skb_headlen(list_skb) == len || sg)) {
                        BUG_ON(skb_headlen(list_skb) > len);
 
+                       nskb = skb_clone(list_skb, GFP_ATOMIC);
+                       if (unlikely(!nskb))
+                               goto err;
+
                        i = 0;
                        nfrags = skb_shinfo(list_skb)->nr_frags;
                        frag = skb_shinfo(list_skb)->frags;
@@ -4552,12 +4568,8 @@ normal:
                                frag++;
                        }
 
-                       nskb = skb_clone(list_skb, GFP_ATOMIC);
                        list_skb = list_skb->next;
 
-                       if (unlikely(!nskb))
-                               goto err;
-
                        if (unlikely(pskb_trim(nskb, len))) {
                                kfree_skb(nskb);
                                goto err;
@@ -4633,12 +4645,16 @@ normal:
                skb_shinfo(nskb)->flags |= skb_shinfo(head_skb)->flags &
                                           SKBFL_SHARED_FRAG;
 
-               if (skb_orphan_frags(frag_skb, GFP_ATOMIC) ||
-                   skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC))
+               if (skb_zerocopy_clone(nskb, frag_skb, GFP_ATOMIC))
                        goto err;
 
                while (pos < offset + len) {
                        if (i >= nfrags) {
+                               if (skb_orphan_frags(list_skb, GFP_ATOMIC) ||
+                                   skb_zerocopy_clone(nskb, list_skb,
+                                                      GFP_ATOMIC))
+                                       goto err;
+
                                i = 0;
                                nfrags = skb_shinfo(list_skb)->nr_frags;
                                frag = skb_shinfo(list_skb)->frags;
@@ -4652,10 +4668,6 @@ normal:
                                        i--;
                                        frag--;
                                }
-                               if (skb_orphan_frags(frag_skb, GFP_ATOMIC) ||
-                                   skb_zerocopy_clone(nskb, frag_skb,
-                                                      GFP_ATOMIC))
-                                       goto err;
 
                                list_skb = list_skb->next;
                        }
@@ -5207,7 +5219,7 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
        serr->ee.ee_info = tstype;
        serr->opt_stats = opt_stats;
        serr->header.h4.iif = skb->dev ? skb->dev->ifindex : 0;
-       if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) {
+       if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID) {
                serr->ee.ee_data = skb_shinfo(skb)->tskey;
                if (sk_is_tcp(sk))
                        serr->ee.ee_data -= atomic_read(&sk->sk_tskey);
@@ -5263,21 +5275,23 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb,
 {
        struct sk_buff *skb;
        bool tsonly, opt_stats = false;
+       u32 tsflags;
 
        if (!sk)
                return;
 
-       if (!hwtstamps && !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TX_SWHW) &&
+       tsflags = READ_ONCE(sk->sk_tsflags);
+       if (!hwtstamps && !(tsflags & SOF_TIMESTAMPING_OPT_TX_SWHW) &&
            skb_shinfo(orig_skb)->tx_flags & SKBTX_IN_PROGRESS)
                return;
 
-       tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
+       tsonly = tsflags & SOF_TIMESTAMPING_OPT_TSONLY;
        if (!skb_may_tx_timestamp(sk, tsonly))
                return;
 
        if (tsonly) {
 #ifdef CONFIG_INET
-               if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_STATS) &&
+               if ((tsflags & SOF_TIMESTAMPING_OPT_STATS) &&
                    sk_is_tcp(sk)) {
                        skb = tcp_get_timestamping_opt_stats(sk, orig_skb,
                                                             ack_skb);
index a0659fc29bcca4eb3a2e1344a72b5033664115b4..6c31eefbd77786ba3651f79313af867883210654 100644 (file)
@@ -612,12 +612,18 @@ static int sk_psock_skb_ingress_self(struct sk_psock *psock, struct sk_buff *skb
 static int sk_psock_handle_skb(struct sk_psock *psock, struct sk_buff *skb,
                               u32 off, u32 len, bool ingress)
 {
+       int err = 0;
+
        if (!ingress) {
                if (!sock_writeable(psock->sk))
                        return -EAGAIN;
                return skb_send_sock(psock->sk, skb, off, len);
        }
-       return sk_psock_skb_ingress(psock, skb, off, len);
+       skb_get(skb);
+       err = sk_psock_skb_ingress(psock, skb, off, len);
+       if (err < 0)
+               kfree_skb(skb);
+       return err;
 }
 
 static void sk_psock_skb_state(struct sk_psock *psock,
@@ -685,9 +691,7 @@ static void sk_psock_backlog(struct work_struct *work)
                } while (len);
 
                skb = skb_dequeue(&psock->ingress_skb);
-               if (!ingress) {
-                       kfree_skb(skb);
-               }
+               kfree_skb(skb);
        }
 end:
        mutex_unlock(&psock->work_mutex);
index 666a17cab4f5605076af3f929864d03bc5e90058..16584e2dd6481a3fc28d796db785439f0446703b 100644 (file)
@@ -765,7 +765,8 @@ bool sk_mc_loop(struct sock *sk)
                return false;
        if (!sk)
                return true;
-       switch (sk->sk_family) {
+       /* IPV6_ADDRFORM can change sk->sk_family under us. */
+       switch (READ_ONCE(sk->sk_family)) {
        case AF_INET:
                return inet_test_bit(MC_LOOP, sk);
 #if IS_ENABLED(CONFIG_IPV6)
@@ -893,7 +894,7 @@ static int sock_timestamping_bind_phc(struct sock *sk, int phc_index)
        if (!match)
                return -EINVAL;
 
-       sk->sk_bind_phc = phc_index;
+       WRITE_ONCE(sk->sk_bind_phc, phc_index);
 
        return 0;
 }
@@ -936,7 +937,7 @@ int sock_set_timestamping(struct sock *sk, int optname,
                        return ret;
        }
 
-       sk->sk_tsflags = val;
+       WRITE_ONCE(sk->sk_tsflags, val);
        sock_valbool_flag(sk, SOCK_TSTAMP_NEW, optname == SO_TIMESTAMPING_NEW);
 
        if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
@@ -1044,7 +1045,7 @@ static int sock_reserve_memory(struct sock *sk, int bytes)
                mem_cgroup_uncharge_skmem(sk->sk_memcg, pages);
                return -ENOMEM;
        }
-       sk->sk_forward_alloc += pages << PAGE_SHIFT;
+       sk_forward_alloc_add(sk, pages << PAGE_SHIFT);
 
        WRITE_ONCE(sk->sk_reserved_mem,
                   sk->sk_reserved_mem + (pages << PAGE_SHIFT));
@@ -1718,8 +1719,8 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
 
        case SO_TIMESTAMPING_OLD:
                lv = sizeof(v.timestamping);
-               v.timestamping.flags = sk->sk_tsflags;
-               v.timestamping.bind_phc = sk->sk_bind_phc;
+               v.timestamping.flags = READ_ONCE(sk->sk_tsflags);
+               v.timestamping.bind_phc = READ_ONCE(sk->sk_bind_phc);
                break;
 
        case SO_RCVTIMEO_OLD:
@@ -2746,9 +2747,9 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
                prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
                if (refcount_read(&sk->sk_wmem_alloc) < READ_ONCE(sk->sk_sndbuf))
                        break;
-               if (sk->sk_shutdown & SEND_SHUTDOWN)
+               if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN)
                        break;
-               if (sk->sk_err)
+               if (READ_ONCE(sk->sk_err))
                        break;
                timeo = schedule_timeout(timeo);
        }
@@ -2776,7 +2777,7 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
                        goto failure;
 
                err = -EPIPE;
-               if (sk->sk_shutdown & SEND_SHUTDOWN)
+               if (READ_ONCE(sk->sk_shutdown) & SEND_SHUTDOWN)
                        goto failure;
 
                if (sk_wmem_alloc_get(sk) < READ_ONCE(sk->sk_sndbuf))
@@ -3138,10 +3139,10 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind)
 {
        int ret, amt = sk_mem_pages(size);
 
-       sk->sk_forward_alloc += amt << PAGE_SHIFT;
+       sk_forward_alloc_add(sk, amt << PAGE_SHIFT);
        ret = __sk_mem_raise_allocated(sk, size, amt, kind);
        if (!ret)
-               sk->sk_forward_alloc -= amt << PAGE_SHIFT;
+               sk_forward_alloc_add(sk, -(amt << PAGE_SHIFT));
        return ret;
 }
 EXPORT_SYMBOL(__sk_mem_schedule);
@@ -3173,7 +3174,7 @@ void __sk_mem_reduce_allocated(struct sock *sk, int amount)
 void __sk_mem_reclaim(struct sock *sk, int amount)
 {
        amount >>= PAGE_SHIFT;
-       sk->sk_forward_alloc -= amount << PAGE_SHIFT;
+       sk_forward_alloc_add(sk, -(amount << PAGE_SHIFT));
        __sk_mem_reduce_allocated(sk, amount);
 }
 EXPORT_SYMBOL(__sk_mem_reclaim);
@@ -3742,7 +3743,7 @@ void sk_get_meminfo(const struct sock *sk, u32 *mem)
        mem[SK_MEMINFO_RCVBUF] = READ_ONCE(sk->sk_rcvbuf);
        mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk);
        mem[SK_MEMINFO_SNDBUF] = READ_ONCE(sk->sk_sndbuf);
-       mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
+       mem[SK_MEMINFO_FWD_ALLOC] = sk_forward_alloc_get(sk);
        mem[SK_MEMINFO_WMEM_QUEUED] = READ_ONCE(sk->sk_wmem_queued);
        mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
        mem[SK_MEMINFO_BACKLOG] = READ_ONCE(sk->sk_backlog.len);
index 8f07fea39d9ea471adc141a8ab2de395de59cd72..cb11750b1df5fc49043333a2d89cc6d18dba06b9 100644 (file)
@@ -18,7 +18,7 @@ struct bpf_stab {
        struct bpf_map map;
        struct sock **sks;
        struct sk_psock_progs progs;
-       raw_spinlock_t lock;
+       spinlock_t lock;
 };
 
 #define SOCK_CREATE_FLAG_MASK                          \
@@ -44,7 +44,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
                return ERR_PTR(-ENOMEM);
 
        bpf_map_init_from_attr(&stab->map, attr);
-       raw_spin_lock_init(&stab->lock);
+       spin_lock_init(&stab->lock);
 
        stab->sks = bpf_map_area_alloc((u64) stab->map.max_entries *
                                       sizeof(struct sock *),
@@ -411,7 +411,7 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,
        struct sock *sk;
        int err = 0;
 
-       raw_spin_lock_bh(&stab->lock);
+       spin_lock_bh(&stab->lock);
        sk = *psk;
        if (!sk_test || sk_test == sk)
                sk = xchg(psk, NULL);
@@ -421,7 +421,7 @@ static int __sock_map_delete(struct bpf_stab *stab, struct sock *sk_test,
        else
                err = -EINVAL;
 
-       raw_spin_unlock_bh(&stab->lock);
+       spin_unlock_bh(&stab->lock);
        return err;
 }
 
@@ -487,7 +487,7 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
        psock = sk_psock(sk);
        WARN_ON_ONCE(!psock);
 
-       raw_spin_lock_bh(&stab->lock);
+       spin_lock_bh(&stab->lock);
        osk = stab->sks[idx];
        if (osk && flags == BPF_NOEXIST) {
                ret = -EEXIST;
@@ -501,10 +501,10 @@ static int sock_map_update_common(struct bpf_map *map, u32 idx,
        stab->sks[idx] = sk;
        if (osk)
                sock_map_unref(osk, &stab->sks[idx]);
-       raw_spin_unlock_bh(&stab->lock);
+       spin_unlock_bh(&stab->lock);
        return 0;
 out_unlock:
-       raw_spin_unlock_bh(&stab->lock);
+       spin_unlock_bh(&stab->lock);
        if (psock)
                sk_psock_put(sk, psock);
 out_free:
@@ -835,7 +835,7 @@ struct bpf_shtab_elem {
 
 struct bpf_shtab_bucket {
        struct hlist_head head;
-       raw_spinlock_t lock;
+       spinlock_t lock;
 };
 
 struct bpf_shtab {
@@ -910,7 +910,7 @@ static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,
         * is okay since it's going away only after RCU grace period.
         * However, we need to check whether it's still present.
         */
-       raw_spin_lock_bh(&bucket->lock);
+       spin_lock_bh(&bucket->lock);
        elem_probe = sock_hash_lookup_elem_raw(&bucket->head, elem->hash,
                                               elem->key, map->key_size);
        if (elem_probe && elem_probe == elem) {
@@ -918,7 +918,7 @@ static void sock_hash_delete_from_link(struct bpf_map *map, struct sock *sk,
                sock_map_unref(elem->sk, elem);
                sock_hash_free_elem(htab, elem);
        }
-       raw_spin_unlock_bh(&bucket->lock);
+       spin_unlock_bh(&bucket->lock);
 }
 
 static long sock_hash_delete_elem(struct bpf_map *map, void *key)
@@ -932,7 +932,7 @@ static long sock_hash_delete_elem(struct bpf_map *map, void *key)
        hash = sock_hash_bucket_hash(key, key_size);
        bucket = sock_hash_select_bucket(htab, hash);
 
-       raw_spin_lock_bh(&bucket->lock);
+       spin_lock_bh(&bucket->lock);
        elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size);
        if (elem) {
                hlist_del_rcu(&elem->node);
@@ -940,7 +940,7 @@ static long sock_hash_delete_elem(struct bpf_map *map, void *key)
                sock_hash_free_elem(htab, elem);
                ret = 0;
        }
-       raw_spin_unlock_bh(&bucket->lock);
+       spin_unlock_bh(&bucket->lock);
        return ret;
 }
 
@@ -1000,7 +1000,7 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
        hash = sock_hash_bucket_hash(key, key_size);
        bucket = sock_hash_select_bucket(htab, hash);
 
-       raw_spin_lock_bh(&bucket->lock);
+       spin_lock_bh(&bucket->lock);
        elem = sock_hash_lookup_elem_raw(&bucket->head, hash, key, key_size);
        if (elem && flags == BPF_NOEXIST) {
                ret = -EEXIST;
@@ -1026,10 +1026,10 @@ static int sock_hash_update_common(struct bpf_map *map, void *key,
                sock_map_unref(elem->sk, elem);
                sock_hash_free_elem(htab, elem);
        }
-       raw_spin_unlock_bh(&bucket->lock);
+       spin_unlock_bh(&bucket->lock);
        return 0;
 out_unlock:
-       raw_spin_unlock_bh(&bucket->lock);
+       spin_unlock_bh(&bucket->lock);
        sk_psock_put(sk, psock);
 out_free:
        sk_psock_free_link(link);
@@ -1115,7 +1115,7 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr)
 
        for (i = 0; i < htab->buckets_num; i++) {
                INIT_HLIST_HEAD(&htab->buckets[i].head);
-               raw_spin_lock_init(&htab->buckets[i].lock);
+               spin_lock_init(&htab->buckets[i].lock);
        }
 
        return &htab->map;
@@ -1147,11 +1147,11 @@ static void sock_hash_free(struct bpf_map *map)
                 * exists, psock exists and holds a ref to socket. That
                 * lets us to grab a socket ref too.
                 */
-               raw_spin_lock_bh(&bucket->lock);
+               spin_lock_bh(&bucket->lock);
                hlist_for_each_entry(elem, &bucket->head, node)
                        sock_hold(elem->sk);
                hlist_move_list(&bucket->head, &unlink_list);
-               raw_spin_unlock_bh(&bucket->lock);
+               spin_unlock_bh(&bucket->lock);
 
                /* Process removed entries out of atomic context to
                 * block for socket lock before deleting the psock's
index 1086653e1fada1724f98ccbc81fbcf7741ef9bc9..d0bc1dd8e65a8201751fddcc2356da89cd2c65e7 100644 (file)
@@ -157,26 +157,24 @@ out_status:
 int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info)
 {
        struct net *net = sock_net(skb->sk);
-       struct handshake_req *req = NULL;
-       struct socket *sock = NULL;
+       struct handshake_req *req;
+       struct socket *sock;
        int fd, status, err;
 
        if (GENL_REQ_ATTR_CHECK(info, HANDSHAKE_A_DONE_SOCKFD))
                return -EINVAL;
        fd = nla_get_u32(info->attrs[HANDSHAKE_A_DONE_SOCKFD]);
 
-       err = 0;
        sock = sockfd_lookup(fd, &err);
-       if (err) {
-               err = -EBADF;
-               goto out_status;
-       }
+       if (!sock)
+               return err;
 
        req = handshake_req_hash_lookup(sock->sk);
        if (!req) {
                err = -EBUSY;
+               trace_handshake_cmd_done_err(net, req, sock->sk, err);
                fput(sock->file);
-               goto out_status;
+               return err;
        }
 
        trace_handshake_cmd_done(net, req, sock->sk, fd);
@@ -188,10 +186,6 @@ int handshake_nl_done_doit(struct sk_buff *skb, struct genl_info *info)
        handshake_complete(req, status, info);
        fput(sock->file);
        return 0;
-
-out_status:
-       trace_handshake_cmd_done_err(net, req, sock->sk, err);
-       return err;
 }
 
 static unsigned int handshake_net_id;
index 65ba18a91865ae9a9bd850052811509b8fb3a79b..eafa4a033515782b4ade9a81ec12cb22f5e51e35 100644 (file)
@@ -278,7 +278,8 @@ void fib_release_info(struct fib_info *fi)
                                hlist_del(&nexthop_nh->nh_hash);
                        } endfor_nexthops(fi)
                }
-               fi->fib_dead = 1;
+               /* Paired with READ_ONCE() from fib_table_lookup() */
+               WRITE_ONCE(fi->fib_dead, 1);
                fib_info_put(fi);
        }
        spin_unlock_bh(&fib_info_lock);
@@ -1581,6 +1582,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
 link_it:
        ofi = fib_find_info(fi);
        if (ofi) {
+               /* fib_table_lookup() should not see @fi yet. */
                fi->fib_dead = 1;
                free_fib_info(fi);
                refcount_inc(&ofi->fib_treeref);
@@ -1619,6 +1621,7 @@ err_inval:
 
 failure:
        if (fi) {
+               /* fib_table_lookup() should not see @fi yet. */
                fi->fib_dead = 1;
                free_fib_info(fi);
        }
index 74d403dbd2b4e6128dacd1bfc3579a1fc3d635aa..d13fb9e76b9718c674b82ea9069f98fb29f06425 100644 (file)
@@ -1582,7 +1582,8 @@ found:
                if (fa->fa_dscp &&
                    inet_dscp_to_dsfield(fa->fa_dscp) != flp->flowi4_tos)
                        continue;
-               if (fi->fib_dead)
+               /* Paired with WRITE_ONCE() in fib_release_info() */
+               if (READ_ONCE(fi->fib_dead))
                        continue;
                if (fa->fa_info->fib_scope < flp->flowi4_scope)
                        continue;
index 0c9e768e5628b1c8fd7e87bebe528762ea4a6e1e..418e5fb58fd3f2443f3c88fde5c0776805a832ef 100644 (file)
@@ -353,8 +353,9 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu)
        struct flowi4 fl4;
        int hlen = LL_RESERVED_SPACE(dev);
        int tlen = dev->needed_tailroom;
-       unsigned int size = mtu;
+       unsigned int size;
 
+       size = min(mtu, IP_MAX_MTU);
        while (1) {
                skb = alloc_skb(size + hlen + tlen,
                                GFP_ATOMIC | __GFP_NOWARN);
index e18931a6d15341d7115e608d614b16ad93f91273..66fac1216d467a5709e8048f4ea9d4172ba85f67 100644 (file)
@@ -67,7 +67,6 @@ static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *s
        struct ip_options *opt  = &(IPCB(skb)->opt);
 
        __IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS);
-       __IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len);
 
 #ifdef CONFIG_NET_SWITCHDEV
        if (skb->offload_l3_fwd_mark) {
index fe9ead9ee863d6d7da1ac78643e9527ae5ddff1e..5e9c8156656a7642acc7a1bb08488b7482e52ce7 100644 (file)
@@ -584,7 +584,8 @@ static void ip_sublist_rcv_finish(struct list_head *head)
 static struct sk_buff *ip_extract_route_hint(const struct net *net,
                                             struct sk_buff *skb, int rt_type)
 {
-       if (fib4_has_custom_rules(net) || rt_type == RTN_BROADCAST)
+       if (fib4_has_custom_rules(net) || rt_type == RTN_BROADCAST ||
+           IPCB(skb)->flags & IPSKB_MULTIPATH)
                return NULL;
 
        return skb;
index 43ba4b77b2484a38031a919c9be29eba9af3f031..4ab877cf6d35f229761986d5c6a17eb2a3ad4043 100644 (file)
@@ -207,6 +207,9 @@ static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *s
        } else if (rt->rt_type == RTN_BROADCAST)
                IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len);
 
+       /* OUTOCTETS should be counted after fragment */
+       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
+
        if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
                skb = skb_expand_head(skb, hh_len);
                if (!skb)
@@ -366,8 +369,6 @@ int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        /*
         *      If the indicated interface is up and running, send the packet.
         */
-       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
-
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
@@ -424,8 +425,6 @@ int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
        struct net_device *dev = skb_dst(skb)->dev, *indev = skb->dev;
 
-       IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
-
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
@@ -982,7 +981,7 @@ static int __ip_append_data(struct sock *sk,
        paged = !!cork->gso_size;
 
        if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
-           sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
+           READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
                tskey = atomic_inc_return(&sk->sk_tskey) - 1;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
index d1c73660b844949b57960630e0467112da4f0abd..cce9cb25f3b31cd57fa883ae0dedb6829d8da2fa 100644 (file)
@@ -511,7 +511,7 @@ static bool ipv4_datagram_support_cmsg(const struct sock *sk,
         * or without payload (SOF_TIMESTAMPING_OPT_TSONLY).
         */
        info = PKTINFO_SKB_CB(skb);
-       if (!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG) ||
+       if (!(READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_CMSG) ||
            !info->ipi_ifindex)
                return false;
 
index 3f0c6d602fb7760ea01b07e8f81592ee0eceb4a1..9e222a57bc2b47a2f89ca068fc5b5f4217df3725 100644 (file)
@@ -1804,7 +1804,6 @@ static inline int ipmr_forward_finish(struct net *net, struct sock *sk,
        struct ip_options *opt = &(IPCB(skb)->opt);
 
        IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS);
-       IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len);
 
        if (unlikely(opt->optlen))
                ip_forward_options(skb);
index d8c99bdc617061b4790f87dce138348ae4cfa3c7..66f419e7f9a7f3cab5328abb8c374686dccd2f19 100644 (file)
@@ -2144,6 +2144,7 @@ static int ip_mkroute_input(struct sk_buff *skb,
                int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys);
 
                fib_select_multipath(res, h);
+               IPCB(skb)->flags |= IPSKB_MULTIPATH;
        }
 #endif
 
index b1559481898de4555869428e28cf5d8f1872e0b0..0c3040a63ebdb15be2c60532e2bdfc3d0fc51a9c 100644 (file)
@@ -2256,14 +2256,14 @@ void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk,
                        }
                }
 
-               if (sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE)
+               if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_SOFTWARE)
                        has_timestamping = true;
                else
                        tss->ts[0] = (struct timespec64) {0};
        }
 
        if (tss->ts[2].tv_sec || tss->ts[2].tv_nsec) {
-               if (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)
+               if (READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_RAW_HARDWARE)
                        has_timestamping = true;
                else
                        tss->ts[2] = (struct timespec64) {0};
index e6b4fbd642f7e4e3c986fef54e416628c8981aff..ccfc8bbf745586cd23dcf02d755d6981dc92742e 100644 (file)
@@ -3474,7 +3474,7 @@ void sk_forced_mem_schedule(struct sock *sk, int size)
        if (delta <= 0)
                return;
        amt = sk_mem_pages(delta);
-       sk->sk_forward_alloc += amt << PAGE_SHIFT;
+       sk_forward_alloc_add(sk, amt << PAGE_SHIFT);
        sk_memory_allocated_add(sk, amt);
 
        if (mem_cgroup_sockets_enabled && sk->sk_memcg)
index 0794a2c46a568d644cc488c1d7f6ee676180a5bd..f39b9c8445808deee2c777cbb828474ff105d322 100644 (file)
@@ -1414,9 +1414,9 @@ static void udp_rmem_release(struct sock *sk, int size, int partial,
                spin_lock(&sk_queue->lock);
 
 
-       sk->sk_forward_alloc += size;
+       sk_forward_alloc_add(sk, size);
        amt = (sk->sk_forward_alloc - partial) & ~(PAGE_SIZE - 1);
-       sk->sk_forward_alloc -= amt;
+       sk_forward_alloc_add(sk, -amt);
 
        if (amt)
                __sk_mem_reduce_allocated(sk, amt >> PAGE_SHIFT);
@@ -1527,7 +1527,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
                goto uncharge_drop;
        }
 
-       sk->sk_forward_alloc -= size;
+       sk_forward_alloc_add(sk, -size);
 
        /* no need to setup a destructor, we will explicitly release the
         * forward allocated memory on dequeue
index 967913ad65e54ae3cd63925dbc5846bfb040c850..0b6ee962c84e27906a1bc0dcd01d7088abb44cb2 100644 (file)
@@ -1378,7 +1378,7 @@ retry:
         * idev->desync_factor if it's larger
         */
        cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft);
-       max_desync_factor = min_t(__u32,
+       max_desync_factor = min_t(long,
                                  idev->cnf.max_desync_factor,
                                  cnf_temp_preferred_lft - regen_advance);
 
index d94041bb42872f02eaaa5bd2f64ae2301a8a48a4..b8378814532cead0275e8b7a656f78450993f619 100644 (file)
@@ -99,7 +99,8 @@ static bool ip6_can_use_hint(const struct sk_buff *skb,
 static struct sk_buff *ip6_extract_route_hint(const struct net *net,
                                              struct sk_buff *skb)
 {
-       if (fib6_routes_require_src(net) || fib6_has_custom_rules(net))
+       if (fib6_routes_require_src(net) || fib6_has_custom_rules(net) ||
+           IP6CB(skb)->flags & IP6SKB_MULTIPATH)
                return NULL;
 
        return skb;
index 0665e8b099680c9bea605da25b06a3d03ced1c78..54fc4c711f2c545f2ca625d6b0e09f2bb8e6d513 100644 (file)
@@ -451,7 +451,6 @@ static inline int ip6_forward_finish(struct net *net, struct sock *sk,
        struct dst_entry *dst = skb_dst(skb);
 
        __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
-       __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
 
 #ifdef CONFIG_NET_SWITCHDEV
        if (skb->offload_l3_fwd_mark) {
@@ -1502,7 +1501,7 @@ static int __ip6_append_data(struct sock *sk,
        orig_mtu = mtu;
 
        if (cork->tx_flags & SKBTX_ANY_TSTAMP &&
-           sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
+           READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_OPT_ID)
                tskey = atomic_inc_return(&sk->sk_tskey) - 1;
 
        hh_len = LL_RESERVED_SPACE(rt->dst.dev);
index 67a3b8f6e72b115e8fae07d7c7d358a7ac1659a5..30ca064b76ef1798d249fa4266bef34668d6a811 100644 (file)
@@ -2010,8 +2010,6 @@ static inline int ip6mr_forward2_finish(struct net *net, struct sock *sk, struct
 {
        IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
                      IPSTATS_MIB_OUTFORWDATAGRAMS);
-       IP6_ADD_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                     IPSTATS_MIB_OUTOCTETS, skb->len);
        return dst_output(net, sk, skb);
 }
 
index 1b27728349725e212ab5d988dd96cf87464c9531..5831aaa53d75eae7b764d54ab52da65db4030d73 100644 (file)
@@ -119,7 +119,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                return -EINVAL;
 
        ipcm6_init_sk(&ipc6, np);
-       ipc6.sockc.tsflags = sk->sk_tsflags;
+       ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
 
        fl6.flowi6_oif = oif;
index 0eae7661a85c4487a64384c6054a3fb827387ce7..42fcec3ecf5e171a5ebe724b8c971d90885abe41 100644 (file)
@@ -772,7 +772,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        fl6.flowi6_uid = sk->sk_uid;
 
        ipcm6_init(&ipc6);
-       ipc6.sockc.tsflags = sk->sk_tsflags;
+       ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = fl6.flowi6_mark;
 
        if (sin6) {
index d15a9e3aa24aedd386eb05498340400236870816..9c687b357e6a41dcbc1011d43766ab1fb0e55a39 100644 (file)
@@ -423,6 +423,9 @@ void fib6_select_path(const struct net *net, struct fib6_result *res,
        if (match->nh && have_oif_match && res->nh)
                return;
 
+       if (skb)
+               IP6CB(skb)->flags |= IP6SKB_MULTIPATH;
+
        /* We might have already computed the hash for ICMPv6 errors. In such
         * case it will always be non-zero. Otherwise now is the time to do it.
         */
index ebc6ae47cfeadc699e3f5a1f46be85803ff37fdd..86b5d509a4688cacb2f40667c9ddc10f81ade2fe 100644 (file)
@@ -1339,7 +1339,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
 
        ipcm6_init(&ipc6);
        ipc6.gso_size = READ_ONCE(up->gso_size);
-       ipc6.sockc.tsflags = sk->sk_tsflags;
+       ipc6.sockc.tsflags = READ_ONCE(sk->sk_tsflags);
        ipc6.sockc.mark = READ_ONCE(sk->sk_mark);
 
        /* destination address check */
index 393f01b2a7e6d4dbd47645d58e5d146548dacc16..4580f61426bb8523638840069a50304994a873bf 100644 (file)
@@ -1859,6 +1859,8 @@ static __net_exit void kcm_exit_net(struct net *net)
         * that all multiplexors and psocks have been destroyed.
         */
        WARN_ON(!list_empty(&knet->mux_list));
+
+       mutex_destroy(&knet->mutex);
 }
 
 static struct pernet_operations kcm_net_ops = {
index 933b257eee0242d9864ca9202cea69f2592663be..a7fc16f5175d22a4e741c79edd84f1ea72c676bc 100644 (file)
@@ -134,9 +134,15 @@ static void mptcp_drop(struct sock *sk, struct sk_buff *skb)
        __kfree_skb(skb);
 }
 
+static void mptcp_rmem_fwd_alloc_add(struct sock *sk, int size)
+{
+       WRITE_ONCE(mptcp_sk(sk)->rmem_fwd_alloc,
+                  mptcp_sk(sk)->rmem_fwd_alloc + size);
+}
+
 static void mptcp_rmem_charge(struct sock *sk, int size)
 {
-       mptcp_sk(sk)->rmem_fwd_alloc -= size;
+       mptcp_rmem_fwd_alloc_add(sk, -size);
 }
 
 static bool mptcp_try_coalesce(struct sock *sk, struct sk_buff *to,
@@ -177,7 +183,7 @@ static bool mptcp_ooo_try_coalesce(struct mptcp_sock *msk, struct sk_buff *to,
 static void __mptcp_rmem_reclaim(struct sock *sk, int amount)
 {
        amount >>= PAGE_SHIFT;
-       mptcp_sk(sk)->rmem_fwd_alloc -= amount << PAGE_SHIFT;
+       mptcp_rmem_charge(sk, amount << PAGE_SHIFT);
        __sk_mem_reduce_allocated(sk, amount);
 }
 
@@ -186,7 +192,7 @@ static void mptcp_rmem_uncharge(struct sock *sk, int size)
        struct mptcp_sock *msk = mptcp_sk(sk);
        int reclaimable;
 
-       msk->rmem_fwd_alloc += size;
+       mptcp_rmem_fwd_alloc_add(sk, size);
        reclaimable = msk->rmem_fwd_alloc - sk_unused_reserved_mem(sk);
 
        /* see sk_mem_uncharge() for the rationale behind the following schema */
@@ -341,7 +347,7 @@ static bool mptcp_rmem_schedule(struct sock *sk, struct sock *ssk, int size)
        if (!__sk_mem_raise_allocated(sk, size, amt, SK_MEM_RECV))
                return false;
 
-       msk->rmem_fwd_alloc += amount;
+       mptcp_rmem_fwd_alloc_add(sk, amount);
        return true;
 }
 
@@ -1800,7 +1806,7 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
                }
 
                /* data successfully copied into the write queue */
-               sk->sk_forward_alloc -= total_ts;
+               sk_forward_alloc_add(sk, -total_ts);
                copied += psize;
                dfrag->data_len += psize;
                frag_truesize += psize;
@@ -3257,8 +3263,8 @@ void mptcp_destroy_common(struct mptcp_sock *msk, unsigned int flags)
        /* move all the rx fwd alloc into the sk_mem_reclaim_final in
         * inet_sock_destruct() will dispose it
         */
-       sk->sk_forward_alloc += msk->rmem_fwd_alloc;
-       msk->rmem_fwd_alloc = 0;
+       sk_forward_alloc_add(sk, msk->rmem_fwd_alloc);
+       WRITE_ONCE(msk->rmem_fwd_alloc, 0);
        mptcp_token_destroy(msk);
        mptcp_pm_free_anno_list(msk);
        mptcp_free_local_addr_list(msk);
@@ -3522,7 +3528,8 @@ static void mptcp_shutdown(struct sock *sk, int how)
 
 static int mptcp_forward_alloc_get(const struct sock *sk)
 {
-       return sk->sk_forward_alloc + mptcp_sk(sk)->rmem_fwd_alloc;
+       return READ_ONCE(sk->sk_forward_alloc) +
+              READ_ONCE(mptcp_sk(sk)->rmem_fwd_alloc);
 }
 
 static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v)
index 005a7ce87217e24c292e27eddb03f1320fed4a6a..bf4f91b78e1dcb93288d4f87471a00ac0a4ae387 100644 (file)
@@ -36,6 +36,7 @@ MODULE_ALIAS("ip_set_hash:net,port,net");
 #define IP_SET_HASH_WITH_PROTO
 #define IP_SET_HASH_WITH_NETS
 #define IPSET_NET_COUNT 2
+#define IP_SET_HASH_WITH_NET0
 
 /* IPv4 variant */
 
index 41b826dff6f5cb8f7ccbfad843f970dcba97e090..e429ebba74b3d13b441f8130087e81153ee1032c 100644 (file)
@@ -102,6 +102,7 @@ static const u8 nft2audit_op[NFT_MSG_MAX] = { // enum nf_tables_msg_types
        [NFT_MSG_NEWFLOWTABLE]  = AUDIT_NFT_OP_FLOWTABLE_REGISTER,
        [NFT_MSG_GETFLOWTABLE]  = AUDIT_NFT_OP_INVALID,
        [NFT_MSG_DELFLOWTABLE]  = AUDIT_NFT_OP_FLOWTABLE_UNREGISTER,
+       [NFT_MSG_GETSETELEM_RESET] = AUDIT_NFT_OP_SETELEM_RESET,
 };
 
 static void nft_validate_state_update(struct nft_table *table, u8 new_validate_state)
@@ -3421,6 +3422,18 @@ err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
+static void audit_log_rule_reset(const struct nft_table *table,
+                                unsigned int base_seq,
+                                unsigned int nentries)
+{
+       char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
+                             table->name, base_seq);
+
+       audit_log_nfcfg(buf, table->family, nentries,
+                       AUDIT_NFT_OP_RULE_RESET, GFP_ATOMIC);
+       kfree(buf);
+}
+
 struct nft_rule_dump_ctx {
        char *table;
        char *chain;
@@ -3467,6 +3480,10 @@ cont:
 cont_skip:
                (*idx)++;
        }
+
+       if (reset && *idx)
+               audit_log_rule_reset(table, cb->seq, *idx);
+
        return 0;
 }
 
@@ -3634,6 +3651,9 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
        if (err < 0)
                goto err_fill_rule_info;
 
+       if (reset)
+               audit_log_rule_reset(table, nft_pernet(net)->base_seq, 1);
+
        return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
 err_fill_rule_info:
@@ -5624,13 +5644,25 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
        return nf_tables_fill_setelem(args->skb, set, elem, args->reset);
 }
 
+static void audit_log_nft_set_reset(const struct nft_table *table,
+                                   unsigned int base_seq,
+                                   unsigned int nentries)
+{
+       char *buf = kasprintf(GFP_ATOMIC, "%s:%u", table->name, base_seq);
+
+       audit_log_nfcfg(buf, table->family, nentries,
+                       AUDIT_NFT_OP_SETELEM_RESET, GFP_ATOMIC);
+       kfree(buf);
+}
+
 struct nft_set_dump_ctx {
        const struct nft_set    *set;
        struct nft_ctx          ctx;
 };
 
 static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
-                                const struct nft_set *set, bool reset)
+                                const struct nft_set *set, bool reset,
+                                unsigned int base_seq)
 {
        struct nft_set_elem_catchall *catchall;
        u8 genmask = nft_genmask_cur(net);
@@ -5646,6 +5678,8 @@ static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
 
                elem.priv = catchall->elem;
                ret = nf_tables_fill_setelem(skb, set, &elem, reset);
+               if (reset && !ret)
+                       audit_log_nft_set_reset(set->table, base_seq, 1);
                break;
        }
 
@@ -5725,12 +5759,17 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        set->ops->walk(&dump_ctx->ctx, set, &args.iter);
 
        if (!args.iter.err && args.iter.count == cb->args[0])
-               args.iter.err = nft_set_catchall_dump(net, skb, set, reset);
-       rcu_read_unlock();
-
+               args.iter.err = nft_set_catchall_dump(net, skb, set,
+                                                     reset, cb->seq);
        nla_nest_end(skb, nest);
        nlmsg_end(skb, nlh);
 
+       if (reset && args.iter.count > args.iter.skip)
+               audit_log_nft_set_reset(table, cb->seq,
+                                       args.iter.count - args.iter.skip);
+
+       rcu_read_unlock();
+
        if (args.iter.err && args.iter.err != -EMSGSIZE)
                return args.iter.err;
        if (args.iter.count == cb->args[0])
@@ -5955,13 +5994,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
        struct netlink_ext_ack *extack = info->extack;
        u8 genmask = nft_genmask_cur(info->net);
        u8 family = info->nfmsg->nfgen_family;
+       int rem, err = 0, nelems = 0;
        struct net *net = info->net;
        struct nft_table *table;
        struct nft_set *set;
        struct nlattr *attr;
        struct nft_ctx ctx;
        bool reset = false;
-       int rem, err = 0;
 
        table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
                                 genmask, 0);
@@ -6004,8 +6043,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
                        NL_SET_BAD_ATTR(extack, attr);
                        break;
                }
+               nelems++;
        }
 
+       if (reset)
+               audit_log_nft_set_reset(table, nft_pernet(net)->base_seq,
+                                       nelems);
+
        return err;
 }
 
index 8f1bfa6ccc2d9a09ab4a6132cd9b7df777316cd9..50723ba0828905737c71dd842be39e28e039218e 100644 (file)
@@ -315,6 +315,14 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,
 
        f = nla_data(osf_attrs[OSF_ATTR_FINGER]);
 
+       if (f->opt_num > ARRAY_SIZE(f->opt))
+               return -EINVAL;
+
+       if (!memchr(f->genre, 0, MAXGENRELEN) ||
+           !memchr(f->subtype, 0, MAXGENRELEN) ||
+           !memchr(f->version, 0, MAXGENRELEN))
+               return -EINVAL;
+
        kf = kmalloc(sizeof(struct nf_osf_finger), GFP_KERNEL);
        if (!kf)
                return -ENOMEM;
index 7f856ceb3a668268205882643b39f56aa2588f97..3fbaa7bf41f9c74956c826ee63797406bff9f297 100644 (file)
@@ -35,6 +35,14 @@ static unsigned int optlen(const u8 *opt, unsigned int offset)
                return opt[offset + 1];
 }
 
+static int nft_skb_copy_to_reg(const struct sk_buff *skb, int offset, u32 *dest, unsigned int len)
+{
+       if (len % NFT_REG32_SIZE)
+               dest[len / NFT_REG32_SIZE] = 0;
+
+       return skb_copy_bits(skb, offset, dest, len);
+}
+
 static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
                                 struct nft_regs *regs,
                                 const struct nft_pktinfo *pkt)
@@ -56,8 +64,7 @@ static void nft_exthdr_ipv6_eval(const struct nft_expr *expr,
        }
        offset += priv->offset;
 
-       dest[priv->len / NFT_REG32_SIZE] = 0;
-       if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
+       if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
                goto err;
        return;
 err:
@@ -153,8 +160,7 @@ static void nft_exthdr_ipv4_eval(const struct nft_expr *expr,
        }
        offset += priv->offset;
 
-       dest[priv->len / NFT_REG32_SIZE] = 0;
-       if (skb_copy_bits(pkt->skb, offset, dest, priv->len) < 0)
+       if (nft_skb_copy_to_reg(pkt->skb, offset, dest, priv->len) < 0)
                goto err;
        return;
 err:
@@ -210,7 +216,8 @@ static void nft_exthdr_tcp_eval(const struct nft_expr *expr,
                if (priv->flags & NFT_EXTHDR_F_PRESENT) {
                        *dest = 1;
                } else {
-                       dest[priv->len / NFT_REG32_SIZE] = 0;
+                       if (priv->len % NFT_REG32_SIZE)
+                               dest[priv->len / NFT_REG32_SIZE] = 0;
                        memcpy(dest, opt + offset, priv->len);
                }
 
@@ -238,7 +245,12 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
        if (!tcph)
                goto err;
 
+       if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
+               goto err;
+
+       tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt));
        opt = (u8 *)tcph;
+
        for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
                union {
                        __be16 v16;
@@ -253,15 +265,6 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
                if (i + optl > tcphdr_len || priv->len + priv->offset > optl)
                        goto err;
 
-               if (skb_ensure_writable(pkt->skb,
-                                       nft_thoff(pkt) + i + priv->len))
-                       goto err;
-
-               tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff,
-                                             &tcphdr_len);
-               if (!tcph)
-                       goto err;
-
                offset = i + priv->offset;
 
                switch (priv->len) {
@@ -325,9 +328,9 @@ static void nft_exthdr_tcp_strip_eval(const struct nft_expr *expr,
        if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
                goto drop;
 
-       opt = (u8 *)nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
-       if (!opt)
-               goto err;
+       tcph = (struct tcphdr *)(pkt->skb->data + nft_thoff(pkt));
+       opt = (u8 *)tcph;
+
        for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
                unsigned int j;
 
@@ -392,9 +395,8 @@ static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
                            offset + ntohs(sch->length) > pkt->skb->len)
                                break;
 
-                       dest[priv->len / NFT_REG32_SIZE] = 0;
-                       if (skb_copy_bits(pkt->skb, offset + priv->offset,
-                                         dest, priv->len) < 0)
+                       if (nft_skb_copy_to_reg(pkt->skb, offset + priv->offset,
+                                               dest, priv->len) < 0)
                                break;
                        return;
                }
index c6435e70923197d838d765bad016f7d929c353cc..f250b5399344afac46bfca4014367bf57cf18ffe 100644 (file)
@@ -312,6 +312,7 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
        struct nft_rbtree_elem *rbe, *rbe_le = NULL, *rbe_ge = NULL;
        struct rb_node *node, *next, *parent, **p, *first = NULL;
        struct nft_rbtree *priv = nft_set_priv(set);
+       u8 cur_genmask = nft_genmask_cur(net);
        u8 genmask = nft_genmask_next(net);
        int d, err;
 
@@ -357,8 +358,11 @@ static int __nft_rbtree_insert(const struct net *net, const struct nft_set *set,
                if (!nft_set_elem_active(&rbe->ext, genmask))
                        continue;
 
-               /* perform garbage collection to avoid bogus overlap reports. */
-               if (nft_set_elem_expired(&rbe->ext)) {
+               /* perform garbage collection to avoid bogus overlap reports
+                * but skip new elements in this transaction.
+                */
+               if (nft_set_elem_expired(&rbe->ext) &&
+                   nft_set_elem_active(&rbe->ext, cur_genmask)) {
                        err = nft_rbtree_gc_elem(set, priv, rbe, genmask);
                        if (err < 0)
                                return err;
index e8961094a2822d991868a318d1ab88a814b45578..b46a6a51205833bb6688d400755a76c3c744bb14 100644 (file)
@@ -149,6 +149,8 @@ static int sctp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_sctp_info *info = par->matchinfo;
 
+       if (info->flag_count > ARRAY_SIZE(info->flag_info))
+               return -EINVAL;
        if (info->flags & ~XT_SCTP_VALID_FLAGS)
                return -EINVAL;
        if (info->invflags & ~XT_SCTP_VALID_FLAGS)
index 177b40d08098b22de5e5335cfc3833e68f6ee457..117d4615d6684c53b3a13225d2222a0993df0002 100644 (file)
@@ -96,11 +96,32 @@ static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par)
        return ret ^ data->invert;
 }
 
+static int u32_mt_checkentry(const struct xt_mtchk_param *par)
+{
+       const struct xt_u32 *data = par->matchinfo;
+       const struct xt_u32_test *ct;
+       unsigned int i;
+
+       if (data->ntests > ARRAY_SIZE(data->tests))
+               return -EINVAL;
+
+       for (i = 0; i < data->ntests; ++i) {
+               ct = &data->tests[i];
+
+               if (ct->nnums > ARRAY_SIZE(ct->location) ||
+                   ct->nvalues > ARRAY_SIZE(ct->value))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 static struct xt_match xt_u32_mt_reg __read_mostly = {
        .name       = "u32",
        .revision   = 0,
        .family     = NFPROTO_UNSPEC,
        .match      = u32_mt,
+       .checkentry = u32_mt_checkentry,
        .matchsize  = sizeof(struct xt_u32),
        .me         = THIS_MODULE,
 };
index 591d87d5e5c0f10379645da9eb0f4e7309d74916..68e6acd0f130d93de42b75f8af40513899b5e2bd 100644 (file)
@@ -61,6 +61,7 @@ struct fq_pie_sched_data {
        struct pie_params p_params;
        u32 ecn_prob;
        u32 flows_cnt;
+       u32 flows_cursor;
        u32 quantum;
        u32 memory_limit;
        u32 new_flow_count;
@@ -375,22 +376,32 @@ flow_error:
 static void fq_pie_timer(struct timer_list *t)
 {
        struct fq_pie_sched_data *q = from_timer(q, t, adapt_timer);
+       unsigned long next, tupdate;
        struct Qdisc *sch = q->sch;
        spinlock_t *root_lock; /* to lock qdisc for probability calculations */
-       u32 idx;
+       int max_cnt, i;
 
        rcu_read_lock();
        root_lock = qdisc_lock(qdisc_root_sleeping(sch));
        spin_lock(root_lock);
 
-       for (idx = 0; idx < q->flows_cnt; idx++)
-               pie_calculate_probability(&q->p_params, &q->flows[idx].vars,
-                                         q->flows[idx].backlog);
-
-       /* reset the timer to fire after 'tupdate' jiffies. */
-       if (q->p_params.tupdate)
-               mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
+       /* Limit this expensive loop to 2048 flows per round. */
+       max_cnt = min_t(int, q->flows_cnt - q->flows_cursor, 2048);
+       for (i = 0; i < max_cnt; i++) {
+               pie_calculate_probability(&q->p_params,
+                                         &q->flows[q->flows_cursor].vars,
+                                         q->flows[q->flows_cursor].backlog);
+               q->flows_cursor++;
+       }
 
+       tupdate = q->p_params.tupdate;
+       next = 0;
+       if (q->flows_cursor >= q->flows_cnt) {
+               q->flows_cursor = 0;
+               next = tupdate;
+       }
+       if (tupdate)
+               mod_timer(&q->adapt_timer, jiffies + next);
        spin_unlock(root_lock);
        rcu_read_unlock();
 }
index ea8c4a7174bba0880851be8631f9234bdecc3ada..35f49edf63dbf2cbdb7010871d7e430cd9d6ed97 100644 (file)
@@ -207,7 +207,7 @@ static struct Qdisc_ops plug_qdisc_ops __read_mostly = {
        .priv_size   =       sizeof(struct plug_sched_data),
        .enqueue     =       plug_enqueue,
        .dequeue     =       plug_dequeue,
-       .peek        =       qdisc_peek_head,
+       .peek        =       qdisc_peek_dequeued,
        .init        =       plug_init,
        .change      =       plug_change,
        .reset       =       qdisc_reset_queue,
index 1a25752f1a9a61dd61445ffef63f03d6e28a01a9..546c10adcacdeaabffbef55f9f992bc239f2fd37 100644 (file)
@@ -974,10 +974,13 @@ static void qfq_update_eligible(struct qfq_sched *q)
 }
 
 /* Dequeue head packet of the head class in the DRR queue of the aggregate. */
-static void agg_dequeue(struct qfq_aggregate *agg,
-                       struct qfq_class *cl, unsigned int len)
+static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg,
+                                  struct qfq_class *cl, unsigned int len)
 {
-       qdisc_dequeue_peeked(cl->qdisc);
+       struct sk_buff *skb = qdisc_dequeue_peeked(cl->qdisc);
+
+       if (!skb)
+               return NULL;
 
        cl->deficit -= (int) len;
 
@@ -987,6 +990,8 @@ static void agg_dequeue(struct qfq_aggregate *agg,
                cl->deficit += agg->lmax;
                list_move_tail(&cl->alist, &agg->active);
        }
+
+       return skb;
 }
 
 static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg,
@@ -1132,11 +1137,18 @@ static struct sk_buff *qfq_dequeue(struct Qdisc *sch)
        if (!skb)
                return NULL;
 
-       qdisc_qstats_backlog_dec(sch, skb);
        sch->q.qlen--;
+
+       skb = agg_dequeue(in_serv_agg, cl, len);
+
+       if (!skb) {
+               sch->q.qlen++;
+               return NULL;
+       }
+
+       qdisc_qstats_backlog_dec(sch, skb);
        qdisc_bstats_update(sch, skb);
 
-       agg_dequeue(in_serv_agg, cl, len);
        /* If lmax is lowered, through qfq_change_class, for a class
         * owning pending packets with larger size than the new value
         * of lmax, then the following condition may hold.
index f13d6a34f32f2f733df83ac82766466234cda42f..ec00ee75d59a658b7ad0086314f7e82a49ffc876 100644 (file)
@@ -282,7 +282,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
                assoc->init_retries, assoc->shutdown_retries,
                assoc->rtx_data_chunks,
                refcount_read(&sk->sk_wmem_alloc),
-               sk->sk_wmem_queued,
+               READ_ONCE(sk->sk_wmem_queued),
                sk->sk_sndbuf,
                sk->sk_rcvbuf);
        seq_printf(seq, "\n");
index fd0631e70d46a282be382e4edb5bcf91ff7798cc..ab943e8fb1db5137ac93fc1728e2fa1b49fe4e9c 100644 (file)
@@ -69,7 +69,7 @@
 #include <net/sctp/stream_sched.h>
 
 /* Forward declarations for internal helper functions. */
-static bool sctp_writeable(struct sock *sk);
+static bool sctp_writeable(const struct sock *sk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
                                size_t msg_len);
@@ -140,7 +140,7 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
 
        refcount_add(sizeof(struct sctp_chunk), &sk->sk_wmem_alloc);
        asoc->sndbuf_used += chunk->skb->truesize + sizeof(struct sctp_chunk);
-       sk->sk_wmem_queued += chunk->skb->truesize + sizeof(struct sctp_chunk);
+       sk_wmem_queued_add(sk, chunk->skb->truesize + sizeof(struct sctp_chunk));
        sk_mem_charge(sk, chunk->skb->truesize);
 }
 
@@ -9144,7 +9144,7 @@ static void sctp_wfree(struct sk_buff *skb)
        struct sock *sk = asoc->base.sk;
 
        sk_mem_uncharge(sk, skb->truesize);
-       sk->sk_wmem_queued -= skb->truesize + sizeof(struct sctp_chunk);
+       sk_wmem_queued_add(sk, -(skb->truesize + sizeof(struct sctp_chunk)));
        asoc->sndbuf_used -= skb->truesize + sizeof(struct sctp_chunk);
        WARN_ON(refcount_sub_and_test(sizeof(struct sctp_chunk),
                                      &sk->sk_wmem_alloc));
@@ -9299,9 +9299,9 @@ void sctp_write_space(struct sock *sk)
  * UDP-style sockets or TCP-style sockets, this code should work.
  *  - Daisy
  */
-static bool sctp_writeable(struct sock *sk)
+static bool sctp_writeable(const struct sock *sk)
 {
-       return sk->sk_sndbuf > sk->sk_wmem_queued;
+       return READ_ONCE(sk->sk_sndbuf) > READ_ONCE(sk->sk_wmem_queued);
 }
 
 /* Wait for an association to go into ESTABLISHED state. If timeout is 0,
index 77f28328e3878bb93f2955868ef019a013834a1e..c8b08b32f097ec5dfde66b42701be720ab05c826 100644 (file)
@@ -827,7 +827,7 @@ static bool skb_is_swtx_tstamp(const struct sk_buff *skb, int false_tstamp)
 
 static ktime_t get_timestamp(struct sock *sk, struct sk_buff *skb, int *if_index)
 {
-       bool cycles = sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC;
+       bool cycles = READ_ONCE(sk->sk_tsflags) & SOF_TIMESTAMPING_BIND_PHC;
        struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
        struct net_device *orig_dev;
        ktime_t hwtstamp;
@@ -879,12 +879,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP);
        int new_tstamp = sock_flag(sk, SOCK_TSTAMP_NEW);
        struct scm_timestamping_internal tss;
-
        int empty = 1, false_tstamp = 0;
        struct skb_shared_hwtstamps *shhwtstamps =
                skb_hwtstamps(skb);
        int if_index;
        ktime_t hwtstamp;
+       u32 tsflags;
 
        /* Race occurred between timestamp enabling and packet
           receiving.  Fill in the current time for now. */
@@ -926,11 +926,12 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        }
 
        memset(&tss, 0, sizeof(tss));
-       if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
+       tsflags = READ_ONCE(sk->sk_tsflags);
+       if ((tsflags & SOF_TIMESTAMPING_SOFTWARE) &&
            ktime_to_timespec64_cond(skb->tstamp, tss.ts + 0))
                empty = 0;
        if (shhwtstamps &&
-           (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
+           (tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) &&
            !skb_is_swtx_tstamp(skb, false_tstamp)) {
                if_index = 0;
                if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP_NETDEV)
@@ -938,14 +939,14 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
                else
                        hwtstamp = shhwtstamps->hwtstamp;
 
-               if (sk->sk_tsflags & SOF_TIMESTAMPING_BIND_PHC)
+               if (tsflags & SOF_TIMESTAMPING_BIND_PHC)
                        hwtstamp = ptp_convert_timestamp(&hwtstamp,
-                                                        sk->sk_bind_phc);
+                                                        READ_ONCE(sk->sk_bind_phc));
 
                if (ktime_to_timespec64_cond(hwtstamp, tss.ts + 2)) {
                        empty = 0;
 
-                       if ((sk->sk_tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
+                       if ((tsflags & SOF_TIMESTAMPING_OPT_PKTINFO) &&
                            !skb_is_err_queue(skb))
                                put_ts_pktinfo(msg, skb, if_index);
                }
index 86930a8ed012bfad9a407db985782934f52b9698..3e8a04a136688341da1dd49255f740f9fba371ff 100644 (file)
@@ -680,7 +680,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
         *        What the above comment does talk about? --ANK(980817)
         */
 
-       if (unix_tot_inflight)
+       if (READ_ONCE(unix_tot_inflight))
                unix_gc();              /* Garbage collect fds */
 }
 
index e9dde7176c8a3a1100aaf659991ceeedf8ef223d..6ff628f2349f571fa8f1e86454a0339a78f7b0f0 100644 (file)
@@ -64,7 +64,7 @@ void unix_inflight(struct user_struct *user, struct file *fp)
                /* Paired with READ_ONCE() in wait_for_unix_gc() */
                WRITE_ONCE(unix_tot_inflight, unix_tot_inflight + 1);
        }
-       user->unix_inflight++;
+       WRITE_ONCE(user->unix_inflight, user->unix_inflight + 1);
        spin_unlock(&unix_gc_lock);
 }
 
@@ -85,7 +85,7 @@ void unix_notinflight(struct user_struct *user, struct file *fp)
                /* Paired with READ_ONCE() in wait_for_unix_gc() */
                WRITE_ONCE(unix_tot_inflight, unix_tot_inflight - 1);
        }
-       user->unix_inflight--;
+       WRITE_ONCE(user->unix_inflight, user->unix_inflight - 1);
        spin_unlock(&unix_gc_lock);
 }
 
@@ -99,7 +99,7 @@ static inline bool too_many_unix_fds(struct task_struct *p)
 {
        struct user_struct *user = current_user();
 
-       if (unlikely(user->unix_inflight > task_rlimit(p, RLIMIT_NOFILE)))
+       if (unlikely(READ_ONCE(user->unix_inflight) > task_rlimit(p, RLIMIT_NOFILE)))
                return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
        return false;
 }
index fcfc8472f73da8500201473ce9960ab838c0428b..55f8b9b0e06d1ff88e918de56dce9635f3a19f08 100644 (file)
@@ -602,7 +602,7 @@ static struct sk_buff *xsk_build_skb_zerocopy(struct xdp_sock *xs,
 
        for (copied = 0, i = skb_shinfo(skb)->nr_frags; copied < len; i++) {
                if (unlikely(i >= MAX_SKB_FRAGS))
-                       return ERR_PTR(-EFAULT);
+                       return ERR_PTR(-EOVERFLOW);
 
                page = pool->umem->pgs[addr >> PAGE_SHIFT];
                get_page(page);
@@ -655,15 +655,17 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
                        skb_put(skb, len);
 
                        err = skb_store_bits(skb, 0, buffer, len);
-                       if (unlikely(err))
+                       if (unlikely(err)) {
+                               kfree_skb(skb);
                                goto free_err;
+                       }
                } else {
                        int nr_frags = skb_shinfo(skb)->nr_frags;
                        struct page *page;
                        u8 *vaddr;
 
                        if (unlikely(nr_frags == (MAX_SKB_FRAGS - 1) && xp_mb_desc(desc))) {
-                               err = -EFAULT;
+                               err = -EOVERFLOW;
                                goto free_err;
                        }
 
@@ -690,12 +692,14 @@ static struct sk_buff *xsk_build_skb(struct xdp_sock *xs,
        return skb;
 
 free_err:
-       if (err == -EAGAIN) {
-               xsk_cq_cancel_locked(xs, 1);
-       } else {
-               xsk_set_destructor_arg(skb);
-               xsk_drop_skb(skb);
+       if (err == -EOVERFLOW) {
+               /* Drop the packet */
+               xsk_set_destructor_arg(xs->skb);
+               xsk_drop_skb(xs->skb);
                xskq_cons_release(xs->tx);
+       } else {
+               /* Let application retry */
+               xsk_cq_cancel_locked(xs, 1);
        }
 
        return ERR_PTR(err);
@@ -738,7 +742,7 @@ static int __xsk_generic_xmit(struct sock *sk)
                skb = xsk_build_skb(xs, &desc);
                if (IS_ERR(skb)) {
                        err = PTR_ERR(skb);
-                       if (err == -EAGAIN)
+                       if (err != -EOVERFLOW)
                                goto out;
                        err = 0;
                        continue;
index c014217f5fa7d92aba92b2682416d208f8a53fdf..22b36c8143cfd5a96ccb7e1934880a98f16f179c 100644 (file)
@@ -111,6 +111,9 @@ static int xsk_diag_fill(struct sock *sk, struct sk_buff *nlskb,
        sock_diag_save_cookie(sk, msg->xdiag_cookie);
 
        mutex_lock(&xs->mutex);
+       if (READ_ONCE(xs->state) == XSK_UNBOUND)
+               goto out_nlmsg_trim;
+
        if ((req->xdiag_show & XDP_SHOW_INFO) && xsk_diag_put_info(xs, nlskb))
                goto out_nlmsg_trim;
 
index eaae2ce78381182463095c4e754816da3fc40678..61b7dddedc461e2ece91a7b25bcf14987fc98886 100755 (executable)
@@ -59,9 +59,9 @@ class Helper(APIElement):
         Break down helper function protocol into smaller chunks: return type,
         name, distincts arguments.
         """
-        arg_re = re.compile('((\w+ )*?(\w+|...))( (\**)(\w+))?$')
+        arg_re = re.compile(r'((\w+ )*?(\w+|...))( (\**)(\w+))?$')
         res = {}
-        proto_re = re.compile('(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
+        proto_re = re.compile(r'(.+) (\**)(\w+)\(((([^,]+)(, )?){1,5})\)$')
 
         capture = proto_re.match(self.proto)
         res['ret_type'] = capture.group(1)
@@ -114,11 +114,11 @@ class HeaderParser(object):
         return Helper(proto=proto, desc=desc, ret=ret)
 
     def parse_symbol(self):
-        p = re.compile(' \* ?(BPF\w+)$')
+        p = re.compile(r' \* ?(BPF\w+)$')
         capture = p.match(self.line)
         if not capture:
             raise NoSyscallCommandFound
-        end_re = re.compile(' \* ?NOTES$')
+        end_re = re.compile(r' \* ?NOTES$')
         end = end_re.match(self.line)
         if end:
             raise NoSyscallCommandFound
@@ -133,7 +133,7 @@ class HeaderParser(object):
         #   - Same as above, with "const" and/or "struct" in front of type
         #   - "..." (undefined number of arguments, for bpf_trace_printk())
         # There is at least one term ("void"), and at most five arguments.
-        p = re.compile(' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
+        p = re.compile(r' \* ?((.+) \**\w+\((((const )?(struct )?(\w+|\.\.\.)( \**\w+)?)(, )?){1,5}\))$')
         capture = p.match(self.line)
         if not capture:
             raise NoHelperFound
@@ -141,7 +141,7 @@ class HeaderParser(object):
         return capture.group(1)
 
     def parse_desc(self, proto):
-        p = re.compile(' \* ?(?:\t| {5,8})Description$')
+        p = re.compile(r' \* ?(?:\t| {5,8})Description$')
         capture = p.match(self.line)
         if not capture:
             raise Exception("No description section found for " + proto)
@@ -154,7 +154,7 @@ class HeaderParser(object):
             if self.line == ' *\n':
                 desc += '\n'
             else:
-                p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
+                p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
                 capture = p.match(self.line)
                 if capture:
                     desc_present = True
@@ -167,7 +167,7 @@ class HeaderParser(object):
         return desc
 
     def parse_ret(self, proto):
-        p = re.compile(' \* ?(?:\t| {5,8})Return$')
+        p = re.compile(r' \* ?(?:\t| {5,8})Return$')
         capture = p.match(self.line)
         if not capture:
             raise Exception("No return section found for " + proto)
@@ -180,7 +180,7 @@ class HeaderParser(object):
             if self.line == ' *\n':
                 ret += '\n'
             else:
-                p = re.compile(' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
+                p = re.compile(r' \* ?(?:\t| {5,8})(?:\t| {8})(.*)')
                 capture = p.match(self.line)
                 if capture:
                     ret_present = True
@@ -219,12 +219,12 @@ class HeaderParser(object):
         self.seek_to('enum bpf_cmd {',
                      'Could not find start of bpf_cmd enum', 0)
         # Searches for either one or more BPF\w+ enums
-        bpf_p = re.compile('\s*(BPF\w+)+')
+        bpf_p = re.compile(r'\s*(BPF\w+)+')
         # Searches for an enum entry assigned to another entry,
         # for e.g. BPF_PROG_RUN = BPF_PROG_TEST_RUN, which is
         # not documented hence should be skipped in check to
         # determine if the right number of syscalls are documented
-        assign_p = re.compile('\s*(BPF\w+)\s*=\s*(BPF\w+)')
+        assign_p = re.compile(r'\s*(BPF\w+)\s*=\s*(BPF\w+)')
         bpf_cmd_str = ''
         while True:
             capture = assign_p.match(self.line)
@@ -239,7 +239,7 @@ class HeaderParser(object):
                 break
             self.line = self.reader.readline()
         # Find the number of occurences of BPF\w+
-        self.enum_syscalls = re.findall('(BPF\w+)+', bpf_cmd_str)
+        self.enum_syscalls = re.findall(r'(BPF\w+)+', bpf_cmd_str)
 
     def parse_desc_helpers(self):
         self.seek_to(helpersDocStart,
@@ -263,7 +263,7 @@ class HeaderParser(object):
         self.seek_to('#define ___BPF_FUNC_MAPPER(FN, ctx...)',
                      'Could not find start of eBPF helper definition list')
         # Searches for one FN(\w+) define or a backslash for newline
-        p = re.compile('\s*FN\((\w+), (\d+), ##ctx\)|\\\\')
+        p = re.compile(r'\s*FN\((\w+), (\d+), ##ctx\)|\\\\')
         fn_defines_str = ''
         i = 0
         while True:
@@ -278,7 +278,7 @@ class HeaderParser(object):
                 break
             self.line = self.reader.readline()
         # Find the number of occurences of FN(\w+)
-        self.define_unique_helpers = re.findall('FN\(\w+, \d+, ##ctx\)', fn_defines_str)
+        self.define_unique_helpers = re.findall(r'FN\(\w+, \d+, ##ctx\)', fn_defines_str)
 
     def validate_helpers(self):
         last_helper = ''
@@ -425,7 +425,7 @@ class PrinterRST(Printer):
         try:
             cmd = ['git', 'log', '-1', '--pretty=format:%cs', '--no-patch',
                    '-L',
-                   '/{}/,/\*\//:include/uapi/linux/bpf.h'.format(delimiter)]
+                   '/{}/,/\\*\\//:include/uapi/linux/bpf.h'.format(delimiter)]
             date = subprocess.run(cmd, cwd=linuxRoot,
                                   capture_output=True, check=True)
             return date.stdout.decode().rstrip()
@@ -516,7 +516,7 @@ as "Dual BSD/GPL", may be used). Some helper functions are only accessible to
 programs that are compatible with the GNU Privacy License (GPL).
 
 In order to use such helpers, the eBPF program must be loaded with the correct
-license string passed (via **attr**) to the **bpf**\ () system call, and this
+license string passed (via **attr**) to the **bpf**\\ () system call, and this
 generally translates into the C source code of the program containing a line
 similar to the following:
 
@@ -550,7 +550,7 @@ may be interested in:
 * The bpftool utility can be used to probe the availability of helper functions
   on the system (as well as supported program and map types, and a number of
   other parameters). To do so, run **bpftool feature probe** (see
-  **bpftool-feature**\ (8) for details). Add the **unprivileged** keyword to
+  **bpftool-feature**\\ (8) for details). Add the **unprivileged** keyword to
   list features available to unprivileged users.
 
 Compatibility between helper functions and program types can generally be found
@@ -562,23 +562,23 @@ other functions, themselves allowing access to additional helpers. The
 requirement for GPL license is also in those **struct bpf_func_proto**.
 
 Compatibility between helper functions and map types can be found in the
-**check_map_func_compatibility**\ () function in file *kernel/bpf/verifier.c*.
+**check_map_func_compatibility**\\ () function in file *kernel/bpf/verifier.c*.
 
 Helper functions that invalidate the checks on **data** and **data_end**
 pointers for network processing are listed in function
-**bpf_helper_changes_pkt_data**\ () in file *net/core/filter.c*.
+**bpf_helper_changes_pkt_data**\\ () in file *net/core/filter.c*.
 
 SEE ALSO
 ========
 
-**bpf**\ (2),
-**bpftool**\ (8),
-**cgroups**\ (7),
-**ip**\ (8),
-**perf_event_open**\ (2),
-**sendmsg**\ (2),
-**socket**\ (7),
-**tc-bpf**\ (8)'''
+**bpf**\\ (2),
+**bpftool**\\ (8),
+**cgroups**\\ (7),
+**ip**\\ (8),
+**perf_event_open**\\ (2),
+**sendmsg**\\ (2),
+**socket**\\ (7),
+**tc-bpf**\\ (8)'''
         print(footer)
 
     def print_proto(self, helper):
@@ -598,7 +598,7 @@ SEE ALSO
             one_arg = '{}{}'.format(comma, a['type'])
             if a['name']:
                 if a['star']:
-                    one_arg += ' {}**\ '.format(a['star'].replace('*', '\\*'))
+                    one_arg += ' {}**\\ '.format(a['star'].replace('*', '\\*'))
                 else:
                     one_arg += '** '
                 one_arg += '*{}*\\ **'.format(a['name'])
index 0b214f6ab5c83447dfc1714f5094c6c6d749129d..2e5c231e08ac795d73dad72eb968f1b4ece1611d 100644 (file)
@@ -83,7 +83,7 @@ const char *evsel__hw_cache_result[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 #define perf_event_name(array, id) ({                  \
        const char *event_str = NULL;                   \
                                                        \
-       if ((id) >= 0 && (id) < ARRAY_SIZE(array))      \
+       if ((id) < ARRAY_SIZE(array))                   \
                event_str = array[id];                  \
        event_str;                                      \
 })
index edef49fcd23e3e4345a0debc804d42b35b5fb39c..caede9b574cb1632fdcb00061a662f6151d61208 100644 (file)
@@ -50,14 +50,17 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
        test_cgroup_storage \
        test_tcpnotify_user test_sysctl \
        test_progs-no_alu32
+TEST_INST_SUBDIRS := no_alu32
 
 # Also test bpf-gcc, if present
 ifneq ($(BPF_GCC),)
 TEST_GEN_PROGS += test_progs-bpf_gcc
+TEST_INST_SUBDIRS += bpf_gcc
 endif
 
 ifneq ($(CLANG_CPUV4),)
 TEST_GEN_PROGS += test_progs-cpuv4
+TEST_INST_SUBDIRS += cpuv4
 endif
 
 TEST_GEN_FILES = test_lwt_ip_encap.bpf.o test_tc_edt.bpf.o
@@ -714,3 +717,12 @@ EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(SCRATCH_DIR) $(HOST_SCRATCH_DIR)     \
 
 # Delete partially updated (corrupted) files on error
 .DELETE_ON_ERROR:
+
+DEFAULT_INSTALL_RULE := $(INSTALL_RULE)
+override define INSTALL_RULE
+       $(DEFAULT_INSTALL_RULE)
+       @for DIR in $(TEST_INST_SUBDIRS); do              \
+               mkdir -p $(INSTALL_PATH)/$$DIR;   \
+               rsync -a $(OUTPUT)/$$DIR/*.bpf.o $(INSTALL_PATH)/$$DIR;\
+       done
+endef
index 31f1e815f67191906d667774a9f16a02ab094c4e..ee0458a5ce789f2a60390c864b6f7e4332a18ecc 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/unistd.h>
 #include <linux/mount.h>
 #include <sys/syscall.h>
+#include "bpf/libbpf_internal.h"
 
 static inline int sys_fsopen(const char *fsname, unsigned flags)
 {
@@ -155,7 +156,7 @@ static void validate_pin(int map_fd, const char *map_name, int src_value,
        ASSERT_OK(err, "obj_pin");
 
        /* cleanup */
-       if (pin_opts.path_fd >= 0)
+       if (path_kind == PATH_FD_REL && pin_opts.path_fd >= 0)
                close(pin_opts.path_fd);
        if (old_cwd[0])
                ASSERT_OK(chdir(old_cwd), "restore_cwd");
@@ -220,7 +221,7 @@ static void validate_get(int map_fd, const char *map_name, int src_value,
                goto cleanup;
 
        /* cleanup */
-       if (get_opts.path_fd >= 0)
+       if (path_kind == PATH_FD_REL && get_opts.path_fd >= 0)
                close(get_opts.path_fd);
        if (old_cwd[0])
                ASSERT_OK(chdir(old_cwd), "restore_cwd");
index 911345c526e6a188bf97e2a02708a6cde0af53b2..ccc768592e66a6a1252d5ae3b24c12270da986ab 100644 (file)
 #include "test_d_path_check_rdonly_mem.skel.h"
 #include "test_d_path_check_types.skel.h"
 
+/* sys_close_range is not around for long time, so let's
+ * make sure we can call it on systems with older glibc
+ */
+#ifndef __NR_close_range
+#ifdef __alpha__
+#define __NR_close_range 546
+#else
+#define __NR_close_range 436
+#endif
+#endif
+
 static int duration;
 
 static struct {
@@ -90,7 +101,11 @@ static int trigger_fstat_events(pid_t pid)
        fstat(indicatorfd, &fileStat);
 
 out_close:
-       /* triggers filp_close */
+       /* sys_close no longer triggers filp_close, but we can
+        * call sys_close_range instead which still does
+        */
+#define close(fd) syscall(__NR_close_range, fd, fd, 0)
+
        close(pipefd[0]);
        close(pipefd[1]);
        close(sockfd);
@@ -98,6 +113,8 @@ out_close:
        close(devfd);
        close(localfd);
        close(indicatorfd);
+
+#undef close
        return ret;
 }
 
diff --git a/tools/testing/selftests/bpf/prog_tests/sk_storage_omem_uncharge.c b/tools/testing/selftests/bpf/prog_tests/sk_storage_omem_uncharge.c
new file mode 100644 (file)
index 0000000..f35852d
--- /dev/null
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Facebook */
+#include <test_progs.h>
+#include <bpf/libbpf.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include "sk_storage_omem_uncharge.skel.h"
+
+void test_sk_storage_omem_uncharge(void)
+{
+       struct sk_storage_omem_uncharge *skel;
+       int sk_fd = -1, map_fd, err, value;
+       socklen_t optlen;
+
+       skel = sk_storage_omem_uncharge__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel open_and_load"))
+               return;
+       map_fd = bpf_map__fd(skel->maps.sk_storage);
+
+       /* A standalone socket not binding to addr:port,
+        * so nentns is not needed.
+        */
+       sk_fd = socket(AF_INET6, SOCK_STREAM, 0);
+       if (!ASSERT_GE(sk_fd, 0, "socket"))
+               goto done;
+
+       optlen = sizeof(skel->bss->cookie);
+       err = getsockopt(sk_fd, SOL_SOCKET, SO_COOKIE, &skel->bss->cookie, &optlen);
+       if (!ASSERT_OK(err, "getsockopt(SO_COOKIE)"))
+               goto done;
+
+       value = 0;
+       err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
+       if (!ASSERT_OK(err, "bpf_map_update_elem(value=0)"))
+               goto done;
+
+       value = 0xdeadbeef;
+       err = bpf_map_update_elem(map_fd, &sk_fd, &value, 0);
+       if (!ASSERT_OK(err, "bpf_map_update_elem(value=0xdeadbeef)"))
+               goto done;
+
+       err = sk_storage_omem_uncharge__attach(skel);
+       if (!ASSERT_OK(err, "attach"))
+               goto done;
+
+       close(sk_fd);
+       sk_fd = -1;
+
+       ASSERT_EQ(skel->bss->cookie_found, 2, "cookie_found");
+       ASSERT_EQ(skel->bss->omem, 0, "omem");
+
+done:
+       sk_storage_omem_uncharge__destroy(skel);
+       if (sk_fd != -1)
+               close(sk_fd);
+}
index d12665490a905ffbaccb6eb85c3344fc43e86f7a..36d829a65aa44a70991e124a485ae5e4160f0e7d 100644 (file)
                __ret;                                                         \
        })
 
+static inline int poll_connect(int fd, unsigned int timeout_sec)
+{
+       struct timeval timeout = { .tv_sec = timeout_sec };
+       fd_set wfds;
+       int r, eval;
+       socklen_t esize = sizeof(eval);
+
+       FD_ZERO(&wfds);
+       FD_SET(fd, &wfds);
+
+       r = select(fd + 1, NULL, &wfds, NULL, &timeout);
+       if (r == 0)
+               errno = ETIME;
+       if (r != 1)
+               return -1;
+
+       if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &eval, &esize) < 0)
+               return -1;
+       if (eval != 0) {
+               errno = eval;
+               return -1;
+       }
+
+       return 0;
+}
+
 static inline int poll_read(int fd, unsigned int timeout_sec)
 {
        struct timeval timeout = { .tv_sec = timeout_sec };
index 5674a9d0cacf0e5b7b216e88064224b8b9ab047f..8df8cbb447f10f21dd8f2a4f61637668c38f40db 100644 (file)
@@ -1452,11 +1452,18 @@ static int vsock_socketpair_connectible(int sotype, int *v0, int *v1)
        if (p < 0)
                goto close_cli;
 
+       if (poll_connect(c, IO_TIMEOUT_SEC) < 0) {
+               FAIL_ERRNO("poll_connect");
+               goto close_acc;
+       }
+
        *v0 = p;
        *v1 = c;
 
        return 0;
 
+close_acc:
+       close(p);
 close_cli:
        close(c);
 close_srv:
index cfed4df490f35b23d808c6ae427d79ab2f3cee58..0b793a102791f73ca08eb948b33a953908c6a3ce 100644 (file)
@@ -88,6 +88,7 @@
 #define sk_v6_rcv_saddr                __sk_common.skc_v6_rcv_saddr
 #define sk_flags               __sk_common.skc_flags
 #define sk_reuse               __sk_common.skc_reuse
+#define sk_cookie              __sk_common.skc_cookie
 
 #define s6_addr32              in6_u.u6_addr32
 
diff --git a/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c b/tools/testing/selftests/bpf/progs/sk_storage_omem_uncharge.c
new file mode 100644 (file)
index 0000000..3e74579
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Facebook */
+#include "vmlinux.h"
+#include "bpf_tracing_net.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_core_read.h>
+
+void *local_storage_ptr = NULL;
+void *sk_ptr = NULL;
+int cookie_found = 0;
+__u64 cookie = 0;
+__u32 omem = 0;
+
+void *bpf_rdonly_cast(void *, __u32) __ksym;
+
+struct {
+       __uint(type, BPF_MAP_TYPE_SK_STORAGE);
+       __uint(map_flags, BPF_F_NO_PREALLOC);
+       __type(key, int);
+       __type(value, int);
+} sk_storage SEC(".maps");
+
+SEC("fexit/bpf_local_storage_destroy")
+int BPF_PROG(bpf_local_storage_destroy, struct bpf_local_storage *local_storage)
+{
+       struct sock *sk;
+
+       if (local_storage_ptr != local_storage)
+               return 0;
+
+       sk = bpf_rdonly_cast(sk_ptr, bpf_core_type_id_kernel(struct sock));
+       if (sk->sk_cookie.counter != cookie)
+               return 0;
+
+       cookie_found++;
+       omem = sk->sk_omem_alloc.counter;
+       local_storage_ptr = NULL;
+
+       return 0;
+}
+
+SEC("fentry/inet6_sock_destruct")
+int BPF_PROG(inet6_sock_destruct, struct sock *sk)
+{
+       int *value;
+
+       if (!cookie || sk->sk_cookie.counter != cookie)
+               return 0;
+
+       value = bpf_sk_storage_get(&sk_storage, sk, 0, 0);
+       if (value && *value == 0xdeadbeef) {
+               cookie_found++;
+               sk_ptr = sk;
+               local_storage_ptr = sk->sk_bpf_storage;
+       }
+
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";
index d328af4a149c3a989b90cc3a3848b8eb3e19dd3d..e7d2a530618a16c7c44af32d0db849d7df75b296 100755 (executable)
@@ -12,7 +12,8 @@ ksft_skip=4
 TESTS="unregister down carrier nexthop suppress ipv6_notify ipv4_notify \
        ipv6_rt ipv4_rt ipv6_addr_metric ipv4_addr_metric ipv6_route_metrics \
        ipv4_route_metrics ipv4_route_v6_gw rp_filter ipv4_del_addr \
-       ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test"
+       ipv6_del_addr ipv4_mangle ipv6_mangle ipv4_bcast_neigh fib6_gc_test \
+       ipv4_mpath_list ipv6_mpath_list"
 
 VERBOSE=0
 PAUSE_ON_FAIL=no
@@ -2352,6 +2353,156 @@ ipv4_bcast_neigh_test()
        cleanup
 }
 
+mpath_dep_check()
+{
+       if [ ! -x "$(command -v mausezahn)" ]; then
+               echo "mausezahn command not found. Skipping test"
+               return 1
+       fi
+
+       if [ ! -x "$(command -v jq)" ]; then
+               echo "jq command not found. Skipping test"
+               return 1
+       fi
+
+       if [ ! -x "$(command -v bc)" ]; then
+               echo "bc command not found. Skipping test"
+               return 1
+       fi
+
+       if [ ! -x "$(command -v perf)" ]; then
+               echo "perf command not found. Skipping test"
+               return 1
+       fi
+
+       perf list fib:* | grep -q fib_table_lookup
+       if [ $? -ne 0 ]; then
+               echo "IPv4 FIB tracepoint not found. Skipping test"
+               return 1
+       fi
+
+       perf list fib6:* | grep -q fib6_table_lookup
+       if [ $? -ne 0 ]; then
+               echo "IPv6 FIB tracepoint not found. Skipping test"
+               return 1
+       fi
+
+       return 0
+}
+
+link_stats_get()
+{
+       local ns=$1; shift
+       local dev=$1; shift
+       local dir=$1; shift
+       local stat=$1; shift
+
+       ip -n $ns -j -s link show dev $dev \
+               | jq '.[]["stats64"]["'$dir'"]["'$stat'"]'
+}
+
+list_rcv_eval()
+{
+       local file=$1; shift
+       local expected=$1; shift
+
+       local count=$(tail -n 1 $file | jq '.["counter-value"] | tonumber | floor')
+       local ratio=$(echo "scale=2; $count / $expected" | bc -l)
+       local res=$(echo "$ratio >= 0.95" | bc)
+       [[ $res -eq 1 ]]
+       log_test $? 0 "Multipath route hit ratio ($ratio)"
+}
+
+ipv4_mpath_list_test()
+{
+       echo
+       echo "IPv4 multipath list receive tests"
+
+       mpath_dep_check || return 1
+
+       route_setup
+
+       set -e
+       run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
+
+       run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
+       run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
+       run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
+       run_cmd "ip -n ns2 link add name nh1 up type dummy"
+       run_cmd "ip -n ns2 link add name nh2 up type dummy"
+       run_cmd "ip -n ns2 address add 172.16.201.1/24 dev nh1"
+       run_cmd "ip -n ns2 address add 172.16.202.1/24 dev nh2"
+       run_cmd "ip -n ns2 neigh add 172.16.201.2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
+       run_cmd "ip -n ns2 neigh add 172.16.202.2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
+       run_cmd "ip -n ns2 route add 203.0.113.0/24
+               nexthop via 172.16.201.2 nexthop via 172.16.202.2"
+       run_cmd "ip netns exec ns2 sysctl -qw net.ipv4.fib_multipath_hash_policy=1"
+       set +e
+
+       local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
+       local tmp_file=$(mktemp)
+       local cmd="ip netns exec ns1 mausezahn veth1 -a own -b $dmac
+               -A 172.16.101.1 -B 203.0.113.1 -t udp 'sp=12345,dp=0-65535' -q"
+
+       # Packets forwarded in a list using a multipath route must not reuse a
+       # cached result so that a flow always hits the same nexthop. In other
+       # words, the FIB lookup tracepoint needs to be triggered for every
+       # packet.
+       local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+       run_cmd "perf stat -e fib:fib_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
+       local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+       local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
+       list_rcv_eval $tmp_file $diff
+
+       rm $tmp_file
+       route_cleanup
+}
+
+ipv6_mpath_list_test()
+{
+       echo
+       echo "IPv6 multipath list receive tests"
+
+       mpath_dep_check || return 1
+
+       route_setup
+
+       set -e
+       run_cmd "ip netns exec ns1 ethtool -K veth1 tcp-segmentation-offload off"
+
+       run_cmd "ip netns exec ns2 bash -c \"echo 20000 > /sys/class/net/veth2/gro_flush_timeout\""
+       run_cmd "ip netns exec ns2 bash -c \"echo 1 > /sys/class/net/veth2/napi_defer_hard_irqs\""
+       run_cmd "ip netns exec ns2 ethtool -K veth2 generic-receive-offload on"
+       run_cmd "ip -n ns2 link add name nh1 up type dummy"
+       run_cmd "ip -n ns2 link add name nh2 up type dummy"
+       run_cmd "ip -n ns2 -6 address add 2001:db8:201::1/64 dev nh1"
+       run_cmd "ip -n ns2 -6 address add 2001:db8:202::1/64 dev nh2"
+       run_cmd "ip -n ns2 -6 neigh add 2001:db8:201::2 lladdr 00:11:22:33:44:55 nud perm dev nh1"
+       run_cmd "ip -n ns2 -6 neigh add 2001:db8:202::2 lladdr 00:aa:bb:cc:dd:ee nud perm dev nh2"
+       run_cmd "ip -n ns2 -6 route add 2001:db8:301::/64
+               nexthop via 2001:db8:201::2 nexthop via 2001:db8:202::2"
+       run_cmd "ip netns exec ns2 sysctl -qw net.ipv6.fib_multipath_hash_policy=1"
+       set +e
+
+       local dmac=$(ip -n ns2 -j link show dev veth2 | jq -r '.[]["address"]')
+       local tmp_file=$(mktemp)
+       local cmd="ip netns exec ns1 mausezahn -6 veth1 -a own -b $dmac
+               -A 2001:db8:101::1 -B 2001:db8:301::1 -t udp 'sp=12345,dp=0-65535' -q"
+
+       # Packets forwarded in a list using a multipath route must not reuse a
+       # cached result so that a flow always hits the same nexthop. In other
+       # words, the FIB lookup tracepoint needs to be triggered for every
+       # packet.
+       local t0_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+       run_cmd "perf stat -e fib6:fib6_table_lookup --filter 'err == 0' -j -o $tmp_file -- $cmd"
+       local t1_rx_pkts=$(link_stats_get ns2 veth2 rx packets)
+       local diff=$(echo $t1_rx_pkts - $t0_rx_pkts | bc -l)
+       list_rcv_eval $tmp_file $diff
+
+       rm $tmp_file
+       route_cleanup
+}
+
 ################################################################################
 # usage
 
@@ -2433,6 +2584,8 @@ do
        ipv6_mangle)                    ipv6_mangle_test;;
        ipv4_bcast_neigh)               ipv4_bcast_neigh_test;;
        fib6_gc_test|ipv6_gc)           fib6_gc_test;;
+       ipv4_mpath_list)                ipv4_mpath_list_test;;
+       ipv6_mpath_list)                ipv6_mpath_list_test;;
 
        help) echo "Test names: $TESTS"; exit 0;;
        esac