diff options
42 files changed, 973 insertions, 188 deletions
diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml index 7f91f474ff25..5ec3d35b7a38 100644 --- a/Documentation/netlink/specs/rt-link.yaml +++ b/Documentation/netlink/specs/rt-link.yaml @@ -594,6 +594,7 @@ definitions: name: reasm-overlaps - name: br-boolopt-multi type: struct + header: linux/if_bridge.h members: - name: optval @@ -826,6 +827,8 @@ definitions: - name: default - name: ovpn-mode + enum-name: ovpn-mode + name-prefix: ovpn-mode type: enum entries: - p2p @@ -2195,6 +2198,7 @@ attribute-sets: type: u16 - name: linkinfo-ovpn-attrs + name-prefix: ifla-ovpn- attributes: - name: mode diff --git a/MAINTAINERS b/MAINTAINERS index 84e99e991f53..c8e91820b527 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18256,10 +18256,11 @@ F: drivers/irqchip/irq-or1k-* OPENVPN DATA CHANNEL OFFLOAD M: Antonio Quartulli <antonio@openvpn.net> +R: Sabrina Dubroca <sd@queasysnail.net> L: openvpn-devel@lists.sourceforge.net (subscribers-only) L: netdev@vger.kernel.org S: Supported -T: git https://github.com/OpenVPN/linux-kernel-ovpn.git +T: git https://github.com/OpenVPN/ovpn-net-next.git F: Documentation/netlink/specs/ovpn.yaml F: drivers/net/ovpn/ F: include/uapi/linux/ovpn.h diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c index 232e839a9d07..038a0400c1f9 100644 --- a/drivers/net/ethernet/dlink/dl2k.c +++ b/drivers/net/ethernet/dlink/dl2k.c @@ -146,6 +146,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) np->ioaddr = ioaddr; np->chip_id = chip_idx; np->pdev = pdev; + + spin_lock_init(&np->stats_lock); spin_lock_init (&np->tx_lock); spin_lock_init (&np->rx_lock); @@ -865,7 +867,6 @@ tx_error (struct net_device *dev, int tx_status) frame_id = (tx_status & 0xffff0000); printk (KERN_ERR "%s: Transmit error, TxStatus %4.4x, FrameId %d.\n", dev->name, tx_status, frame_id); - dev->stats.tx_errors++; /* Ttransmit Underrun */ if (tx_status & 0x10) { dev->stats.tx_fifo_errors++; @@ -902,9 +903,15 @@ tx_error (struct net_device *dev, int tx_status) rio_set_led_mode(dev); /* Let TxStartThresh stay default value */ } + + spin_lock(&np->stats_lock); /* Maximum Collisions */ if (tx_status & 0x08) dev->stats.collisions++; + + dev->stats.tx_errors++; + spin_unlock(&np->stats_lock); + /* Restart the Tx */ dw32(MACCtrl, dr16(MACCtrl) | TxEnable); } @@ -1073,7 +1080,9 @@ get_stats (struct net_device *dev) int i; #endif unsigned int stat_reg; + unsigned long flags; + spin_lock_irqsave(&np->stats_lock, flags); /* All statistics registers need to be acknowledged, else statistic overflow could cause problems */ @@ -1123,6 +1132,9 @@ get_stats (struct net_device *dev) dr16(TCPCheckSumErrors); dr16(UDPCheckSumErrors); dr16(IPCheckSumErrors); + + spin_unlock_irqrestore(&np->stats_lock, flags); + return &dev->stats; } diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h index 0e33e2eaae96..56aff2f0bdbf 100644 --- a/drivers/net/ethernet/dlink/dl2k.h +++ b/drivers/net/ethernet/dlink/dl2k.h @@ -372,6 +372,8 @@ struct netdev_private { struct pci_dev *pdev; void __iomem *ioaddr; void __iomem *eeprom_addr; + // To ensure synchronization when stats are updated. + spinlock_t stats_lock; spinlock_t tx_lock; spinlock_t rx_lock; unsigned int rx_buf_sz; /* Based on MTU+slack. */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 32ed4963b8ad..5b0d03b3efe8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -520,6 +520,12 @@ struct mlx5e_xdpsq { struct mlx5e_channel *channel; } ____cacheline_aligned_in_smp; +struct mlx5e_xdp_buff { + struct xdp_buff xdp; + struct mlx5_cqe64 *cqe; + struct mlx5e_rq *rq; +}; + struct mlx5e_ktls_resync_resp; struct mlx5e_icosq { @@ -716,6 +722,7 @@ struct mlx5e_rq { struct mlx5e_xdpsq *xdpsq; DECLARE_BITMAP(flags, 8); struct page_pool *page_pool; + struct mlx5e_xdp_buff mxbuf; /* AF_XDP zero-copy */ struct xsk_buff_pool *xsk_pool; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h index 446e492c6bb8..46ab0a9e8cdd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h @@ -45,12 +45,6 @@ (MLX5E_XDP_INLINE_WQE_MAX_DS_CNT * MLX5_SEND_WQE_DS - \ sizeof(struct mlx5_wqe_inline_seg)) -struct mlx5e_xdp_buff { - struct xdp_buff xdp; - struct mlx5_cqe64 *cqe; - struct mlx5e_rq *rq; -}; - /* XDP packets can be transmitted in different ways. On completion, we need to * distinguish between them to clean up things in a proper way. */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 5fd70b4d55be..84b1ab8233b8 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -1684,17 +1684,17 @@ mlx5e_skb_from_cqe_linear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi, prog = rcu_dereference(rq->xdp_prog); if (prog) { - struct mlx5e_xdp_buff mxbuf; + struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; net_prefetchw(va); /* xdp_frame data area */ mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz, - cqe_bcnt, &mxbuf); - if (mlx5e_xdp_handle(rq, prog, &mxbuf)) + cqe_bcnt, mxbuf); + if (mlx5e_xdp_handle(rq, prog, mxbuf)) return NULL; /* page/packet was consumed by XDP */ - rx_headroom = mxbuf.xdp.data - mxbuf.xdp.data_hard_start; - metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta; - cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data; + rx_headroom = mxbuf->xdp.data - mxbuf->xdp.data_hard_start; + metasize = mxbuf->xdp.data - mxbuf->xdp.data_meta; + cqe_bcnt = mxbuf->xdp.data_end - mxbuf->xdp.data; } frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt); skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize); @@ -1713,11 +1713,11 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi struct mlx5_cqe64 *cqe, u32 cqe_bcnt) { struct mlx5e_rq_frag_info *frag_info = &rq->wqe.info.arr[0]; + struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; struct mlx5e_wqe_frag_info *head_wi = wi; u16 rx_headroom = rq->buff.headroom; struct mlx5e_frag_page *frag_page; struct skb_shared_info *sinfo; - struct mlx5e_xdp_buff mxbuf; u32 frag_consumed_bytes; struct bpf_prog *prog; struct sk_buff *skb; @@ -1737,8 +1737,8 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi net_prefetch(va + rx_headroom); mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz, - frag_consumed_bytes, &mxbuf); - sinfo = xdp_get_shared_info_from_buff(&mxbuf.xdp); + frag_consumed_bytes, mxbuf); + sinfo = xdp_get_shared_info_from_buff(&mxbuf->xdp); truesize = 0; cqe_bcnt -= frag_consumed_bytes; @@ -1750,8 +1750,9 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi frag_consumed_bytes = min_t(u32, frag_info->frag_size, cqe_bcnt); - mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf.xdp, frag_page, - wi->offset, frag_consumed_bytes); + mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf->xdp, + frag_page, wi->offset, + frag_consumed_bytes); truesize += frag_info->frag_stride; cqe_bcnt -= frag_consumed_bytes; @@ -1760,7 +1761,7 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi } prog = rcu_dereference(rq->xdp_prog); - if (prog && mlx5e_xdp_handle(rq, prog, &mxbuf)) { + if (prog && mlx5e_xdp_handle(rq, prog, mxbuf)) { if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) { struct mlx5e_wqe_frag_info *pwi; @@ -1770,21 +1771,23 @@ mlx5e_skb_from_cqe_nonlinear(struct mlx5e_rq *rq, struct mlx5e_wqe_frag_info *wi return NULL; /* page/packet was consumed by XDP */ } - skb = mlx5e_build_linear_skb(rq, mxbuf.xdp.data_hard_start, rq->buff.frame0_sz, - mxbuf.xdp.data - mxbuf.xdp.data_hard_start, - mxbuf.xdp.data_end - mxbuf.xdp.data, - mxbuf.xdp.data - mxbuf.xdp.data_meta); + skb = mlx5e_build_linear_skb( + rq, mxbuf->xdp.data_hard_start, rq->buff.frame0_sz, + mxbuf->xdp.data - mxbuf->xdp.data_hard_start, + mxbuf->xdp.data_end - mxbuf->xdp.data, + mxbuf->xdp.data - mxbuf->xdp.data_meta); if (unlikely(!skb)) return NULL; skb_mark_for_recycle(skb); head_wi->frag_page->frags++; - if (xdp_buff_has_frags(&mxbuf.xdp)) { + if (xdp_buff_has_frags(&mxbuf->xdp)) { /* sinfo->nr_frags is reset by build_skb, calculate again. */ xdp_update_skb_shared_info(skb, wi - head_wi - 1, sinfo->xdp_frags_size, truesize, - xdp_buff_is_frag_pfmemalloc(&mxbuf.xdp)); + xdp_buff_is_frag_pfmemalloc( + &mxbuf->xdp)); for (struct mlx5e_wqe_frag_info *pwi = head_wi + 1; pwi < wi; pwi++) pwi->frag_page->frags++; @@ -1984,10 +1987,10 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w struct mlx5e_frag_page *frag_page = &wi->alloc_units.frag_pages[page_idx]; u16 headlen = min_t(u16, MLX5E_RX_MAX_HEAD, cqe_bcnt); struct mlx5e_frag_page *head_page = frag_page; + struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; u32 frag_offset = head_offset; u32 byte_cnt = cqe_bcnt; struct skb_shared_info *sinfo; - struct mlx5e_xdp_buff mxbuf; unsigned int truesize = 0; struct bpf_prog *prog; struct sk_buff *skb; @@ -2033,9 +2036,10 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w } } - mlx5e_fill_mxbuf(rq, cqe, va, linear_hr, linear_frame_sz, linear_data_len, &mxbuf); + mlx5e_fill_mxbuf(rq, cqe, va, linear_hr, linear_frame_sz, + linear_data_len, mxbuf); - sinfo = xdp_get_shared_info_from_buff(&mxbuf.xdp); + sinfo = xdp_get_shared_info_from_buff(&mxbuf->xdp); while (byte_cnt) { /* Non-linear mode, hence non-XSK, which always uses PAGE_SIZE. */ @@ -2046,7 +2050,8 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w else truesize += ALIGN(pg_consumed_bytes, BIT(rq->mpwqe.log_stride_sz)); - mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf.xdp, frag_page, frag_offset, + mlx5e_add_skb_shared_info_frag(rq, sinfo, &mxbuf->xdp, + frag_page, frag_offset, pg_consumed_bytes); byte_cnt -= pg_consumed_bytes; frag_offset = 0; @@ -2054,7 +2059,7 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w } if (prog) { - if (mlx5e_xdp_handle(rq, prog, &mxbuf)) { + if (mlx5e_xdp_handle(rq, prog, mxbuf)) { if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) { struct mlx5e_frag_page *pfp; @@ -2067,10 +2072,10 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w return NULL; /* page/packet was consumed by XDP */ } - skb = mlx5e_build_linear_skb(rq, mxbuf.xdp.data_hard_start, - linear_frame_sz, - mxbuf.xdp.data - mxbuf.xdp.data_hard_start, 0, - mxbuf.xdp.data - mxbuf.xdp.data_meta); + skb = mlx5e_build_linear_skb( + rq, mxbuf->xdp.data_hard_start, linear_frame_sz, + mxbuf->xdp.data - mxbuf->xdp.data_hard_start, 0, + mxbuf->xdp.data - mxbuf->xdp.data_meta); if (unlikely(!skb)) { mlx5e_page_release_fragmented(rq, &wi->linear_page); return NULL; @@ -2080,13 +2085,14 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w wi->linear_page.frags++; mlx5e_page_release_fragmented(rq, &wi->linear_page); - if (xdp_buff_has_frags(&mxbuf.xdp)) { + if (xdp_buff_has_frags(&mxbuf->xdp)) { struct mlx5e_frag_page *pagep; /* sinfo->nr_frags is reset by build_skb, calculate again. */ xdp_update_skb_shared_info(skb, frag_page - head_page, sinfo->xdp_frags_size, truesize, - xdp_buff_is_frag_pfmemalloc(&mxbuf.xdp)); + xdp_buff_is_frag_pfmemalloc( + &mxbuf->xdp)); pagep = head_page; do @@ -2097,12 +2103,13 @@ mlx5e_skb_from_cqe_mpwrq_nonlinear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *w } else { dma_addr_t addr; - if (xdp_buff_has_frags(&mxbuf.xdp)) { + if (xdp_buff_has_frags(&mxbuf->xdp)) { struct mlx5e_frag_page *pagep; xdp_update_skb_shared_info(skb, sinfo->nr_frags, sinfo->xdp_frags_size, truesize, - xdp_buff_is_frag_pfmemalloc(&mxbuf.xdp)); + xdp_buff_is_frag_pfmemalloc( + &mxbuf->xdp)); pagep = frag_page - sinfo->nr_frags; do @@ -2152,20 +2159,20 @@ mlx5e_skb_from_cqe_mpwrq_linear(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi, prog = rcu_dereference(rq->xdp_prog); if (prog) { - struct mlx5e_xdp_buff mxbuf; + struct mlx5e_xdp_buff *mxbuf = &rq->mxbuf; net_prefetchw(va); /* xdp_frame data area */ mlx5e_fill_mxbuf(rq, cqe, va, rx_headroom, rq->buff.frame0_sz, - cqe_bcnt, &mxbuf); - if (mlx5e_xdp_handle(rq, prog, &mxbuf)) { + cqe_bcnt, mxbuf); + if (mlx5e_xdp_handle(rq, prog, mxbuf)) { if (__test_and_clear_bit(MLX5E_RQ_FLAG_XDP_XMIT, rq->flags)) frag_page->frags++; return NULL; /* page/packet was consumed by XDP */ } - rx_headroom = mxbuf.xdp.data - mxbuf.xdp.data_hard_start; - metasize = mxbuf.xdp.data - mxbuf.xdp.data_meta; - cqe_bcnt = mxbuf.xdp.data_end - mxbuf.xdp.data; + rx_headroom = mxbuf->xdp.data - mxbuf->xdp.data_hard_start; + metasize = mxbuf->xdp.data - mxbuf->xdp.data_meta; + cqe_bcnt = mxbuf->xdp.data_end - mxbuf->xdp.data; } frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + cqe_bcnt); skb = mlx5e_build_linear_skb(rq, va, frag_size, rx_headroom, cqe_bcnt, metasize); diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index f05231030925..2c1a0c21af8d 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -70,6 +70,7 @@ enum mac_version { RTL_GIGA_MAC_VER_64, RTL_GIGA_MAC_VER_66, RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_80, RTL_GIGA_MAC_NONE, RTL_GIGA_MAC_VER_LAST = RTL_GIGA_MAC_NONE - 1 }; diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 7bf71a675362..43170500d566 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -60,6 +60,7 @@ #define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" #define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" #define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" +#define FIRMWARE_8127A_1 "rtl_nic/rtl8127a-1.fw" #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -98,6 +99,9 @@ static const struct rtl_chip_info { const char *name; const char *fw_name; } rtl_chip_infos[] = { + /* 8127A family. */ + { 0x7cf, 0x6c9, RTL_GIGA_MAC_VER_80, "RTL8127A", FIRMWARE_8127A_1 }, + /* 8126A family. */ { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_3 }, { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70, "RTL8126A", FIRMWARE_8126A_2 }, @@ -222,8 +226,10 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, { PCI_VDEVICE(REALTEK, 0x8125) }, { PCI_VDEVICE(REALTEK, 0x8126) }, + { PCI_VDEVICE(REALTEK, 0x8127) }, { PCI_VDEVICE(REALTEK, 0x3000) }, { PCI_VDEVICE(REALTEK, 0x5000) }, + { PCI_VDEVICE(REALTEK, 0x0e10) }, {} }; @@ -769,6 +775,7 @@ MODULE_FIRMWARE(FIRMWARE_8125D_2); MODULE_FIRMWARE(FIRMWARE_8125BP_2); MODULE_FIRMWARE(FIRMWARE_8126A_2); MODULE_FIRMWARE(FIRMWARE_8126A_3); +MODULE_FIRMWARE(FIRMWARE_8127A_1); static inline struct device *tp_to_dev(struct rtl8169_private *tp) { @@ -2937,6 +2944,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) rtl_mod_config5(tp, 0, ASPM_en); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_80: val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -2968,6 +2976,7 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) switch (tp->mac_version) { case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_80: val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; RTL_W8(tp, INT_CFG0_8125, val8); break; @@ -3687,10 +3696,13 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_80) RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_80) + r8168_mac_ocp_modify(tp, 0xe614, 0x0f00, 0x0f00); + else if (tp->mac_version == RTL_GIGA_MAC_VER_70) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); @@ -3708,7 +3720,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); - if (tp->mac_version == RTL_GIGA_MAC_VER_70) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_80) r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); else r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); @@ -3786,6 +3799,12 @@ static void rtl_hw_start_8126a(struct rtl8169_private *tp) rtl_hw_start_8125_common(tp); } +static void rtl_hw_start_8127a(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + static void rtl_hw_config(struct rtl8169_private *tp) { static const rtl_generic_fct hw_configs[] = { @@ -3829,6 +3848,7 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_80] = rtl_hw_start_8127a, }; if (hw_configs[tp->mac_version]) @@ -3846,8 +3866,11 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: case RTL_GIGA_MAC_VER_64: case RTL_GIGA_MAC_VER_66: + case RTL_GIGA_MAC_VER_80: for (i = 0xa00; i < 0xb00; i += 4) RTL_W32(tp, i, 0); + if (tp->mac_version == RTL_GIGA_MAC_VER_80) + RTL_W16(tp, INT_CFG1_8125, 0x0000); break; case RTL_GIGA_MAC_VER_63: case RTL_GIGA_MAC_VER_70: diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index 5403f8202c79..032d9d2cfa2a 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -1130,6 +1130,171 @@ static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, rtl8125_common_config_eee_phy(phydev); } +static void rtl8127a_1_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + + r8168g_phy_param(phydev, 0x8415, 0xff00, 0x9300); + r8168g_phy_param(phydev, 0x81a3, 0xff00, 0x0f00); + r8168g_phy_param(phydev, 0x81ae, 0xff00, 0x0f00); + r8168g_phy_param(phydev, 0x81b9, 0xff00, 0xb900); + rtl8125_phy_param(phydev, 0x83b0, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83C5, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83da, 0x0e00, 0x0000); + rtl8125_phy_param(phydev, 0x83ef, 0x0e00, 0x0000); + phy_modify_paged(phydev, 0x0bf3, 0x14, 0x01f0, 0x0160); + phy_modify_paged(phydev, 0x0bf3, 0x15, 0x001f, 0x0014); + phy_modify_paged(phydev, 0x0bf2, 0x14, 0x6000, 0x0000); + phy_modify_paged(phydev, 0x0bf2, 0x16, 0xc000, 0x0000); + phy_modify_paged(phydev, 0x0bf2, 0x14, 0x1fff, 0x0187); + phy_modify_paged(phydev, 0x0bf2, 0x15, 0x003f, 0x0003); + + r8168g_phy_param(phydev, 0x8173, 0xffff, 0x8620); + r8168g_phy_param(phydev, 0x8175, 0xffff, 0x8671); + r8168g_phy_param(phydev, 0x817c, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x8187, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x8192, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x819d, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x81a8, 0x2000, 0x0000); + r8168g_phy_param(phydev, 0x81b3, 0x2000, 0x0000); + r8168g_phy_param(phydev, 0x81be, 0x0000, 0x2000); + r8168g_phy_param(phydev, 0x817d, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x8188, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x8193, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x819e, 0xff00, 0xa600); + r8168g_phy_param(phydev, 0x81a9, 0xff00, 0x1400); + r8168g_phy_param(phydev, 0x81b4, 0xff00, 0x1400); + r8168g_phy_param(phydev, 0x81bf, 0xff00, 0xa600); + + phy_modify_paged(phydev, 0x0aea, 0x15, 0x0028, 0x0000); + + rtl8125_phy_param(phydev, 0x84f0, 0xffff, 0x201c); + rtl8125_phy_param(phydev, 0x84f2, 0xffff, 0x3117); + + phy_write_paged(phydev, 0x0aec, 0x13, 0x0000); + phy_write_paged(phydev, 0x0ae2, 0x10, 0xffff); + phy_write_paged(phydev, 0x0aec, 0x17, 0xffff); + phy_write_paged(phydev, 0x0aed, 0x11, 0xffff); + phy_write_paged(phydev, 0x0aec, 0x14, 0x0000); + phy_modify_paged(phydev, 0x0aed, 0x10, 0x0001, 0x0000); + phy_write_paged(phydev, 0x0adb, 0x14, 0x0150); + rtl8125_phy_param(phydev, 0x8197, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x8231, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x82cb, 0xff00, 0x5000); + rtl8125_phy_param(phydev, 0x82cd, 0xff00, 0x5700); + rtl8125_phy_param(phydev, 0x8233, 0xff00, 0x5700); + rtl8125_phy_param(phydev, 0x8199, 0xff00, 0x5700); + + rtl8125_phy_param(phydev, 0x815a, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x81f4, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x828e, 0xffff, 0x0150); + rtl8125_phy_param(phydev, 0x81b1, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x824b, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x82e5, 0xffff, 0x0000); + + rtl8125_phy_param(phydev, 0x84f7, 0xff00, 0x2800); + phy_modify_paged(phydev, 0x0aec, 0x11, 0x0000, 0x1000); + rtl8125_phy_param(phydev, 0x81b3, 0xff00, 0xad00); + rtl8125_phy_param(phydev, 0x824d, 0xff00, 0xad00); + rtl8125_phy_param(phydev, 0x82e7, 0xff00, 0xad00); + phy_modify_paged(phydev, 0x0ae4, 0x17, 0x000f, 0x0001); + rtl8125_phy_param(phydev, 0x82ce, 0xf000, 0x4000); + + rtl8125_phy_param(phydev, 0x84ac, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x84ae, 0xffff, 0x0000); + rtl8125_phy_param(phydev, 0x84b0, 0xffff, 0xf818); + rtl8125_phy_param(phydev, 0x84b2, 0xff00, 0x6000); + + rtl8125_phy_param(phydev, 0x8ffc, 0xffff, 0x6008); + rtl8125_phy_param(phydev, 0x8ffe, 0xffff, 0xf450); + + rtl8125_phy_param(phydev, 0x8015, 0x0000, 0x0200); + rtl8125_phy_param(phydev, 0x8016, 0x0800, 0x0000); + rtl8125_phy_param(phydev, 0x8fe6, 0xff00, 0x0800); + rtl8125_phy_param(phydev, 0x8fe4, 0xffff, 0x2114); + + rtl8125_phy_param(phydev, 0x8647, 0xffff, 0xa7b1); + rtl8125_phy_param(phydev, 0x8649, 0xffff, 0xbbca); + rtl8125_phy_param(phydev, 0x864b, 0xff00, 0xdc00); + + rtl8125_phy_param(phydev, 0x8154, 0xc000, 0x4000); + rtl8125_phy_param(phydev, 0x8158, 0xc000, 0x0000); + + rtl8125_phy_param(phydev, 0x826c, 0xffff, 0xffff); + rtl8125_phy_param(phydev, 0x826e, 0xffff, 0xffff); + + rtl8125_phy_param(phydev, 0x8872, 0xff00, 0x0e00); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x0800); + r8168g_phy_param(phydev, 0x8012, 0x0000, 0x4000); + phy_modify_paged(phydev, 0x0b57, 0x13, 0x0000, 0x0001); + r8168g_phy_param(phydev, 0x834a, 0xff00, 0x0700); + rtl8125_phy_param(phydev, 0x8217, 0x3f00, 0x2a00); + r8168g_phy_param(phydev, 0x81b1, 0xff00, 0x0b00); + rtl8125_phy_param(phydev, 0x8fed, 0xff00, 0x4e00); + + rtl8125_phy_param(phydev, 0x88ac, 0xff00, 0x2300); + phy_modify_paged(phydev, 0x0bf0, 0x16, 0x0000, 0x3800); + rtl8125_phy_param(phydev, 0x88de, 0xff00, 0x0000); + rtl8125_phy_param(phydev, 0x80b4, 0xffff, 0x5195); + + r8168g_phy_param(phydev, 0x8370, 0xffff, 0x8671); + r8168g_phy_param(phydev, 0x8372, 0xffff, 0x86c8); + + r8168g_phy_param(phydev, 0x8401, 0xffff, 0x86c8); + r8168g_phy_param(phydev, 0x8403, 0xffff, 0x86da); + r8168g_phy_param(phydev, 0x8406, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8408, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840a, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840c, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x840e, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8410, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8412, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8414, 0x1800, 0x1000); + r8168g_phy_param(phydev, 0x8416, 0x1800, 0x1000); + + r8168g_phy_param(phydev, 0x82bd, 0xffff, 0x1f40); + + phy_modify_paged(phydev, 0x0bfb, 0x12, 0x07ff, 0x0328); + phy_write_paged(phydev, 0x0bfb, 0x13, 0x3e14); + + r8168g_phy_param(phydev, 0x81c4, 0xffff, 0x003b); + r8168g_phy_param(phydev, 0x81c6, 0xffff, 0x0086); + r8168g_phy_param(phydev, 0x81c8, 0xffff, 0x00b7); + r8168g_phy_param(phydev, 0x81ca, 0xffff, 0x00db); + r8168g_phy_param(phydev, 0x81cc, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81ce, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d0, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d2, 0xffff, 0x00fe); + r8168g_phy_param(phydev, 0x81d4, 0xffff, 0x00c3); + r8168g_phy_param(phydev, 0x81d6, 0xffff, 0x0078); + r8168g_phy_param(phydev, 0x81d8, 0xffff, 0x0047); + r8168g_phy_param(phydev, 0x81da, 0xffff, 0x0023); + + rtl8125_phy_param(phydev, 0x88d7, 0xffff, 0x01a0); + rtl8125_phy_param(phydev, 0x88d9, 0xffff, 0x01a0); + rtl8125_phy_param(phydev, 0x8ffa, 0xffff, 0x002a); + + rtl8125_phy_param(phydev, 0x8fee, 0xffff, 0xffdf); + rtl8125_phy_param(phydev, 0x8ff0, 0xffff, 0xffff); + rtl8125_phy_param(phydev, 0x8ff2, 0xffff, 0x0a4a); + rtl8125_phy_param(phydev, 0x8ff4, 0xffff, 0xaa5a); + rtl8125_phy_param(phydev, 0x8ff6, 0xffff, 0x0a4a); + + rtl8125_phy_param(phydev, 0x8ff8, 0xffff, 0xaa5a); + rtl8125_phy_param(phydev, 0x88d5, 0xff00, 0x0200); + + r8168g_phy_param(phydev, 0x84bb, 0xff00, 0x0a00); + r8168g_phy_param(phydev, 0x84c0, 0xff00, 0x1600); + + phy_modify_paged(phydev, 0x0a43, 0x10, 0x0000, 0x0003); + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_common_config_eee_phy(phydev); +} + void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, enum mac_version ver) { @@ -1181,6 +1346,7 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_80] = rtl8127a_1_hw_phy_config, }; if (phy_configs[ver]) diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c index 74ee639ac868..2cca759feffa 100644 --- a/drivers/net/ovpn/crypto_aead.c +++ b/drivers/net/ovpn/crypto_aead.c @@ -88,12 +88,15 @@ int ovpn_aead_encrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks, /* build scatterlist to encrypt packet payload */ ret = skb_to_sgvec_nomark(skb, sg + 1, 0, skb->len); - if (unlikely(nfrags != ret)) - return -EINVAL; + if (unlikely(ret < 0)) { + netdev_err(peer->ovpn->dev, + "encrypt: cannot map skb to sg: %d\n", ret); + return ret; + } /* append auth_tag onto scatterlist */ __skb_push(skb, tag_size); - sg_set_buf(sg + nfrags + 1, skb->data, tag_size); + sg_set_buf(sg + ret + 1, skb->data, tag_size); /* obtain packet ID, which is used both as a first * 4 bytes of nonce and last 4 bytes of associated data. @@ -201,11 +204,14 @@ int ovpn_aead_decrypt(struct ovpn_peer *peer, struct ovpn_crypto_key_slot *ks, /* build scatterlist to decrypt packet payload */ ret = skb_to_sgvec_nomark(skb, sg + 1, payload_offset, payload_len); - if (unlikely(nfrags != ret)) - return -EINVAL; + if (unlikely(ret < 0)) { + netdev_err(peer->ovpn->dev, + "decrypt: cannot map skb to sg: %d\n", ret); + return ret; + } /* append auth_tag onto scatterlist */ - sg_set_buf(sg + nfrags + 1, skb->data + OVPN_AAD_SIZE, tag_size); + sg_set_buf(sg + ret + 1, skb->data + OVPN_AAD_SIZE, tag_size); /* iv may be required by async crypto */ ovpn_skb_cb(skb)->iv = kmalloc(OVPN_NONCE_SIZE, GFP_ATOMIC); diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index dd8a8055d967..10d8afecec55 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -394,10 +394,22 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) /* retrieve peer serving the destination IP of this packet */ peer = ovpn_peer_get_by_dst(ovpn, skb); if (unlikely(!peer)) { - net_dbg_ratelimited("%s: no peer to send data to\n", - netdev_name(ovpn->dev)); + switch (skb->protocol) { + case htons(ETH_P_IP): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n", + netdev_name(ovpn->dev), + &ip_hdr(skb)->daddr); + break; + case htons(ETH_P_IPV6): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n", + netdev_name(ovpn->dev), + &ipv6_hdr(skb)->daddr); + break; + } goto drop; } + /* dst was needed for peer selection - it can now be dropped */ + skb_dst_drop(skb); ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len); ovpn_send(ovpn, skb_list.next, peer); @@ -408,7 +420,7 @@ drop: dev_dstats_tx_dropped(ovpn->dev); skb_tx_error(skb); kfree_skb_list(skb); - return NET_XMIT_DROP; + return NETDEV_TX_OK; } /** diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 0acb0934c1be..1bb1afe766a4 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -157,6 +157,11 @@ static void ovpn_setup(struct net_device *dev) dev->type = ARPHRD_NONE; dev->flags = IFF_POINTOPOINT | IFF_NOARP; dev->priv_flags |= IFF_NO_QUEUE; + /* when routing packets to a LAN behind a client, we rely on the + * route entry that originally brought the packet into ovpn, so + * don't release it + */ + netif_keep_dst(dev); dev->lltx = true; dev->features |= feat; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index a37f89fffb02..a1fd27b9c038 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -258,7 +258,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) */ if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, &ipv6_hdr(skb)->daddr))) { - net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", + net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c)\n", netdev_name(peer->ovpn->dev), peer->id, &bind->local.ipv6, &ipv6_hdr(skb)->daddr); @@ -1353,8 +1353,7 @@ void ovpn_peer_keepalive_work(struct work_struct *work) } /* prevent rearming if the interface is being destroyed */ - if (next_run > 0 && - READ_ONCE(ovpn->dev->reg_state) == NETREG_REGISTERED) { + if (next_run > 0) { netdev_dbg(ovpn->dev, "scheduling keepalive work: now=%llu next_run=%llu delta=%llu\n", next_run, now, next_run - now); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index c9e189056f33..aef8c0406ec9 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -262,6 +262,16 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, dst_cache_set_ip6(cache, dst, &fl.saddr); transmit: + /* user IPv6 packets may be larger than the transport interface + * MTU (after encapsulation), however, since they are locally + * generated we should ensure they get fragmented. + * Setting the ignore_df flag to 1 will instruct ip6_fragment() to + * fragment packets if needed. + * + * NOTE: this is not needed for IPv4 because we pass df=0 to + * udp_tunnel_xmit_skb() + */ + skb->ignore_df = 1; udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0, ip6_dst_hoplimit(dst), 0, fl.fl6_sport, fl.fl6_dport, udp_get_no_check6_tx(sk)); diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index ee7831a9849b..c91adf2464c5 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -223,12 +223,12 @@ static struct gpio_desc *fixed_phy_get_gpiod(struct device_node *np) } #endif -static struct phy_device *__fixed_phy_register(unsigned int irq, - struct fixed_phy_status *status, - struct device_node *np, - struct gpio_desc *gpiod) +struct phy_device *fixed_phy_register(unsigned int irq, + struct fixed_phy_status *status, + struct device_node *np) { struct fixed_mdio_bus *fmb = &platform_fmb; + struct gpio_desc *gpiod; struct phy_device *phy; int phy_addr; int ret; @@ -237,11 +237,9 @@ static struct phy_device *__fixed_phy_register(unsigned int irq, return ERR_PTR(-EPROBE_DEFER); /* Check if we have a GPIO associated with this fixed phy */ - if (!gpiod) { - gpiod = fixed_phy_get_gpiod(np); - if (IS_ERR(gpiod)) - return ERR_CAST(gpiod); - } + gpiod = fixed_phy_get_gpiod(np); + if (IS_ERR(gpiod)) + return ERR_CAST(gpiod); /* Get the next available PHY address, up to PHY_MAX_ADDR */ phy_addr = ida_alloc_max(&phy_fixed_ida, PHY_MAX_ADDR - 1, GFP_KERNEL); @@ -306,24 +304,8 @@ static struct phy_device *__fixed_phy_register(unsigned int irq, return phy; } - -struct phy_device *fixed_phy_register(unsigned int irq, - struct fixed_phy_status *status, - struct device_node *np) -{ - return __fixed_phy_register(irq, status, np, NULL); -} EXPORT_SYMBOL_GPL(fixed_phy_register); -struct phy_device * -fixed_phy_register_with_gpiod(unsigned int irq, - struct fixed_phy_status *status, - struct gpio_desc *gpiod) -{ - return __fixed_phy_register(irq, status, NULL, gpiod); -} -EXPORT_SYMBOL_GPL(fixed_phy_register_with_gpiod); - void fixed_phy_unregister(struct phy_device *phy) { phy_device_remove(phy); diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index cd09684780a4..a284e8435cb6 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -7,6 +7,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/phy.h> #include <linux/regmap.h> +#include <linux/of.h> #include "../phylib.h" #include "mtk.h" @@ -1322,6 +1323,7 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) { struct device_node *np = dev_of_node(&phydev->mdio.bus->dev); struct mtk_socphy_shared *shared = phy_package_get_priv(phydev); + struct device_node *pio_np; struct regmap *regmap; u32 reg; int ret; @@ -1339,7 +1341,13 @@ static int mt7988_phy_probe_shared(struct phy_device *phydev) * The 4 bits in TPBANK0 are kept as package shared data and are used to * set LED polarity for each of the LED0. */ - regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio"); + pio_np = of_parse_phandle(np, "mediatek,pio", 0); + if (!pio_np) + return -ENODEV; + + regmap = device_node_to_regmap(pio_np); + of_node_put(pio_np); + if (IS_ERR(regmap)) return PTR_ERR(regmap); diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c index 93de88c1c8fd..13570f628aa5 100644 --- a/drivers/net/phy/microchip.c +++ b/drivers/net/phy/microchip.c @@ -474,6 +474,8 @@ static struct phy_driver microchip_phy_driver[] = { /* This mask (0xfffffff2) is to differentiate from * LAN8742 (phy_id 0x0007c130 and 0x0007c131) * and allows future phy_id revisions. + * These PHYs are integrated in LAN7800 and LAN7850 USB/Ethernet + * controllers. */ .phy_id_mask = 0xfffffff2, .name = "Microchip LAN88xx", diff --git a/include/linux/netlink.h b/include/linux/netlink.h index c3ae84a77e16..882e9c1b6c1d 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -63,7 +63,7 @@ netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg) } /* this can be increased when necessary - don't expose to userland */ -#define NETLINK_MAX_COOKIE_LEN 20 +#define NETLINK_MAX_COOKIE_LEN 8 #define NETLINK_MAX_FMTMSG_LEN 80 /** @@ -212,6 +212,7 @@ static inline void nl_set_extack_cookie_u64(struct netlink_ext_ack *extack, { if (!extack) return; + BUILD_BUG_ON(sizeof(extack->cookie) < sizeof(cookie)); memcpy(extack->cookie, &cookie, sizeof(cookie)); extack->cookie_len = sizeof(cookie); } diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h index 1acafd86ab13..3392c09b5d24 100644 --- a/include/linux/phy_fixed.h +++ b/include/linux/phy_fixed.h @@ -13,7 +13,6 @@ struct fixed_phy_status { }; struct device_node; -struct gpio_desc; struct net_device; #if IS_ENABLED(CONFIG_FIXED_PHY) @@ -24,11 +23,6 @@ extern struct phy_device *fixed_phy_register(unsigned int irq, struct fixed_phy_status *status, struct device_node *np); -extern struct phy_device * -fixed_phy_register_with_gpiod(unsigned int irq, - struct fixed_phy_status *status, - struct gpio_desc *gpiod); - extern void fixed_phy_unregister(struct phy_device *phydev); extern int fixed_phy_set_link_update(struct phy_device *phydev, int (*link_update)(struct net_device *, @@ -46,14 +40,6 @@ static inline struct phy_device *fixed_phy_register(unsigned int irq, return ERR_PTR(-ENODEV); } -static inline struct phy_device * -fixed_phy_register_with_gpiod(unsigned int irq, - struct fixed_phy_status *status, - struct gpio_desc *gpiod) -{ - return ERR_PTR(-ENODEV); -} - static inline void fixed_phy_unregister(struct phy_device *phydev) { } diff --git a/include/net/rps.h b/include/net/rps.h index 507f4aa5d39b..d8ab3a08bcc4 100644 --- a/include/net/rps.h +++ b/include/net/rps.h @@ -123,6 +123,30 @@ static inline void sock_rps_record_flow(const struct sock *sk) #endif } +static inline void sock_rps_delete_flow(const struct sock *sk) +{ +#ifdef CONFIG_RPS + struct rps_sock_flow_table *table; + u32 hash, index; + + if (!static_branch_unlikely(&rfs_needed)) + return; + + hash = READ_ONCE(sk->sk_rxhash); + if (!hash) + return; + + rcu_read_lock(); + table = rcu_dereference(net_hotdata.rps_sock_flow_table); + if (table) { + index = hash & table->mask; + if (READ_ONCE(table->ents[index]) != RPS_NO_CPU) + WRITE_ONCE(table->ents[index], RPS_NO_CPU); + } + rcu_read_unlock(); +#endif +} + static inline u32 rps_input_queue_tail_incr(struct softnet_data *sd) { #ifdef CONFIG_RPS diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index da85cc30e382..77a0b52b2eab 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -23,11 +23,12 @@ #if IS_ENABLED(CONFIG_IPV6) #include <net/inet6_hashtables.h> #endif -#include <net/secure_seq.h> #include <net/hotdata.h> #include <net/ip.h> -#include <net/tcp.h> +#include <net/rps.h> +#include <net/secure_seq.h> #include <net/sock_reuseport.h> +#include <net/tcp.h> u32 inet_ehashfn(const struct net *net, const __be32 laddr, const __u16 lport, const __be32 faddr, @@ -790,6 +791,7 @@ void inet_unhash(struct sock *sk) if (sk_unhashed(sk)) return; + sock_rps_delete_flow(sk); if (sk->sk_state == TCP_LISTEN) { struct inet_listen_hashbucket *ilb2; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 358b49caa7b9..dde52b8050b8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -120,6 +120,7 @@ #if IS_ENABLED(CONFIG_IPV6) #include <net/ipv6_stubs.h> #endif +#include <net/rps.h> struct udp_table udp_table __read_mostly; @@ -2200,6 +2201,7 @@ void udp_lib_unhash(struct sock *sk) struct udp_table *udptable = udp_get_table_prot(sk); struct udp_hslot *hslot, *hslot2; + sock_rps_delete_flow(sk); hslot = udp_hashslot(udptable, sock_net(sk), udp_sk(sk)->udp_port_hash); hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 53725ee7ba06..85a9dfeff4d6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -8321,7 +8321,7 @@ static int sctp_hash(struct sock *sk) static void sctp_unhash(struct sock *sk) { - /* STUB */ + sock_rps_delete_flow(sk); } /* Check if port is acceptable. Possibly find first available port. diff --git a/tools/net/ynl/Makefile.deps b/tools/net/ynl/Makefile.deps index a5e6093903fb..e5a5cb1b2cff 100644 --- a/tools/net/ynl/Makefile.deps +++ b/tools/net/ynl/Makefile.deps @@ -33,5 +33,9 @@ CFLAGS_ovs_flow:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) CFLAGS_ovs_vport:=$(call get_hdr_inc,__LINUX_OPENVSWITCH_H,openvswitch.h) CFLAGS_rt-addr:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ $(call get_hdr_inc,__LINUX_IF_ADDR_H,if_addr.h) +CFLAGS_rt-link:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) \ + $(call get_hdr_inc,_LINUX_IF_LINK_H,if_link.h) +CFLAGS_rt-neigh:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) CFLAGS_rt-route:=$(call get_hdr_inc,__LINUX_RTNETLINK_H,rtnetlink.h) +CFLAGS_rt-rule:=$(call get_hdr_inc,__LINUX_FIB_RULES_H,fib_rules.h) CFLAGS_tcp_metrics:=$(call get_hdr_inc,_LINUX_TCP_METRICS_H,tcp_metrics.h) diff --git a/tools/net/ynl/generated/Makefile b/tools/net/ynl/generated/Makefile index 6603ad8d4ce1..9208feed28c1 100644 --- a/tools/net/ynl/generated/Makefile +++ b/tools/net/ynl/generated/Makefile @@ -22,10 +22,9 @@ TOOL:=../pyynl/ynl_gen_c.py TOOL_RST:=../pyynl/ynl_gen_rst.py SPECS_DIR:=../../../../Documentation/netlink/specs -GENS_PATHS=$(shell grep -nrI --files-without-match \ - 'protocol: netlink' \ - $(SPECS_DIR)) -GENS=$(patsubst $(SPECS_DIR)/%.yaml,%,${GENS_PATHS}) rt-addr rt-route +SPECS_PATHS=$(wildcard $(SPECS_DIR)/*.yaml) +GENS_UNSUP=conntrack nftables tc +GENS=$(filter-out ${GENS_UNSUP},$(patsubst $(SPECS_DIR)/%.yaml,%,${SPECS_PATHS})) SRCS=$(patsubst %,%-user.c,${GENS}) HDRS=$(patsubst %,%-user.h,${GENS}) OBJS=$(patsubst %,%-user.o,${GENS}) diff --git a/tools/net/ynl/lib/ynl-priv.h b/tools/net/ynl/lib/ynl-priv.h index 5debb09491e7..416866f85820 100644 --- a/tools/net/ynl/lib/ynl-priv.h +++ b/tools/net/ynl/lib/ynl-priv.h @@ -25,6 +25,7 @@ enum ynl_policy_type { YNL_PT_UINT, YNL_PT_NUL_STR, YNL_PT_BITFIELD32, + YNL_PT_SUBMSG, }; enum ynl_parse_result { @@ -42,7 +43,10 @@ typedef int (*ynl_parse_cb_t)(const struct nlmsghdr *nlh, struct ynl_parse_arg *yarg); struct ynl_policy_attr { - enum ynl_policy_type type; + enum ynl_policy_type type:8; + __u8 is_submsg:1; + __u8 is_selector:1; + __u16 selector_type; unsigned int len; const char *name; const struct ynl_policy_nest *nest; @@ -103,6 +107,8 @@ struct nlmsghdr * ynl_gemsg_start_dump(struct ynl_sock *ys, __u32 id, __u8 cmd, __u8 version); int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr); +int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, + const char *sel_name); /* YNL specific helpers used by the auto-generated code */ diff --git a/tools/net/ynl/lib/ynl.c b/tools/net/ynl/lib/ynl.c index a0b54ad4c073..2a169c3c0797 100644 --- a/tools/net/ynl/lib/ynl.c +++ b/tools/net/ynl/lib/ynl.c @@ -45,8 +45,39 @@ #define perr(_ys, _msg) __yerr(&(_ys)->err, errno, _msg) /* -- Netlink boiler plate */ +static bool +ynl_err_walk_is_sel(const struct ynl_policy_nest *policy, + const struct nlattr *attr) +{ + unsigned int type = ynl_attr_type(attr); + + return policy && type <= policy->max_attr && + policy->table[type].is_selector; +} + +static const struct ynl_policy_nest * +ynl_err_walk_sel_policy(const struct ynl_policy_attr *policy_attr, + const struct nlattr *selector) +{ + const struct ynl_policy_nest *policy = policy_attr->nest; + const char *sel; + unsigned int i; + + if (!policy_attr->is_submsg) + return policy; + + sel = ynl_attr_get_str(selector); + for (i = 0; i <= policy->max_attr; i++) { + if (!strcmp(sel, policy->table[i].name)) + return policy->table[i].nest; + } + + return NULL; +} + static int -ynl_err_walk_report_one(const struct ynl_policy_nest *policy, unsigned int type, +ynl_err_walk_report_one(const struct ynl_policy_nest *policy, + const struct nlattr *selector, unsigned int type, char *str, int str_sz, int *n) { if (!policy) { @@ -67,9 +98,34 @@ ynl_err_walk_report_one(const struct ynl_policy_nest *policy, unsigned int type, return 1; } - if (*n < str_sz) - *n += snprintf(str, str_sz - *n, - ".%s", policy->table[type].name); + if (*n < str_sz) { + int sz; + + sz = snprintf(str, str_sz - *n, + ".%s", policy->table[type].name); + *n += sz; + str += sz; + } + + if (policy->table[type].is_submsg) { + if (!selector) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "(!selector)"); + return 1; + } + + if (ynl_attr_type(selector) != + policy->table[type].selector_type) { + if (*n < str_sz) + *n += snprintf(str, str_sz, "(!=selector)"); + return 1; + } + + if (*n < str_sz) + *n += snprintf(str, str_sz - *n, "(%s)", + ynl_attr_get_str(selector)); + } + return 0; } @@ -78,6 +134,8 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, const struct ynl_policy_nest *policy, char *str, int str_sz, const struct ynl_policy_nest **nest_pol) { + const struct ynl_policy_nest *next_pol; + const struct nlattr *selector = NULL; unsigned int astart_off, aend_off; const struct nlattr *attr; unsigned int data_len; @@ -96,6 +154,10 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, ynl_attr_for_each_payload(start, data_len, attr) { astart_off = (char *)attr - (char *)start; aend_off = (char *)ynl_attr_data_end(attr) - (char *)start; + + if (ynl_err_walk_is_sel(policy, attr)) + selector = attr; + if (aend_off <= off) continue; @@ -109,16 +171,20 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, type = ynl_attr_type(attr); - if (ynl_err_walk_report_one(policy, type, str, str_sz, &n)) + if (ynl_err_walk_report_one(policy, selector, type, str, str_sz, &n)) + return n; + + next_pol = ynl_err_walk_sel_policy(&policy->table[type], selector); + if (!next_pol) return n; if (!off) { if (nest_pol) - *nest_pol = policy->table[type].nest; + *nest_pol = next_pol; return n; } - if (!policy->table[type].nest) { + if (!next_pol) { if (n < str_sz) n += snprintf(str, str_sz, "!nest"); return n; @@ -128,7 +194,7 @@ ynl_err_walk(struct ynl_sock *ys, void *start, void *end, unsigned int off, start = ynl_attr_data(attr); end = start + ynl_attr_data_len(attr); - return n + ynl_err_walk(ys, start, end, off, policy->table[type].nest, + return n + ynl_err_walk(ys, start, end, off, next_pol, &str[n], str_sz - n, nest_pol); } @@ -231,7 +297,7 @@ ynl_ext_ack_check(struct ynl_sock *ys, const struct nlmsghdr *nlh, } n2 = 0; - ynl_err_walk_report_one(nest_pol, type, &miss_attr[n], + ynl_err_walk_report_one(nest_pol, NULL, type, &miss_attr[n], sizeof(miss_attr) - n, &n2); n += n2; @@ -384,6 +450,15 @@ int ynl_attr_validate(struct ynl_parse_arg *yarg, const struct nlattr *attr) return 0; } +int ynl_submsg_failed(struct ynl_parse_arg *yarg, const char *field_name, + const char *sel_name) +{ + yerr(yarg->ys, YNL_ERROR_SUBMSG_KEY, + "Parsing error: Sub-message key not set (msg %s, key %s)", + field_name, sel_name); + return YNL_PARSE_CB_ERROR; +} + /* Generic code */ static void ynl_err_reset(struct ynl_sock *ys) diff --git a/tools/net/ynl/lib/ynl.h b/tools/net/ynl/lib/ynl.h index 32efeb224829..db7c0591a63f 100644 --- a/tools/net/ynl/lib/ynl.h +++ b/tools/net/ynl/lib/ynl.h @@ -23,6 +23,7 @@ enum ynl_error_code { YNL_ERROR_INV_RESP, YNL_ERROR_INPUT_INVALID, YNL_ERROR_INPUT_TOO_BIG, + YNL_ERROR_SUBMSG_KEY, }; /** diff --git a/tools/net/ynl/pyynl/lib/__init__.py b/tools/net/ynl/pyynl/lib/__init__.py index 9137b83e580a..71518b9842ee 100644 --- a/tools/net/ynl/pyynl/lib/__init__.py +++ b/tools/net/ynl/pyynl/lib/__init__.py @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause from .nlspec import SpecAttr, SpecAttrSet, SpecEnumEntry, SpecEnumSet, \ - SpecFamily, SpecOperation + SpecFamily, SpecOperation, SpecSubMessage, SpecSubMessageFormat from .ynl import YnlFamily, Netlink, NlError __all__ = ["SpecAttr", "SpecAttrSet", "SpecEnumEntry", "SpecEnumSet", - "SpecFamily", "SpecOperation", "YnlFamily", "Netlink", "NlError"] + "SpecFamily", "SpecOperation", "SpecSubMessage", "SpecSubMessageFormat", + "YnlFamily", "Netlink", "NlError"] diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 9e143520e2f7..1f8cc34ab3f0 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -14,6 +14,7 @@ import yaml sys.path.append(pathlib.Path(__file__).resolve().parent.as_posix()) from lib import SpecFamily, SpecAttrSet, SpecAttr, SpecOperation, SpecEnumSet, SpecEnumEntry +from lib import SpecSubMessage, SpecSubMessageFormat def c_upper(name): @@ -56,11 +57,20 @@ class Type(SpecAttr): self.request = False self.reply = False + self.is_selector = False + if 'len' in attr: self.len = attr['len'] if 'nested-attributes' in attr: - self.nested_attrs = attr['nested-attributes'] + nested = attr['nested-attributes'] + elif 'sub-message' in attr: + nested = attr['sub-message'] + else: + nested = None + + if nested: + self.nested_attrs = nested if self.nested_attrs == family.name: self.nested_render_name = c_lower(f"{family.ident_name}") else: @@ -119,7 +129,9 @@ class Type(SpecAttr): return c_upper(value) def resolve(self): - if 'name-prefix' in self.attr: + if 'parent-sub-message' in self.attr: + enum_name = self.attr['parent-sub-message'].enum_name + elif 'name-prefix' in self.attr: enum_name = f"{self.attr['name-prefix']}{self.name}" else: enum_name = f"{self.attr_set.name_prefix}{self.name}" @@ -474,7 +486,10 @@ class TypeString(Type): ri.cw.p(f"char *{self.c_name};") def _attr_typol(self): - return f'.type = YNL_PT_NUL_STR, ' + typol = f'.type = YNL_PT_NUL_STR, ' + if self.is_selector: + typol += '.is_selector = 1, ' + return typol def _attr_policy(self, policy): if 'exact-len' in self.checks: @@ -867,14 +882,51 @@ class TypeNestTypeValue(Type): return get_lines, init_lines, local_vars +class TypeSubMessage(TypeNest): + def __init__(self, family, attr_set, attr, value): + super().__init__(family, attr_set, attr, value) + + self.selector = Selector(attr, attr_set) + + def _attr_typol(self): + typol = f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, ' + typol += f'.is_submsg = 1, .selector_type = {self.attr_set[self["selector"]].value} ' + return typol + + def _attr_get(self, ri, var): + sel = c_lower(self['selector']) + get_lines = [f'if (!{var}->{sel})', + f'return ynl_submsg_failed(yarg, "%s", "%s");' % + (self.name, self['selector']), + f"if ({self.nested_render_name}_parse(&parg, {var}->{sel}, attr))", + "return YNL_PARSE_CB_ERROR;"] + init_lines = [f"parg.rsp_policy = &{self.nested_render_name}_nest;", + f"parg.data = &{var}->{self.c_name};"] + return get_lines, init_lines, None + + +class Selector: + def __init__(self, msg_attr, attr_set): + self.name = msg_attr["selector"] + + if self.name in attr_set: + self.attr = attr_set[self.name] + self.attr.is_selector = True + self._external = False + else: + raise Exception("Passing selectors from external nests not supported") + + class Struct: - def __init__(self, family, space_name, type_list=None, inherited=None): + def __init__(self, family, space_name, type_list=None, + inherited=None, submsg=None): self.family = family self.space_name = space_name self.attr_set = family.attr_sets[space_name] # Use list to catch comparisons with empty sets self._inherited = inherited if inherited is not None else [] self.inherited = [] + self.submsg = submsg self.nested = type_list is None if family.name == c_lower(space_name): @@ -1047,6 +1099,8 @@ class AttrSet(SpecAttrSet): raise Exception(f'new_attr: unsupported sub-type {elem["sub-type"]}') elif elem['type'] == 'nest-type-value': t = TypeNestTypeValue(self.family, self, elem, value) + elif elem['type'] == 'sub-message': + t = TypeSubMessage(self.family, self, elem, value) else: raise Exception(f"No typed class for type {elem['type']}") @@ -1091,6 +1145,16 @@ class Operation(SpecOperation): self.has_ntf = True +class SubMessage(SpecSubMessage): + def __init__(self, family, yaml): + super().__init__(family, yaml) + + self.render_name = c_lower(family.ident_name + '-' + yaml['name']) + + def resolve(self): + self.resolve_up(super()) + + class Family(SpecFamily): def __init__(self, file_name, exclude_ops): # Added by resolve: @@ -1173,6 +1237,9 @@ class Family(SpecFamily): def new_operation(self, elem, req_value, rsp_value): return Operation(self, elem, req_value, rsp_value) + def new_sub_message(self, elem): + return SubMessage(self, elem) + def is_classic(self): return self.proto == 'netlink-raw' @@ -1225,20 +1292,70 @@ class Family(SpecFamily): for _, spec in self.attr_sets[name].items(): if 'nested-attributes' in spec: nested = spec['nested-attributes'] - # If the unknown nest we hit is recursive it's fine, it'll be a pointer - if self.pure_nested_structs[nested].recursive: - continue - if nested not in pns_key_seen: - # Dicts are sorted, this will make struct last - struct = self.pure_nested_structs.pop(name) - self.pure_nested_structs[name] = struct - finished = False - break + elif 'sub-message' in spec: + nested = spec.sub_message + else: + continue + + # If the unknown nest we hit is recursive it's fine, it'll be a pointer + if self.pure_nested_structs[nested].recursive: + continue + if nested not in pns_key_seen: + # Dicts are sorted, this will make struct last + struct = self.pure_nested_structs.pop(name) + self.pure_nested_structs[name] = struct + finished = False + break if finished: pns_key_seen.add(name) else: pns_key_list.append(name) + def _load_nested_set_nest(self, spec): + inherit = set() + nested = spec['nested-attributes'] + if nested not in self.root_sets: + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) + else: + raise Exception(f'Using attr set as root and nested not supported - {nested}') + + if 'type-value' in spec: + if nested in self.root_sets: + raise Exception("Inheriting members to a space used as root not supported") + inherit.update(set(spec['type-value'])) + elif spec['type'] == 'indexed-array': + inherit.add('idx') + self.pure_nested_structs[nested].set_inherited(inherit) + + return nested + + def _load_nested_set_submsg(self, spec): + # Fake the struct type for the sub-message itself + # its not a attr_set but codegen wants attr_sets. + submsg = self.sub_msgs[spec["sub-message"]] + nested = submsg.name + + attrs = [] + for name, fmt in submsg.formats.items(): + attrs.append({ + "name": name, + "type": "nest", + "parent-sub-message": spec, + "nested-attributes": fmt['attribute-set'] + }) + + self.attr_sets[nested] = AttrSet(self, { + "name": nested, + "name-pfx": self.name + '-' + spec.name + '-', + "attributes": attrs + }) + + if nested not in self.pure_nested_structs: + self.pure_nested_structs[nested] = Struct(self, nested, submsg=submsg) + + return nested + def _load_nested_sets(self): attr_set_queue = list(self.root_sets.keys()) attr_set_seen = set(self.root_sets.keys()) @@ -1246,37 +1363,32 @@ class Family(SpecFamily): while len(attr_set_queue): a_set = attr_set_queue.pop(0) for attr, spec in self.attr_sets[a_set].items(): - if 'nested-attributes' not in spec: + if 'nested-attributes' in spec: + nested = self._load_nested_set_nest(spec) + elif 'sub-message' in spec: + nested = self._load_nested_set_submsg(spec) + else: continue - nested = spec['nested-attributes'] if nested not in attr_set_seen: attr_set_queue.append(nested) attr_set_seen.add(nested) - inherit = set() - if nested not in self.root_sets: - if nested not in self.pure_nested_structs: - self.pure_nested_structs[nested] = Struct(self, nested, inherited=inherit) - else: - raise Exception(f'Using attr set as root and nested not supported - {nested}') - - if 'type-value' in spec: - if nested in self.root_sets: - raise Exception("Inheriting members to a space used as root not supported") - inherit.update(set(spec['type-value'])) - elif spec['type'] == 'indexed-array': - inherit.add('idx') - self.pure_nested_structs[nested].set_inherited(inherit) - for root_set, rs_members in self.root_sets.items(): for attr, spec in self.attr_sets[root_set].items(): if 'nested-attributes' in spec: nested = spec['nested-attributes'] + elif 'sub-message' in spec: + nested = spec.sub_message + else: + nested = None + + if nested: if attr in rs_members['request']: self.pure_nested_structs[nested].request = True if attr in rs_members['reply']: self.pure_nested_structs[nested].reply = True + if spec.is_multi_val(): child = self.pure_nested_structs.get(nested) child.in_multi_val = True @@ -1286,20 +1398,26 @@ class Family(SpecFamily): # Propagate the request / reply / recursive for attr_set, struct in reversed(self.pure_nested_structs.items()): for _, spec in self.attr_sets[attr_set].items(): - if 'nested-attributes' in spec: - child_name = spec['nested-attributes'] - struct.child_nests.add(child_name) - child = self.pure_nested_structs.get(child_name) - if child: - if not child.recursive: - struct.child_nests.update(child.child_nests) - child.request |= struct.request - child.reply |= struct.reply - if spec.is_multi_val(): - child.in_multi_val = True if attr_set in struct.child_nests: struct.recursive = True + if 'nested-attributes' in spec: + child_name = spec['nested-attributes'] + elif 'sub-message' in spec: + child_name = spec.sub_message + else: + continue + + struct.child_nests.add(child_name) + child = self.pure_nested_structs.get(child_name) + if child: + if not child.recursive: + struct.child_nests.update(child.child_nests) + child.request |= struct.request + child.reply |= struct.reply + if spec.is_multi_val(): + child.in_multi_val = True + self._sort_pure_types() def _load_attr_use(self): @@ -1736,11 +1854,34 @@ def print_dump_prototype(ri): print_prototype(ri, "request") +def put_typol_submsg(cw, struct): + cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[] =') + + i = 0 + for name, arg in struct.member_list(): + cw.p('[%d] = { .type = YNL_PT_SUBMSG, .name = "%s", .nest = &%s_nest, },' % + (i, name, arg.nested_render_name)) + i += 1 + + cw.block_end(line=';') + cw.nl() + + cw.block_start(line=f'const struct ynl_policy_nest {struct.render_name}_nest =') + cw.p(f'.max_attr = {i - 1},') + cw.p(f'.table = {struct.render_name}_policy,') + cw.block_end(line=';') + cw.nl() + + def put_typol_fwd(cw, struct): cw.p(f'extern const struct ynl_policy_nest {struct.render_name}_nest;') def put_typol(cw, struct): + if struct.submsg: + put_typol_submsg(cw, struct) + return + type_max = struct.attr_set.max_name cw.block_start(line=f'const struct ynl_policy_attr {struct.render_name}_policy[{type_max} + 1] =') @@ -1826,8 +1967,9 @@ def put_req_nested(ri, struct): local_vars = [] init_lines = [] - local_vars.append('struct nlattr *nest;') - init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") + if struct.submsg is None: + local_vars.append('struct nlattr *nest;') + init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);") has_anest = False has_count = False @@ -1849,7 +1991,8 @@ def put_req_nested(ri, struct): for _, arg in struct.member_list(): arg.attr_put(ri, "obj") - ri.cw.p("ynl_attr_nest_end(nlh, nest);") + if struct.submsg is None: + ri.cw.p("ynl_attr_nest_end(nlh, nest);") ri.cw.nl() ri.cw.p('return 0;') @@ -1886,6 +2029,7 @@ def _multi_parse(ri, struct, init_lines, local_vars): if 'multi-attr' in aspec: multi_attrs.add(arg) needs_parg |= 'nested-attributes' in aspec + needs_parg |= 'sub-message' in aspec if array_nests or multi_attrs: local_vars.append('int i;') if needs_parg: @@ -2004,9 +2148,43 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.nl() +def parse_rsp_submsg(ri, struct): + parse_rsp_nested_prototype(ri, struct, suffix='') + + var = 'dst' + + ri.cw.block_start() + ri.cw.write_func_lvar(['const struct nlattr *attr = nested;', + f'{struct.ptr_name}{var} = yarg->data;', + 'struct ynl_parse_arg parg;']) + + ri.cw.p('parg.ys = yarg->ys;') + ri.cw.nl() + + first = True + for name, arg in struct.member_list(): + kw = 'if' if first else 'else if' + first = False + + ri.cw.block_start(line=f'{kw} (!strcmp(sel, "{name}"))') + get_lines, init_lines, _ = arg._attr_get(ri, var) + for line in init_lines: + ri.cw.p(line) + for line in get_lines: + ri.cw.p(line) + if arg.presence_type() == 'present': + ri.cw.p(f"{var}->_present.{arg.c_name} = 1;") + ri.cw.block_end() + ri.cw.p('return 0;') + ri.cw.block_end() + ri.cw.nl() + + def parse_rsp_nested_prototype(ri, struct, suffix=';'): func_args = ['struct ynl_parse_arg *yarg', 'const struct nlattr *nested'] + if struct.submsg: + func_args.insert(1, 'const char *sel') for arg in struct.inherited: func_args.append('__u32 ' + arg) @@ -2015,6 +2193,9 @@ def parse_rsp_nested_prototype(ri, struct, suffix=';'): def parse_rsp_nested(ri, struct): + if struct.submsg: + return parse_rsp_submsg(ri, struct) + parse_rsp_nested_prototype(ri, struct, suffix='') local_vars = ['const struct nlattr *attr;', @@ -3302,8 +3483,7 @@ def main(): has_recursive_nests = True if has_recursive_nests: cw.nl() - for name in parsed.pure_nested_structs: - struct = Struct(parsed, name) + for struct in parsed.pure_nested_structs.values(): put_typol(cw, struct) for name in parsed.root_sets: struct = Struct(parsed, name) diff --git a/tools/net/ynl/samples/.gitignore b/tools/net/ynl/samples/.gitignore index 7f9781cf532f..b3ec3fb0929f 100644 --- a/tools/net/ynl/samples/.gitignore +++ b/tools/net/ynl/samples/.gitignore @@ -4,4 +4,5 @@ netdev ovs page-pool rt-addr +rt-link rt-route diff --git a/tools/net/ynl/samples/rt-link.c b/tools/net/ynl/samples/rt-link.c new file mode 100644 index 000000000000..acdd4b4a0f74 --- /dev/null +++ b/tools/net/ynl/samples/rt-link.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <string.h> + +#include <ynl.h> + +#include <arpa/inet.h> +#include <net/if.h> + +#include "rt-link-user.h" + +static void rt_link_print(struct rt_link_getlink_rsp *r) +{ + unsigned int i; + + printf("%3d: ", r->_hdr.ifi_index); + + if (r->_len.ifname) + printf("%16s: ", r->ifname); + + if (r->_present.mtu) + printf("mtu %5d ", r->mtu); + + if (r->linkinfo._len.kind) + printf("kind %-8s ", r->linkinfo.kind); + else + printf(" %8s ", ""); + + if (r->prop_list._count.alt_ifname) { + printf("altname "); + for (i = 0; i < r->prop_list._count.alt_ifname; i++) + printf("%s ", r->prop_list.alt_ifname[i]->str); + printf(" "); + } + + if (r->linkinfo._present.data && r->linkinfo.data._present.netkit) { + struct rt_link_linkinfo_netkit_attrs *netkit; + const char *name; + + netkit = &r->linkinfo.data.netkit; + printf("primary %d ", netkit->primary); + + name = NULL; + if (netkit->_present.policy) + name = rt_link_netkit_policy_str(netkit->policy); + if (name) + printf("policy %s ", name); + } + + printf("\n"); +} + +static int rt_link_create_netkit(struct ynl_sock *ys) +{ + struct rt_link_getlink_ntf *ntf_gl; + struct rt_link_newlink_req *req; + struct ynl_ntf_base_type *ntf; + int ret; + + req = rt_link_newlink_req_alloc(); + if (!req) { + fprintf(stderr, "Can't alloc req\n"); + return -1; + } + + /* rtnetlink doesn't provide info about the created object. + * It expects us to set the ECHO flag and the dig the info out + * of the notifications... + */ + rt_link_newlink_req_set_nlflags(req, NLM_F_CREATE | NLM_F_ECHO); + + rt_link_newlink_req_set_linkinfo_kind(req, "netkit"); + + /* Test error messages */ + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, 10); + ret = rt_link_newlink(ys, req); + if (ret) { + printf("Testing error message for policy being bad:\n\t%s\n", ys->err.msg); + } else { + fprintf(stderr, "Warning: unexpected success creating netkit with bad attrs\n"); + goto created; + } + + rt_link_newlink_req_set_linkinfo_data_netkit_policy(req, NETKIT_DROP); + + ret = rt_link_newlink(ys, req); +created: + rt_link_newlink_req_free(req); + if (ret) { + fprintf(stderr, "YNL: %s\n", ys->err.msg); + return -1; + } + + if (!ynl_has_ntf(ys)) { + fprintf(stderr, + "Warning: interface created but received no notification, won't delete the interface\n"); + return 0; + } + + ntf = ynl_ntf_dequeue(ys); + if (ntf->cmd != RTM_NEWLINK) { + fprintf(stderr, + "Warning: unexpected notification type, won't delete the interface\n"); + return 0; + } + ntf_gl = (void *)ntf; + ret = ntf_gl->obj._hdr.ifi_index; + ynl_ntf_free(ntf); + + return ret; +} + +static void rt_link_del(struct ynl_sock *ys, int ifindex) +{ + struct rt_link_dellink_req *req; + + req = rt_link_dellink_req_alloc(); + if (!req) { + fprintf(stderr, "Can't alloc req\n"); + return; + } + + req->_hdr.ifi_index = ifindex; + if (rt_link_dellink(ys, req)) + fprintf(stderr, "YNL: %s\n", ys->err.msg); + else + fprintf(stderr, + "Trying to delete a Netkit interface (ifindex %d)\n", + ifindex); + + rt_link_dellink_req_free(req); +} + +int main(int argc, char **argv) +{ + struct rt_link_getlink_req_dump *req; + struct rt_link_getlink_list *rsp; + struct ynl_error yerr; + struct ynl_sock *ys; + int created = 0; + + ys = ynl_sock_create(&ynl_rt_link_family, &yerr); + if (!ys) { + fprintf(stderr, "YNL: %s\n", yerr.msg); + return 1; + } + + if (argc > 1) { + fprintf(stderr, "Trying to create a Netkit interface\n"); + created = rt_link_create_netkit(ys); + if (created < 0) + goto err_destroy; + } + + req = rt_link_getlink_req_dump_alloc(); + if (!req) + goto err_del_ifc; + + rsp = rt_link_getlink_dump(ys, req); + rt_link_getlink_req_dump_free(req); + if (!rsp) + goto err_close; + + if (ynl_dump_empty(rsp)) + fprintf(stderr, "Error: no links reported\n"); + ynl_dump_foreach(rsp, link) + rt_link_print(link); + rt_link_getlink_list_free(rsp); + + if (created) + rt_link_del(ys, created); + + ynl_sock_destroy(ys); + return 0; + +err_close: + fprintf(stderr, "YNL: %s\n", ys->err.msg); +err_del_ifc: + if (created) + rt_link_del(ys, created); +err_destroy: + ynl_sock_destroy(ys); + return 2; +} diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py index ad5ff645183a..3bccddf8cbc5 100644 --- a/tools/testing/selftests/drivers/net/lib/py/env.py +++ b/tools/testing/selftests/drivers/net/lib/py/env.py @@ -12,7 +12,7 @@ from .remote import Remote class NetDrvEnvBase: """ - Base class for a NIC / host envirnoments + Base class for a NIC / host environments Attributes: test_dir: Path to the source directory of the test diff --git a/tools/testing/selftests/net/ovpn/Makefile b/tools/testing/selftests/net/ovpn/Makefile index 2d102878cb6d..e0926d76b4c8 100644 --- a/tools/testing/selftests/net/ovpn/Makefile +++ b/tools/testing/selftests/net/ovpn/Makefile @@ -20,6 +20,7 @@ LDLIBS += $(VAR_LDLIBS) TEST_FILES = common.sh TEST_PROGS = test.sh \ + test-large-mtu.sh \ test-chachapoly.sh \ test-tcp.sh \ test-float.sh \ diff --git a/tools/testing/selftests/net/ovpn/common.sh b/tools/testing/selftests/net/ovpn/common.sh index 7502292a1ee0..88869c675d03 100644 --- a/tools/testing/selftests/net/ovpn/common.sh +++ b/tools/testing/selftests/net/ovpn/common.sh @@ -11,6 +11,8 @@ ALG=${ALG:-aes} PROTO=${PROTO:-UDP} FLOAT=${FLOAT:-0} +LAN_IP="11.11.11.11" + create_ns() { ip netns add peer${1} } @@ -24,15 +26,25 @@ setup_ns() { ip link add veth${p} netns peer0 type veth peer name veth${p} netns peer${p} ip -n peer0 addr add 10.10.${p}.1/24 dev veth${p} + ip -n peer0 addr add fd00:0:0:${p}::1/64 dev veth${p} ip -n peer0 link set veth${p} up ip -n peer${p} addr add 10.10.${p}.2/24 dev veth${p} + ip -n peer${p} addr add fd00:0:0:${p}::2/64 dev veth${p} ip -n peer${p} link set veth${p} up done fi ip netns exec peer${1} ${OVPN_CLI} new_iface tun${1} $MODE ip -n peer${1} addr add ${2} dev tun${1} + # add a secondary IP to peer 1, to test a LAN behind a client + if [ ${1} -eq 1 -a -n "${LAN_IP}" ]; then + ip -n peer${1} addr add ${LAN_IP} dev tun${1} + ip -n peer0 route add ${LAN_IP} via $(echo ${2} |sed -e s'!/.*!!') dev tun0 + fi + if [ -n "${3}" ]; then + ip -n peer${1} link set mtu ${3} dev tun${1} + fi ip -n peer${1} link set tun${1} up } @@ -46,7 +58,11 @@ add_peer() { data64.key done else - ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} 1 10.10.${1}.1 1 + RADDR=$(awk "NR == ${1} {print \$2}" ${UDP_PEERS_FILE}) + RPORT=$(awk "NR == ${1} {print \$3}" ${UDP_PEERS_FILE}) + LPORT=$(awk "NR == ${1} {print \$5}" ${UDP_PEERS_FILE}) + ip netns exec peer${1} ${OVPN_CLI} new_peer tun${1} ${1} ${LPORT} \ + ${RADDR} ${RPORT} ip netns exec peer${1} ${OVPN_CLI} new_key tun${1} ${1} 1 0 ${ALG} 1 \ data64.key fi diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c b/tools/testing/selftests/net/ovpn/ovpn-cli.c index 69e41fc07fbc..de9c26f98b2e 100644 --- a/tools/testing/selftests/net/ovpn/ovpn-cli.c +++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c @@ -1753,8 +1753,11 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, if (host) { ret = getaddrinfo(host, service, &hints, &result); - if (ret == EAI_NONAME || ret == EAI_FAIL) + if (ret) { + fprintf(stderr, "getaddrinfo on remote error: %s\n", + gai_strerror(ret)); return -1; + } if (!(result->ai_family == AF_INET && result->ai_addrlen == sizeof(struct sockaddr_in)) && @@ -1769,8 +1772,11 @@ static int ovpn_parse_remote(struct ovpn_ctx *ovpn, const char *host, if (vpnip) { ret = getaddrinfo(vpnip, NULL, &hints, &result); - if (ret == EAI_NONAME || ret == EAI_FAIL) + if (ret) { + fprintf(stderr, "getaddrinfo on vpnip error: %s\n", + gai_strerror(ret)); return -1; + } if (!(result->ai_family == AF_INET && result->ai_addrlen == sizeof(struct sockaddr_in)) && @@ -1928,7 +1934,8 @@ static void ovpn_waitbg(void) static int ovpn_run_cmd(struct ovpn_ctx *ovpn) { - char peer_id[10], vpnip[INET6_ADDRSTRLEN], raddr[128], rport[10]; + char peer_id[10], vpnip[INET6_ADDRSTRLEN], laddr[128], lport[10]; + char raddr[128], rport[10]; int n, ret; FILE *fp; @@ -2044,8 +2051,8 @@ static int ovpn_run_cmd(struct ovpn_ctx *ovpn) return -1; } - while ((n = fscanf(fp, "%s %s %s %s\n", peer_id, raddr, rport, - vpnip)) == 4) { + while ((n = fscanf(fp, "%s %s %s %s %s %s\n", peer_id, laddr, + lport, raddr, rport, vpnip)) == 6) { struct ovpn_ctx peer_ctx = { 0 }; peer_ctx.ifindex = ovpn->ifindex; @@ -2349,7 +2356,7 @@ int main(int argc, char *argv[]) } memset(&ovpn, 0, sizeof(ovpn)); - ovpn.sa_family = AF_INET; + ovpn.sa_family = AF_UNSPEC; ovpn.cipher = OVPN_CIPHER_ALG_NONE; ovpn.cmd = ovpn_parse_cmd(argv[1]); diff --git a/tools/testing/selftests/net/ovpn/test.sh b/tools/testing/selftests/net/ovpn/test.sh index 7b62897b0240..e8acdc303307 100755 --- a/tools/testing/selftests/net/ovpn/test.sh +++ b/tools/testing/selftests/net/ovpn/test.sh @@ -18,7 +18,7 @@ for p in $(seq 0 ${NUM_PEERS}); do done for p in $(seq 0 ${NUM_PEERS}); do - setup_ns ${p} 5.5.5.$((${p} + 1))/24 + setup_ns ${p} 5.5.5.$((${p} + 1))/24 ${MTU} done for p in $(seq 0 ${NUM_PEERS}); do @@ -34,8 +34,12 @@ sleep 1 for p in $(seq 1 ${NUM_PEERS}); do ip netns exec peer0 ping -qfc 500 -w 3 5.5.5.$((${p} + 1)) + ip netns exec peer0 ping -qfc 500 -s 3000 -w 3 5.5.5.$((${p} + 1)) done +# ping LAN behind client 1 +ip netns exec peer0 ping -qfc 500 -w 3 ${LAN_IP} + if [ "$FLOAT" == "1" ]; then # make clients float.. for p in $(seq 1 ${NUM_PEERS}); do diff --git a/tools/testing/selftests/net/ovpn/udp_peers.txt b/tools/testing/selftests/net/ovpn/udp_peers.txt index 32f14bd9347a..e9773ddf875c 100644 --- a/tools/testing/selftests/net/ovpn/udp_peers.txt +++ b/tools/testing/selftests/net/ovpn/udp_peers.txt @@ -1,5 +1,6 @@ -1 10.10.1.2 1 5.5.5.2 -2 10.10.2.2 1 5.5.5.3 -3 10.10.3.2 1 5.5.5.4 -4 10.10.4.2 1 5.5.5.5 -5 10.10.5.2 1 5.5.5.6 +1 10.10.1.1 1 10.10.1.2 1 5.5.5.2 +2 10.10.2.1 1 10.10.2.2 1 5.5.5.3 +3 10.10.3.1 1 10.10.3.2 1 5.5.5.4 +4 fd00:0:0:4::1 1 fd00:0:0:4::2 1 5.5.5.5 +5 fd00:0:0:5::1 1 fd00:0:0:5::2 1 5.5.5.6 +6 fd00:0:0:6::1 1 fd00:0:0:6::2 1 5.5.5.7 diff --git a/tools/testing/vsock/timeout.c b/tools/testing/vsock/timeout.c index 44aee49b6cee..1453d38e08bb 100644 --- a/tools/testing/vsock/timeout.c +++ b/tools/testing/vsock/timeout.c @@ -21,6 +21,7 @@ #include <stdbool.h> #include <unistd.h> #include <stdio.h> +#include <time.h> #include "timeout.h" static volatile bool timeout; @@ -28,6 +29,8 @@ static volatile bool timeout; /* SIGALRM handler function. Do not use sleep(2), alarm(2), or * setitimer(2) while using this API - they may interfere with each * other. + * + * If you need to sleep, please use timeout_sleep() provided by this API. */ void sigalrm(int signo) { @@ -58,3 +61,18 @@ void timeout_end(void) alarm(0); timeout = false; } + +/* Sleep in a timeout section. + * + * nanosleep(2) can be used with this API since POSIX.1 explicitly + * specifies that it does not interact with signals. + */ +int timeout_usleep(useconds_t usec) +{ + struct timespec ts = { + .tv_sec = usec / 1000000, + .tv_nsec = (usec % 1000000) * 1000, + }; + + return nanosleep(&ts, NULL); +} diff --git a/tools/testing/vsock/timeout.h b/tools/testing/vsock/timeout.h index ecb7c840e65a..1c3fcad87a49 100644 --- a/tools/testing/vsock/timeout.h +++ b/tools/testing/vsock/timeout.h @@ -11,5 +11,6 @@ void sigalrm(int signo); void timeout_begin(unsigned int seconds); void timeout_check(const char *operation); void timeout_end(void); +int timeout_usleep(useconds_t usec); #endif /* TIMEOUT_H */ diff --git a/tools/testing/vsock/vsock_test.c b/tools/testing/vsock/vsock_test.c index 613551132a96..9ea33b78b9fc 100644 --- a/tools/testing/vsock/vsock_test.c +++ b/tools/testing/vsock/vsock_test.c @@ -1058,18 +1058,39 @@ static void sigpipe(int signo) have_sigpipe = 1; } +#define SEND_SLEEP_USEC (10 * 1000) + static void test_stream_check_sigpipe(int fd) { ssize_t res; have_sigpipe = 0; - res = send(fd, "A", 1, 0); - if (res != -1) { - fprintf(stderr, "expected send(2) failure, got %zi\n", res); - exit(EXIT_FAILURE); + /* When the other peer calls shutdown(SHUT_RD), there is a chance that + * the send() call could occur before the message carrying the close + * information arrives over the transport. In such cases, the send() + * might still succeed. To avoid this race, let's retry the send() call + * a few times, ensuring the test is more reliable. + */ + timeout_begin(TIMEOUT); + while(1) { + res = send(fd, "A", 1, 0); + if (res == -1 && errno != EINTR) + break; + + /* Sleep a little before trying again to avoid flooding the + * other peer and filling its receive buffer, causing + * false-negative. + */ + timeout_usleep(SEND_SLEEP_USEC); + timeout_check("send"); } + timeout_end(); + if (errno != EPIPE) { + fprintf(stderr, "unexpected send(2) errno %d\n", errno); + exit(EXIT_FAILURE); + } if (!have_sigpipe) { fprintf(stderr, "SIGPIPE expected\n"); exit(EXIT_FAILURE); @@ -1077,12 +1098,21 @@ static void test_stream_check_sigpipe(int fd) have_sigpipe = 0; - res = send(fd, "A", 1, MSG_NOSIGNAL); - if (res != -1) { - fprintf(stderr, "expected send(2) failure, got %zi\n", res); - exit(EXIT_FAILURE); + timeout_begin(TIMEOUT); + while(1) { + res = send(fd, "A", 1, MSG_NOSIGNAL); + if (res == -1 && errno != EINTR) + break; + + timeout_usleep(SEND_SLEEP_USEC); + timeout_check("send"); } + timeout_end(); + if (errno != EPIPE) { + fprintf(stderr, "unexpected send(2) errno %d\n", errno); + exit(EXIT_FAILURE); + } if (have_sigpipe) { fprintf(stderr, "SIGPIPE not expected\n"); exit(EXIT_FAILURE); |
