Pull networking fixes from Jakub Kicinski: "Including fixes from netfilter and IPsec. Current release - regressions: - do not acquire dev->tx_global_lock in netdev_watchdog_up() - ethtool: keep rtnl_lock for ops using ethtool_op_get_link() - fix deadlock in nested UP notifier events Current release - new code bugs: - eth: - cn20k: fix subbank free list indexing for search order - airoha: fix BQL underflow in shared QDMA TX ring Previous releases - regressions: - netfilter: - flowtable: fix offloaded ct timeout never being extended - nf_conncount: prevent connlimit drops for early confirmed ct Previous releases - always broken: - require CAP_NET_ADMIN in the originating netns when modifying cross-netns devices - report NAPI thread PID in the caller's pid namespace - mac802154: fix dirty frag in in-place crypto for IOT radios - sctp: hold socket lock when dumping endpoints in sctp_diag, avoid an overflow - eth: gve: fix header buffer corruption with header-split and HW-GRO - af_key: initialize alg_key_len for IPComp states, prevent OOB read" * tag 'net-7.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net: (213 commits) selftests: bonding: add a test for VLAN propagation over a bonded real device vlan: defer real device state propagation to netdev_work net: add the driver-facing netdev_work scheduling API net: turn the rx_mode work into a generic netdev_work facility net: ethtool: keep rtnl_lock for ops using ethtool_op_get_link() rxrpc: Fix rxrpc_rotate_tx_rotate() to check there's something to rotate rxrpc: Fix leak of released call in recvmsg(MSG_PEEK) rxrpc: Fix socket notification race rxrpc: Fix potential infinite loop in rxrpc_recvmsg() rxrpc: Fix oob challenge leak in cleanup after notification failure rxrpc: Fix the reception of a reply packet before data transmission afs: Fix uncancelled rxrpc OOB message handler afs: Fix further netns teardown to cancel the preallocation charger rxrpc: Fix double unlock in rxrpc_recvmsg() rxrpc: Fix leak of connection from OOB challenge rxrpc: Fix ACKALL packet handling net: hns3: differentiate autoneg default values between copper and fiber net: hns3: fix permanent link down deadlock after reset net: hns3: refactor MAC autoneg and speed configuration net: hns3: unify copper port ksettings configuration path ...
Unified · Split
| @@ -530,7 +530,8 @@ Luca Ceresoli <luca.ceresoli@bootlin.com> <luca@lucaceresoli.net> · 529 unmodified lines | |||
| 530 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> | 530 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> |
| 531 | Lucas De Marchi <demarchi@kernel.org> <lucas.demarchi@intel.com> | 531 | Lucas De Marchi <demarchi@kernel.org> <lucas.demarchi@intel.com> |
| 532 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> | 532 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> |
| 533 | Luo Jie <quic_luoj@quicinc.com> <luoj@codeaurora.org> | 533 | Luo Jie <jie.luo@oss.qualcomm.com> <luoj@codeaurora.org> |
| 534 | Luo Jie <jie.luo@oss.qualcomm.com> <quic_luoj@quicinc.com> | ||
| 534 | Lance Yang <lance.yang@linux.dev> <ioworker0@gmail.com> | 535 | Lance Yang <lance.yang@linux.dev> <ioworker0@gmail.com> |
| 535 | Lance Yang <lance.yang@linux.dev> <mingzhe.yang@ly.com> | 536 | Lance Yang <lance.yang@linux.dev> <mingzhe.yang@ly.com> |
| 536 | Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com> | 537 | Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com> |
| @@ -8,7 +8,7 @@ title: Qualcomm CMN PLL Clock Controller on IPQ SoC · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Bjorn Andersson <andersson@kernel.org> | 10 | - Bjorn Andersson <andersson@kernel.org> |
| 11 | - Luo Jie <quic_luoj@quicinc.com> | 11 | - Luo Jie <jie.luo@oss.qualcomm.com> |
| 12 | 12 | ||
| 13 | description: | 13 | description: |
| 14 | The CMN (or common) PLL clock controller expects a reference | 14 | The CMN (or common) PLL clock controller expects a reference |
| @@ -8,7 +8,7 @@ title: Qualcomm NSS Clock & Reset Controller on QCA8386/QCA8084 · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Bjorn Andersson <andersson@kernel.org> | 10 | - Bjorn Andersson <andersson@kernel.org> |
| 11 | - Luo Jie <quic_luoj@quicinc.com> | 11 | - Luo Jie <jie.luo@oss.qualcomm.com> |
| 12 | 12 | ||
| 13 | description: | | 13 | description: | |
| 14 | Qualcomm NSS clock control module provides the clocks and resets | 14 | Qualcomm NSS clock control module provides the clocks and resets |
| @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml# · 6 unmodified lines | |||
| 7 | title: Qualcomm IPQ packet process engine (PPE) | 7 | title: Qualcomm IPQ packet process engine (PPE) |
| 8 | 8 | ||
| 9 | maintainers: | 9 | maintainers: |
| 10 | - Luo Jie <quic_luoj@quicinc.com> | 10 | - Luo Jie <jie.luo@oss.qualcomm.com> |
| 11 | - Lei Wei <quic_leiwei@quicinc.com> | 11 | - Lei Wei <quic_leiwei@quicinc.com> |
| 12 | - Suruchi Agarwal <quic_suruchia@quicinc.com> | 12 | - Suruchi Agarwal <quic_suruchia@quicinc.com> |
| 13 | - Pavithra R <quic_pavir@quicinc.com> | 13 | - Pavithra R <quic_pavir@quicinc.com> |
| @@ -121,8 +121,7 @@ examples: · 120 unmodified lines | |||
| 121 | #size-cells = <0>; | 121 | #size-cells = <0>; |
| 122 | 122 | ||
| 123 | phy1: ethernet-phy@1 { | 123 | phy1: ethernet-phy@1 { |
| 124 | compatible = "ethernet-phy-id0022.1537", | 124 | compatible = "ethernet-phy-id0022.1537"; |
| 125 | "ethernet-phy-ieee802.3-c22"; | ||
| 126 | reg = <1>; | 125 | reg = <1>; |
| 127 | interrupt-parent = <&irqc0>; | 126 | interrupt-parent = <&irqc0>; |
| 128 | interrupts = <0 IRQ_TYPE_LEVEL_LOW>; | 127 | interrupts = <0 IRQ_TYPE_LEVEL_LOW>; |
| @@ -433,6 +433,8 @@ exceptions) notifiers run under the instance lock. Please extend this · 432 unmodified lines | |||
| 433 | documentation whenever you make explicit assumption about lock being held | 433 | documentation whenever you make explicit assumption about lock being held |
| 434 | from a notifier. | 434 | from a notifier. |
| 435 | 435 | ||
| 436 | Drivers **must not** generate nested notifications of the ops-locked types. | ||
| 437 | |||
| 436 | NETDEV_INTERNAL symbol namespace | 438 | NETDEV_INTERNAL symbol namespace |
| 437 | ================================ | 439 | ================================ |
| 438 | 440 | ||
| @@ -22323,9 +22323,9 @@ F: Documentation/devicetree/bindings/power/supply/qcom,pmi8998-charger.yaml · 22322 unmodified lines | |||
| 22323 | F: drivers/power/supply/qcom_smbx.c | 22323 | F: drivers/power/supply/qcom_smbx.c |
| 22324 | 22324 | ||
| 22325 | QUALCOMM PPE DRIVER | 22325 | QUALCOMM PPE DRIVER |
| 22326 | M: Luo Jie <quic_luoj@quicinc.com> | 22326 | M: Luo Jie <jie.luo@oss.qualcomm.com> |
| 22327 | L: netdev@vger.kernel.org | 22327 | L: netdev@vger.kernel.org |
| 22328 | S: Supported | 22328 | S: Maintained |
| 22329 | F: Documentation/devicetree/bindings/net/qcom,ipq9574-ppe.yaml | 22329 | F: Documentation/devicetree/bindings/net/qcom,ipq9574-ppe.yaml |
| 22330 | F: Documentation/networking/device_drivers/ethernet/qualcomm/ppe/ppe.rst | 22330 | F: Documentation/networking/device_drivers/ethernet/qualcomm/ppe/ppe.rst |
| 22331 | F: drivers/net/ethernet/qualcomm/ppe/ | 22331 | F: drivers/net/ethernet/qualcomm/ppe/ |
| @@ -26001,9 +26001,8 @@ S: Maintained · 3669 unmodified lines | |||
| 26001 | F: drivers/net/ethernet/dlink/sundance.c | 26001 | F: drivers/net/ethernet/dlink/sundance.c |
| 26002 | 26002 | ||
| 26003 | SUNPLUS ETHERNET DRIVER | 26003 | SUNPLUS ETHERNET DRIVER |
| 26004 | M: Wells Lu <wellslutw@gmail.com> | ||
| 26005 | L: netdev@vger.kernel.org | 26004 | L: netdev@vger.kernel.org |
| 26006 | S: Maintained | 26005 | S: Orphan |
| 26007 | W: https://sunplus.atlassian.net/wiki/spaces/doc/overview | 26006 | W: https://sunplus.atlassian.net/wiki/spaces/doc/overview |
| 26008 | F: Documentation/devicetree/bindings/net/sunplus,sp7021-emac.yaml | 26007 | F: Documentation/devicetree/bindings/net/sunplus,sp7021-emac.yaml |
| 26009 | F: drivers/net/ethernet/sunplus/ | 26008 | F: drivers/net/ethernet/sunplus/ |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/crc16.h> | 12 | #include <linux/crc16.h> |
| 13 | #include <linux/iopoll.h> | 13 | #include <linux/iopoll.h> |
| 14 | #include <linux/limits.h> | 14 | #include <linux/limits.h> |
| 15 | #include <linux/unaligned.h> | ||
| 15 | #include <net/dsa.h> | 16 | #include <net/dsa.h> |
| 16 | #include "mxl862xx.h" | 17 | #include "mxl862xx.h" |
| 17 | #include "mxl862xx-host.h" | 18 | #include "mxl862xx-host.h" |
| @@ -40,12 +41,13 @@ static void mxl862xx_crc_err_work_fn(struct work_struct *work) · 22 unmodified lines | |||
| 40 | crc_err_work); | 41 | crc_err_work); |
| 41 | struct dsa_port *dp; | 42 | struct dsa_port *dp; |
| 42 | 43 | ||
| 43 | dev_warn(&priv->mdiodev->dev, | ||
| 44 | "MDIO CRC error detected, shutting down all ports\n"); | ||
| 45 | |||
| 46 | rtnl_lock(); | 44 | rtnl_lock(); |
| 47 | dsa_switch_for_each_cpu_port(dp, priv->ds) | 45 | if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) { |
| 48 | dev_close(dp->conduit); | 46 | dev_warn(&priv->mdiodev->dev, |
| 47 | "MDIO CRC error detected, shutting down all ports\n"); | ||
| 48 | dsa_switch_for_each_cpu_port(dp, priv->ds) | ||
| 49 | dev_close(dp->conduit); | ||
| 50 | } | ||
| 49 | rtnl_unlock(); | 51 | rtnl_unlock(); |
| 50 | 52 | ||
| 51 | clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags); | 53 | clear_bit(MXL862XX_FLAG_CRC_ERR, &priv->flags); |
| @@ -349,7 +351,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, · 297 unmodified lines | |||
| 349 | * zero words individually. | 351 | * zero words individually. |
| 350 | */ | 352 | */ |
| 351 | for (i = 0, zeros = 0; i < size / 2 && zeros < RST_DATA_THRESHOLD; i++) | 353 | for (i = 0, zeros = 0; i < size / 2 && zeros < RST_DATA_THRESHOLD; i++) |
| 352 | if (!data[i]) | 354 | if (!get_unaligned_le16(&data[i])) |
| 353 | zeros++; | 355 | zeros++; |
| 354 | 356 | ||
| 355 | if (zeros < RST_DATA_THRESHOLD && (size & 1) && !*(u8 *)&data[i]) | 357 | if (zeros < RST_DATA_THRESHOLD && (size & 1) && !*(u8 *)&data[i]) |
| @@ -395,7 +397,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, · 39 unmodified lines | |||
| 395 | */ | 397 | */ |
| 396 | val = *(u8 *)&data[i] | ((crc & 0xff) << 8); | 398 | val = *(u8 *)&data[i] | ((crc & 0xff) << 8); |
| 397 | } else { | 399 | } else { |
| 398 | val = le16_to_cpu(data[i]); | 400 | val = get_unaligned_le16(&data[i]); |
| 399 | } | 401 | } |
| 400 | 402 | ||
| 401 | /* After RST_DATA, skip zero data words as the registers | 403 | /* After RST_DATA, skip zero data words as the registers |
| @@ -453,7 +455,7 @@ int mxl862xx_api_wrap(struct mxl862xx_priv *priv, u16 cmd, void *_data, · 51 unmodified lines | |||
| 453 | *(uint8_t *)&data[i] = ret & 0xff; | 455 | *(uint8_t *)&data[i] = ret & 0xff; |
| 454 | crc = (ret >> 8) & 0xff; | 456 | crc = (ret >> 8) & 0xff; |
| 455 | } else { | 457 | } else { |
| 456 | data[i] = cpu_to_le16((u16)ret); | 458 | put_unaligned_le16((u16)ret, &data[i]); |
| 457 | } | 459 | } |
| 458 | } | 460 | } |
| 459 | 461 | ||
| @@ -89,6 +89,7 @@ static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, · 88 unmodified lines | |||
| 89 | struct led_init_data init_data = { }; | 89 | struct led_init_data init_data = { }; |
| 90 | enum led_default_state state; | 90 | enum led_default_state state; |
| 91 | struct rtl8366rb_led *led; | 91 | struct rtl8366rb_led *led; |
| 92 | char name[64]; | ||
| 92 | u32 led_group; | 93 | u32 led_group; |
| 93 | int ret; | 94 | int ret; |
| 94 | 95 | ||
| @@ -129,10 +130,9 @@ static int rtl8366rb_setup_led(struct realtek_priv *priv, struct dsa_port *dp, · 34 unmodified lines | |||
| 129 | init_data.fwnode = led_fwnode; | 130 | init_data.fwnode = led_fwnode; |
| 130 | init_data.devname_mandatory = true; | 131 | init_data.devname_mandatory = true; |
| 131 | 132 | ||
| 132 | init_data.devicename = kasprintf(GFP_KERNEL, "Realtek-%d:0%d:%d", | 133 | snprintf(name, sizeof(name), "Realtek-%d:0%d:%d", |
| 133 | dp->ds->index, dp->index, led_group); | 134 | dp->ds->index, dp->index, led_group); |
| 134 | if (!init_data.devicename) | 135 | init_data.devicename = name; |
| 135 | return -ENOMEM; | ||
| 136 | 136 | ||
| 137 | ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data); | 137 | ret = devm_led_classdev_register_ext(priv->dev, &led->cdev, &init_data); |
| 138 | if (ret) { | 138 | if (ret) { |
| @@ -755,7 +755,7 @@ static int sja1105_per_out_enable(struct sja1105_private *priv, · 754 unmodified lines | |||
| 755 | * 2 edges on PTP_CLK. So check for truncation which happens | 755 | * 2 edges on PTP_CLK. So check for truncation which happens |
| 756 | * at periods larger than around 68.7 seconds. | 756 | * at periods larger than around 68.7 seconds. |
| 757 | */ | 757 | */ |
| 758 | pin_duration = ns_to_sja1105_ticks(pin_duration / 2); | 758 | pin_duration = max_t(u64, ns_to_sja1105_ticks(pin_duration / 2), 1); |
| 759 | if (pin_duration > U32_MAX) { | 759 | if (pin_duration > U32_MAX) { |
| 760 | rc = -ERANGE; | 760 | rc = -ERANGE; |
| 761 | goto out; | 761 | goto out; |
| @@ -1004,6 +1004,7 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) · 1003 unmodified lines | |||
| 1004 | 1004 | ||
| 1005 | e = &q->entry[index]; | 1005 | e = &q->entry[index]; |
| 1006 | skb = e->skb; | 1006 | skb = e->skb; |
| 1007 | e->skb = NULL; | ||
| 1007 | 1008 | ||
| 1008 | dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, | 1009 | dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, |
| 1009 | DMA_TO_DEVICE); | 1010 | DMA_TO_DEVICE); |
| @@ -1147,55 +1148,76 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma) · 137 unmodified lines | |||
| 1147 | return 0; | 1148 | return 0; |
| 1148 | } | 1149 | } |
| 1149 | 1150 | ||
| 1150 | static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) | 1151 | static void airoha_qdma_tx_cleanup(struct airoha_qdma *qdma) |
| 1151 | { | 1152 | { |
| 1152 | struct airoha_qdma *qdma = q->qdma; | 1153 | u32 status; |
| 1153 | struct airoha_eth *eth = qdma->eth; | 1154 | int i; |
| 1154 | int i, qid = q - &qdma->q_tx[0]; | ||
| 1155 | u16 index = 0; | ||
| 1156 | 1155 | ||
| 1157 | spin_lock_bh(&q->lock); | 1156 | airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, |
| 1158 | for (i = 0; i < q->ndesc; i++) { | 1157 | GLOBAL_CFG_TX_DMA_EN_MASK); |
| 1159 | struct airoha_queue_entry *e = &q->entry[i]; | 1158 | if (read_poll_timeout(airoha_qdma_rr, status, |
| 1160 | struct airoha_qdma_desc *desc = &q->desc[i]; | 1159 | !(status & GLOBAL_CFG_TX_DMA_BUSY_MASK), |
| 1160 | USEC_PER_MSEC, 50 * USEC_PER_MSEC, true, | ||
| 1161 | qdma, REG_QDMA_GLOBAL_CFG)) | ||
| 1162 | dev_warn(qdma->eth->dev, "QDMA TX DMA busy timeout\n"); | ||
| 1161 | 1163 | ||
| 1162 | if (!e->dma_addr) | 1164 | for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { |
| 1165 | struct airoha_queue *q = &qdma->q_tx[i]; | ||
| 1166 | u16 index = 0; | ||
| 1167 | int j; | ||
| 1168 | |||
| 1169 | if (!q->ndesc) | ||
| 1163 | continue; | 1170 | continue; |
| 1164 | 1171 | ||
| 1165 | dma_unmap_single(eth->dev, e->dma_addr, e->dma_len, | 1172 | spin_lock_bh(&q->lock); |
| 1166 | DMA_TO_DEVICE); | ||
| 1167 | dev_kfree_skb_any(e->skb); | ||
| 1168 | e->dma_addr = 0; | ||
| 1169 | e->skb = NULL; | ||
| 1170 | list_add_tail(&e->list, &q->tx_list); | ||
| 1171 | 1173 | ||
| 1172 | /* Reset DMA descriptor */ | 1174 | q->flushing = true; |
| 1173 | WRITE_ONCE(desc->ctrl, 0); | 1175 | for (j = 0; j < q->ndesc; j++) { |
| 1174 | WRITE_ONCE(desc->addr, 0); | 1176 | struct airoha_queue_entry *e = &q->entry[j]; |
| 1175 | WRITE_ONCE(desc->data, 0); | 1177 | struct airoha_qdma_desc *desc = &q->desc[j]; |
| 1176 | WRITE_ONCE(desc->msg0, 0); | 1178 | struct sk_buff *skb = e->skb; |
| 1177 | WRITE_ONCE(desc->msg1, 0); | ||
| 1178 | WRITE_ONCE(desc->msg2, 0); | ||
| 1179 | 1179 | ||
| 1180 | q->queued--; | 1180 | if (!e->dma_addr) |
| 1181 | } | 1181 | continue; |
| 1182 | 1182 | ||
| 1183 | if (!list_empty(&q->tx_list)) { | 1183 | dma_unmap_single(qdma->eth->dev, e->dma_addr, |
| 1184 | struct airoha_queue_entry *e; | 1184 | e->dma_len, DMA_TO_DEVICE); |
| 1185 | e->dma_addr = 0; | ||
| 1186 | list_add_tail(&e->list, &q->tx_list); | ||
| 1187 | |||
| 1188 | WRITE_ONCE(desc->ctrl, 0); | ||
| 1189 | WRITE_ONCE(desc->addr, 0); | ||
| 1190 | WRITE_ONCE(desc->data, 0); | ||
| 1191 | WRITE_ONCE(desc->msg0, 0); | ||
| 1192 | WRITE_ONCE(desc->msg1, 0); | ||
| 1193 | WRITE_ONCE(desc->msg2, 0); | ||
| 1194 | |||
| 1195 | if (skb) { | ||
| 1196 | struct netdev_queue *txq; | ||
| 1197 | |||
| 1198 | txq = skb_get_tx_queue(skb->dev, skb); | ||
| 1199 | netdev_tx_completed_queue(txq, 1, skb->len); | ||
| 1200 | dev_kfree_skb_any(skb); | ||
| 1201 | e->skb = NULL; | ||
| 1202 | } | ||
| 1185 | 1203 | ||
| 1186 | e = list_first_entry(&q->tx_list, struct airoha_queue_entry, | 1204 | q->queued--; |
| 1187 | list); | 1205 | } |
| 1188 | index = e - q->entry; | ||
| 1189 | } | ||
| 1190 | /* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is | ||
| 1191 | * empty. | ||
| 1192 | */ | ||
| 1193 | airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(qid), TX_RING_CPU_IDX_MASK, | ||
| 1194 | FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); | ||
| 1195 | airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(qid), TX_RING_DMA_IDX_MASK, | ||
| 1196 | FIELD_PREP(TX_RING_DMA_IDX_MASK, index)); | ||
| 1197 | 1206 | ||
| 1198 | spin_unlock_bh(&q->lock); | 1207 | if (!list_empty(&q->tx_list)) { |
| 1208 | struct airoha_queue_entry *e; | ||
| 1209 | |||
| 1210 | e = list_first_entry(&q->tx_list, | ||
| 1211 | struct airoha_queue_entry, list); | ||
| 1212 | index = e - q->entry; | ||
| 1213 | } | ||
| 1214 | airoha_qdma_rmw(qdma, REG_TX_CPU_IDX(i), TX_RING_CPU_IDX_MASK, | ||
| 1215 | FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); | ||
| 1216 | airoha_qdma_rmw(qdma, REG_TX_DMA_IDX(i), TX_RING_DMA_IDX_MASK, | ||
| 1217 | FIELD_PREP(TX_RING_DMA_IDX_MASK, index)); | ||
| 1218 | |||
| 1219 | spin_unlock_bh(&q->lock); | ||
| 1220 | } | ||
| 1199 | } | 1221 | } |
| 1200 | 1222 | ||
| 1201 | static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma) | 1223 | static int airoha_qdma_init_hfwd_queues(struct airoha_qdma *qdma) |
| @@ -1523,10 +1545,23 @@ static int airoha_qdma_init(struct platform_device *pdev, · 321 unmodified lines | |||
| 1523 | return airoha_qdma_hw_init(qdma); | 1545 | return airoha_qdma_hw_init(qdma); |
| 1524 | } | 1546 | } |
| 1525 | 1547 | ||
| 1526 | static void airoha_qdma_cleanup(struct airoha_qdma *qdma) | 1548 | static void airoha_qdma_cleanup(struct airoha_eth *eth, |
| 1549 | struct airoha_qdma *qdma) | ||
| 1527 | { | 1550 | { |
| 1528 | int i; | 1551 | int i; |
| 1529 | 1552 | ||
| 1553 | if (test_bit(DEV_STATE_INITIALIZED, ð->state)) { | ||
| 1554 | u32 status; | ||
| 1555 | |||
| 1556 | airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, | ||
| 1557 | GLOBAL_CFG_RX_DMA_EN_MASK); | ||
| 1558 | if (read_poll_timeout(airoha_qdma_rr, status, | ||
| 1559 | !(status & GLOBAL_CFG_RX_DMA_BUSY_MASK), | ||
| 1560 | USEC_PER_MSEC, 50 * USEC_PER_MSEC, true, | ||
| 1561 | qdma, REG_QDMA_GLOBAL_CFG)) | ||
| 1562 | dev_warn(eth->dev, "QDMA RX DMA busy timeout\n"); | ||
| 1563 | } | ||
| 1564 | |||
| 1530 | for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { | 1565 | for (i = 0; i < ARRAY_SIZE(qdma->q_rx); i++) { |
| 1531 | if (!qdma->q_rx[i].ndesc) | 1566 | if (!qdma->q_rx[i].ndesc) |
| 1532 | continue; | 1567 | continue; |
| @@ -1546,12 +1581,6 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma) · 13 unmodified lines | |||
| 1546 | netif_napi_del(&qdma->q_tx_irq[i].napi); | 1581 | netif_napi_del(&qdma->q_tx_irq[i].napi); |
| 1547 | } | 1582 | } |
| 1548 | 1583 | ||
| 1549 | for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { | ||
| 1550 | if (!qdma->q_tx[i].ndesc) | ||
| 1551 | continue; | ||
| 1552 | |||
| 1553 | airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); | ||
| 1554 | } | ||
| 1555 | } | 1584 | } |
| 1556 | 1585 | ||
| 1557 | static int airoha_hw_init(struct platform_device *pdev, | 1586 | static int airoha_hw_init(struct platform_device *pdev, |
| @@ -1593,7 +1622,7 @@ static int airoha_hw_init(struct platform_device *pdev, · 35 unmodified lines | |||
| 1593 | return 0; | 1622 | return 0; |
| 1594 | error: | 1623 | error: |
| 1595 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) | 1624 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) |
| 1596 | airoha_qdma_cleanup(ð->qdma[i]); | 1625 | airoha_qdma_cleanup(eth, ð->qdma[i]); |
| 1597 | 1626 | ||
| 1598 | return err; | 1627 | return err; |
| 1599 | } | 1628 | } |
| @@ -1603,7 +1632,7 @@ static void airoha_hw_cleanup(struct airoha_eth *eth) · 3 unmodified lines | |||
| 1603 | int i; | 1632 | int i; |
| 1604 | 1633 | ||
| 1605 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) | 1634 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) |
| 1606 | airoha_qdma_cleanup(ð->qdma[i]); | 1635 | airoha_qdma_cleanup(eth, ð->qdma[i]); |
| 1607 | airoha_ppe_deinit(eth); | 1636 | airoha_ppe_deinit(eth); |
| 1608 | } | 1637 | } |
| 1609 | 1638 | ||
| @@ -1837,11 +1866,6 @@ static int airoha_dev_open(struct net_device *netdev) · 227 unmodified lines | |||
| 1837 | } | 1866 | } |
| 1838 | port->users++; | 1867 | port->users++; |
| 1839 | 1868 | ||
| 1840 | airoha_qdma_set(qdma, REG_QDMA_GLOBAL_CFG, | ||
| 1841 | GLOBAL_CFG_TX_DMA_EN_MASK | | ||
| 1842 | GLOBAL_CFG_RX_DMA_EN_MASK); | ||
| 1843 | qdma->users++; | ||
| 1844 | |||
| 1845 | if (!airoha_is_lan_gdm_dev(dev) && | 1869 | if (!airoha_is_lan_gdm_dev(dev) && |
| 1846 | airoha_ppe_is_enabled(qdma->eth, 1)) | 1870 | airoha_ppe_is_enabled(qdma->eth, 1)) |
| 1847 | pse_port = FE_PSE_PORT_PPE2; | 1871 | pse_port = FE_PSE_PORT_PPE2; |
| @@ -1880,12 +1904,9 @@ static int airoha_dev_stop(struct net_device *netdev) · 32 unmodified lines | |||
| 1880 | struct airoha_gdm_dev *dev = netdev_priv(netdev); | 1904 | struct airoha_gdm_dev *dev = netdev_priv(netdev); |
| 1881 | struct airoha_gdm_port *port = dev->port; | 1905 | struct airoha_gdm_port *port = dev->port; |
| 1882 | struct airoha_qdma *qdma = dev->qdma; | 1906 | struct airoha_qdma *qdma = dev->qdma; |
| 1883 | int i; | ||
| 1884 | 1907 | ||
| 1885 | netif_tx_disable(netdev); | 1908 | netif_tx_disable(netdev); |
| 1886 | airoha_set_vip_for_gdm_port(dev, false); | 1909 | airoha_set_vip_for_gdm_port(dev, false); |
| 1887 | for (i = 0; i < netdev->num_tx_queues; i++) | ||
| 1888 | netdev_tx_reset_subqueue(netdev, i); | ||
| 1889 | 1910 | ||
| 1890 | if (--port->users) | 1911 | if (--port->users) |
| 1891 | airoha_set_port_mtu(dev->eth, port); | 1912 | airoha_set_port_mtu(dev->eth, port); |
| @@ -1893,20 +1914,6 @@ static int airoha_dev_stop(struct net_device *netdev) · 1 unmodified line | |||
| 1893 | airoha_set_gdm_port_fwd_cfg(qdma->eth, | 1914 | airoha_set_gdm_port_fwd_cfg(qdma->eth, |
| 1894 | REG_GDM_FWD_CFG(port->id), | 1915 | REG_GDM_FWD_CFG(port->id), |
| 1895 | FE_PSE_PORT_DROP); | 1916 | FE_PSE_PORT_DROP); |
| 1896 | |||
| 1897 | if (!--qdma->users) { | ||
| 1898 | airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG, | ||
| 1899 | GLOBAL_CFG_TX_DMA_EN_MASK | | ||
| 1900 | GLOBAL_CFG_RX_DMA_EN_MASK); | ||
| 1901 | |||
| 1902 | for (i = 0; i < ARRAY_SIZE(qdma->q_tx); i++) { | ||
| 1903 | if (!qdma->q_tx[i].ndesc) | ||
| 1904 | continue; | ||
| 1905 | |||
| 1906 | airoha_qdma_cleanup_tx_queue(&qdma->q_tx[i]); | ||
| 1907 | } | ||
| 1908 | } | ||
| 1909 | |||
| 1910 | return 0; | 1917 | return 0; |
| 1911 | } | 1918 | } |
| 1912 | 1919 | ||
| @@ -2110,7 +2117,7 @@ static u16 airoha_dev_select_queue(struct net_device *netdev, · 197 unmodified lines | |||
| 2110 | */ | 2117 | */ |
| 2111 | channel = netdev_uses_dsa(netdev) ? skb_get_queue_mapping(skb) : port->id; | 2118 | channel = netdev_uses_dsa(netdev) ? skb_get_queue_mapping(skb) : port->id; |
| 2112 | channel = channel % AIROHA_NUM_QOS_CHANNELS; | 2119 | channel = channel % AIROHA_NUM_QOS_CHANNELS; |
| 2113 | queue = (skb->priority - 1) % AIROHA_NUM_QOS_QUEUES; /* QoS queue */ | 2120 | queue = skb->priority % AIROHA_NUM_QOS_QUEUES; |
| 2114 | queue = channel * AIROHA_NUM_QOS_QUEUES + queue; | 2121 | queue = channel * AIROHA_NUM_QOS_QUEUES + queue; |
| 2115 | 2122 | ||
| 2116 | return queue < netdev->num_tx_queues ? queue : 0; | 2123 | return queue < netdev->num_tx_queues ? queue : 0; |
| @@ -2229,6 +2236,9 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb, · 112 unmodified lines | |||
| 2229 | 2236 | ||
| 2230 | spin_lock_bh(&q->lock); | 2237 | spin_lock_bh(&q->lock); |
| 2231 | 2238 | ||
| 2239 | if (q->flushing) | ||
| 2240 | goto error_unlock; | ||
| 2241 | |||
| 2232 | txq = skb_get_tx_queue(netdev, skb); | 2242 | txq = skb_get_tx_queue(netdev, skb); |
| 2233 | nr_frags = 1 + skb_shinfo(skb)->nr_frags; | 2243 | nr_frags = 1 + skb_shinfo(skb)->nr_frags; |
| 2234 | 2244 | ||
| @@ -2309,7 +2319,7 @@ error_unmap: · 74 unmodified lines | |||
| 2309 | e->dma_addr = 0; | 2319 | e->dma_addr = 0; |
| 2310 | } | 2320 | } |
| 2311 | list_splice(&tx_list, &q->tx_list); | 2321 | list_splice(&tx_list, &q->tx_list); |
| 2312 | 2322 | error_unlock: | |
| 2313 | spin_unlock_bh(&q->lock); | 2323 | spin_unlock_bh(&q->lock); |
| 2314 | error: | 2324 | error: |
| 2315 | dev_kfree_skb_any(skb); | 2325 | dev_kfree_skb_any(skb); |
| @@ -2395,7 +2405,7 @@ static int airoha_qdma_set_chan_tx_sched(struct net_device *netdev, · 79 unmodified lines | |||
| 2395 | struct airoha_gdm_dev *dev = netdev_priv(netdev); | 2405 | struct airoha_gdm_dev *dev = netdev_priv(netdev); |
| 2396 | int i; | 2406 | int i; |
| 2397 | 2407 | ||
| 2398 | for (i = 0; i < AIROHA_NUM_TX_RING; i++) | 2408 | for (i = 0; i < AIROHA_NUM_QOS_QUEUES; i++) |
| 2399 | airoha_qdma_clear(dev->qdma, REG_QUEUE_CLOSE_CFG(channel), | 2409 | airoha_qdma_clear(dev->qdma, REG_QUEUE_CLOSE_CFG(channel), |
| 2400 | TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)); | 2410 | TXQ_DISABLE_CHAN_QUEUE_MASK(channel, i)); |
| 2401 | 2411 | ||
| @@ -2789,7 +2799,7 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, · 387 unmodified lines | |||
| 2789 | struct tc_htb_qopt_offload *opt) | 2799 | struct tc_htb_qopt_offload *opt) |
| 2790 | { | 2800 | { |
| 2791 | u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; | 2801 | u32 channel = TC_H_MIN(opt->classid) % AIROHA_NUM_QOS_CHANNELS; |
| 2792 | int err, num_tx_queues = netdev->real_num_tx_queues; | 2802 | int err, num_tx_queues = AIROHA_NUM_TX_RING + channel + 1; |
| 2793 | struct airoha_gdm_dev *dev = netdev_priv(netdev); | 2803 | struct airoha_gdm_dev *dev = netdev_priv(netdev); |
| 2794 | struct airoha_qdma *qdma = dev->qdma; | 2804 | struct airoha_qdma *qdma = dev->qdma; |
| 2795 | 2805 | ||
| @@ -2806,13 +2816,15 @@ static int airoha_tc_htb_alloc_leaf_queue(struct net_device *netdev, · 10 unmodified lines | |||
| 2806 | if (err) | 2816 | if (err) |
| 2807 | goto error; | 2817 | goto error; |
| 2808 | 2818 | ||
| 2809 | err = netif_set_real_num_tx_queues(netdev, num_tx_queues + 1); | 2819 | if (num_tx_queues > netdev->real_num_tx_queues) { |
| 2810 | if (err) { | 2820 | err = netif_set_real_num_tx_queues(netdev, num_tx_queues); |
| 2811 | airoha_qdma_set_tx_rate_limit(netdev, channel, 0, | 2821 | if (err) { |
| 2812 | opt->quantum); | 2822 | airoha_qdma_set_tx_rate_limit(netdev, channel, 0, |
| 2813 | NL_SET_ERR_MSG_MOD(opt->extack, | 2823 | opt->quantum); |
| 2814 | "failed setting real_num_tx_queues"); | 2824 | NL_SET_ERR_MSG_MOD(opt->extack, |
| 2815 | goto error; | 2825 | "failed setting real_num_tx_queues"); |
| 2826 | goto error; | ||
| 2827 | } | ||
| 2816 | } | 2828 | } |
| 2817 | 2829 | ||
| 2818 | set_bit(channel, dev->qos_sq_bmap); | 2830 | set_bit(channel, dev->qos_sq_bmap); |
| @@ -3003,13 +3015,18 @@ static int airoha_dev_setup_tc_block(struct net_device *dev, · 184 unmodified lines | |||
| 3003 | static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) | 3015 | static void airoha_tc_remove_htb_queue(struct net_device *netdev, int queue) |
| 3004 | { | 3016 | { |
| 3005 | struct airoha_gdm_dev *dev = netdev_priv(netdev); | 3017 | struct airoha_gdm_dev *dev = netdev_priv(netdev); |
| 3018 | int num_tx_queues = AIROHA_NUM_TX_RING; | ||
| 3006 | struct airoha_qdma *qdma = dev->qdma; | 3019 | struct airoha_qdma *qdma = dev->qdma; |
| 3007 | 3020 | ||
| 3008 | netif_set_real_num_tx_queues(netdev, netdev->real_num_tx_queues - 1); | 3021 | airoha_qdma_set_tx_rate_limit(netdev, queue, 0, 0); |
| 3009 | airoha_qdma_set_tx_rate_limit(netdev, queue + 1, 0, 0); | ||
| 3010 | 3022 | ||
| 3011 | clear_bit(queue, qdma->qos_channel_map); | 3023 | clear_bit(queue, qdma->qos_channel_map); |
| 3012 | clear_bit(queue, dev->qos_sq_bmap); | 3024 | clear_bit(queue, dev->qos_sq_bmap); |
| 3025 | |||
| 3026 | if (!bitmap_empty(dev->qos_sq_bmap, AIROHA_NUM_QOS_CHANNELS)) | ||
| 3027 | num_tx_queues += find_last_bit(dev->qos_sq_bmap, | ||
| 3028 | AIROHA_NUM_QOS_CHANNELS) + 1; | ||
| 3029 | netif_set_real_num_tx_queues(netdev, num_tx_queues); | ||
| 3013 | } | 3030 | } |
| 3014 | 3031 | ||
| 3015 | static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, | 3032 | static int airoha_tc_htb_delete_leaf_queue(struct net_device *netdev, |
| @@ -3413,8 +3430,12 @@ static int airoha_probe(struct platform_device *pdev) · 397 unmodified lines | |||
| 3413 | if (err) | 3430 | if (err) |
| 3414 | goto error_netdev_free; | 3431 | goto error_netdev_free; |
| 3415 | 3432 | ||
| 3416 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) | 3433 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { |
| 3417 | airoha_qdma_start_napi(ð->qdma[i]); | 3434 | airoha_qdma_start_napi(ð->qdma[i]); |
| 3435 | airoha_qdma_set(ð->qdma[i], REG_QDMA_GLOBAL_CFG, | ||
| 3436 | GLOBAL_CFG_TX_DMA_EN_MASK | | ||
| 3437 | GLOBAL_CFG_RX_DMA_EN_MASK); | ||
| 3438 | } | ||
| 3418 | 3439 | ||
| 3419 | for_each_child_of_node(pdev->dev.of_node, np) { | 3440 | for_each_child_of_node(pdev->dev.of_node, np) { |
| 3420 | if (!of_device_is_compatible(np, "airoha,eth-mac")) | 3441 | if (!of_device_is_compatible(np, "airoha,eth-mac")) |
| @@ -3437,8 +3458,10 @@ static int airoha_probe(struct platform_device *pdev) · 16 unmodified lines | |||
| 3437 | return 0; | 3458 | return 0; |
| 3438 | 3459 | ||
| 3439 | error_napi_stop: | 3460 | error_napi_stop: |
| 3440 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) | 3461 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { |
| 3441 | airoha_qdma_stop_napi(ð->qdma[i]); | 3462 | airoha_qdma_stop_napi(ð->qdma[i]); |
| 3463 | airoha_qdma_tx_cleanup(ð->qdma[i]); | ||
| 3464 | } | ||
| 3442 | 3465 | ||
| 3443 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { | 3466 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { |
| 3444 | struct airoha_gdm_port *port = eth->ports[i]; | 3467 | struct airoha_gdm_port *port = eth->ports[i]; |
| @@ -3474,8 +3497,10 @@ static void airoha_remove(struct platform_device *pdev) · 29 unmodified lines | |||
| 3474 | struct airoha_eth *eth = platform_get_drvdata(pdev); | 3497 | struct airoha_eth *eth = platform_get_drvdata(pdev); |
| 3475 | int i; | 3498 | int i; |
| 3476 | 3499 | ||
| 3477 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) | 3500 | for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) { |
| 3478 | airoha_qdma_stop_napi(ð->qdma[i]); | 3501 | airoha_qdma_stop_napi(ð->qdma[i]); |
| 3502 | airoha_qdma_tx_cleanup(ð->qdma[i]); | ||
| 3503 | } | ||
| 3479 | 3504 | ||
| 3480 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { | 3505 | for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { |
| 3481 | struct airoha_gdm_port *port = eth->ports[i]; | 3506 | struct airoha_gdm_port *port = eth->ports[i]; |
| @@ -197,6 +197,7 @@ struct airoha_queue { · 196 unmodified lines | |||
| 197 | int free_thr; | 197 | int free_thr; |
| 198 | int buf_size; | 198 | int buf_size; |
| 199 | bool txq_stopped; | 199 | bool txq_stopped; |
| 200 | bool flushing; | ||
| 200 | 201 | ||
| 201 | struct napi_struct napi; | 202 | struct napi_struct napi; |
| 202 | struct page_pool *page_pool; | 203 | struct page_pool *page_pool; |
| @@ -524,8 +525,6 @@ struct airoha_qdma { · 321 unmodified lines | |||
| 524 | struct airoha_eth *eth; | 525 | struct airoha_eth *eth; |
| 525 | void __iomem *regs; | 526 | void __iomem *regs; |
| 526 | 527 | ||
| 527 | int users; | ||
| 528 | |||
| 529 | struct airoha_irq_bank irq_banks[AIROHA_MAX_NUM_IRQ_BANKS]; | 528 | struct airoha_irq_bank irq_banks[AIROHA_MAX_NUM_IRQ_BANKS]; |
| 530 | 529 | ||
| 531 | struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ]; | 530 | struct airoha_tx_irq_queue q_tx_irq[AIROHA_NUM_TX_IRQ]; |
| @@ -1601,7 +1601,8 @@ int airoha_ppe_init(struct airoha_eth *eth) · 1600 unmodified lines | |||
| 1601 | return -ENOMEM; | 1601 | return -ENOMEM; |
| 1602 | } | 1602 | } |
| 1603 | 1603 | ||
| 1604 | ppe->foe_check_time = devm_kzalloc(eth->dev, ppe_num_entries, | 1604 | ppe->foe_check_time = devm_kzalloc(eth->dev, |
| 1605 | ppe_num_entries * sizeof(*ppe->foe_check_time), | ||
| 1605 | GFP_KERNEL); | 1606 | GFP_KERNEL); |
| 1606 | if (!ppe->foe_check_time) | 1607 | if (!ppe->foe_check_time) |
| 1607 | return -ENOMEM; | 1608 | return -ENOMEM; |
| @@ -752,6 +752,18 @@ static void ena_destroy_all_tx_queues(struct ena_adapter *adapter) · 751 unmodified lines | |||
| 752 | } | 752 | } |
| 753 | } | 753 | } |
| 754 | 754 | ||
| 755 | static void ena_destroy_xdp_tx_queues(struct ena_adapter *adapter) | ||
| 756 | { | ||
| 757 | u16 ena_qid; | ||
| 758 | int i; | ||
| 759 | |||
| 760 | for (i = adapter->xdp_first_ring; | ||
| 761 | i < adapter->xdp_first_ring + adapter->xdp_num_queues; i++) { | ||
| 762 | ena_qid = ENA_IO_TXQ_IDX(i); | ||
| 763 | ena_com_destroy_io_queue(adapter->ena_dev, ena_qid); | ||
| 764 | } | ||
| 765 | } | ||
| 766 | |||
| 755 | static void ena_destroy_all_rx_queues(struct ena_adapter *adapter) | 767 | static void ena_destroy_all_rx_queues(struct ena_adapter *adapter) |
| 756 | { | 768 | { |
| 757 | u16 ena_qid; | 769 | u16 ena_qid; |
| @@ -2078,14 +2090,21 @@ static int create_queues_with_size_backoff(struct ena_adapter *adapter) · 1320 unmodified lines | |||
| 2078 | rc = ena_setup_tx_resources_in_range(adapter, | 2090 | rc = ena_setup_tx_resources_in_range(adapter, |
| 2079 | 0, | 2091 | 0, |
| 2080 | adapter->num_io_queues); | 2092 | adapter->num_io_queues); |
| 2081 | if (rc) | 2093 | if (rc) { |
| 2094 | ena_destroy_xdp_tx_queues(adapter); | ||
| 2095 | ena_free_all_io_tx_resources_in_range(adapter, | ||
| 2096 | adapter->xdp_first_ring, | ||
| 2097 | adapter->xdp_num_queues); | ||
| 2082 | goto err_setup_tx; | 2098 | goto err_setup_tx; |
| 2099 | } | ||
| 2083 | 2100 | ||
| 2084 | rc = ena_create_io_tx_queues_in_range(adapter, | 2101 | rc = ena_create_io_tx_queues_in_range(adapter, |
| 2085 | 0, | 2102 | 0, |
| 2086 | adapter->num_io_queues); | 2103 | adapter->num_io_queues); |
| 2087 | if (rc) | 2104 | if (rc) { |
| 2105 | ena_destroy_xdp_tx_queues(adapter); | ||
| 2088 | goto err_create_tx_queues; | 2106 | goto err_create_tx_queues; |
| 2107 | } | ||
| 2089 | 2108 | ||
| 2090 | rc = ena_setup_all_rx_resources(adapter); | 2109 | rc = ena_setup_all_rx_resources(adapter); |
| 2091 | if (rc) | 2110 | if (rc) |
| @@ -943,9 +943,10 @@ static int au1000_close(struct net_device *dev) · 942 unmodified lines | |||
| 943 | /* stop the device */ | 943 | /* stop the device */ |
| 944 | netif_stop_queue(dev); | 944 | netif_stop_queue(dev); |
| 945 | 945 | ||
| 946 | spin_unlock_irqrestore(&aup->lock, flags); | ||
| 947 | |||
| 946 | /* disable the interrupt */ | 948 | /* disable the interrupt */ |
| 947 | free_irq(dev->irq, dev); | 949 | free_irq(dev->irq, dev); |
| 948 | spin_unlock_irqrestore(&aup->lock, flags); | ||
| 949 | 950 | ||
| 950 | return 0; | 951 | return 0; |
| 951 | } | 952 | } |
| @@ -4748,6 +4748,7 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp) · 4747 unmodified lines | |||
| 4748 | fp = kzalloc_objs(*fp, bp->fp_array_size); | 4748 | fp = kzalloc_objs(*fp, bp->fp_array_size); |
| 4749 | if (!fp) | 4749 | if (!fp) |
| 4750 | goto alloc_err; | 4750 | goto alloc_err; |
| 4751 | bp->fp = fp; | ||
| 4751 | for (i = 0; i < bp->fp_array_size; i++) { | 4752 | for (i = 0; i < bp->fp_array_size; i++) { |
| 4752 | fp[i].tpa_info = | 4753 | fp[i].tpa_info = |
| 4753 | kzalloc_objs(struct bnx2x_agg_info, | 4754 | kzalloc_objs(struct bnx2x_agg_info, |
| @@ -4756,8 +4757,6 @@ int bnx2x_alloc_mem_bp(struct bnx2x *bp) · 2 unmodified lines | |||
| 4756 | goto alloc_err; | 4757 | goto alloc_err; |
| 4757 | } | 4758 | } |
| 4758 | 4759 | ||
| 4759 | bp->fp = fp; | ||
| 4760 | |||
| 4761 | /* allocate sp objs */ | 4760 | /* allocate sp objs */ |
| 4762 | bp->sp_objs = kzalloc_objs(struct bnx2x_sp_objs, bp->fp_array_size); | 4761 | bp->sp_objs = kzalloc_objs(struct bnx2x_sp_objs, bp->fp_array_size); |
| 4763 | if (!bp->sp_objs) | 4762 | if (!bp->sp_objs) |
| @@ -10530,7 +10530,7 @@ static void bnxt_accumulate_stats(struct bnxt_stats_mem *stats) · 10529 unmodified lines | |||
| 10530 | stats->hw_masks, stats->len / 8, false); | 10530 | stats->hw_masks, stats->len / 8, false); |
| 10531 | } | 10531 | } |
| 10532 | 10532 | ||
| 10533 | static void bnxt_accumulate_all_stats(struct bnxt *bp) | 10533 | static void bnxt_accumulate_ring_stats(struct bnxt *bp) |
| 10534 | { | 10534 | { |
| 10535 | struct bnxt_stats_mem *ring0_stats; | 10535 | struct bnxt_stats_mem *ring0_stats; |
| 10536 | bool ignore_zero = false; | 10536 | bool ignore_zero = false; |
| @@ -10553,6 +10553,10 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp) · 16 unmodified lines | |||
| 10553 | ring0_stats->hw_masks, | 10553 | ring0_stats->hw_masks, |
| 10554 | ring0_stats->len / 8, ignore_zero); | 10554 | ring0_stats->len / 8, ignore_zero); |
| 10555 | } | 10555 | } |
| 10556 | } | ||
| 10557 | |||
| 10558 | static void bnxt_accumulate_port_stats(struct bnxt *bp) | ||
| 10559 | { | ||
| 10556 | if (bp->flags & BNXT_FLAG_PORT_STATS) { | 10560 | if (bp->flags & BNXT_FLAG_PORT_STATS) { |
| 10557 | struct bnxt_stats_mem *stats = &bp->port_stats; | 10561 | struct bnxt_stats_mem *stats = &bp->port_stats; |
| 10558 | __le64 *hw_stats = stats->hw_stats; | 10562 | __le64 *hw_stats = stats->hw_stats; |
| @@ -10575,6 +10579,41 @@ static void bnxt_accumulate_all_stats(struct bnxt *bp) · 16 unmodified lines | |||
| 10575 | } | 10579 | } |
| 10576 | } | 10580 | } |
| 10577 | 10581 | ||
| 10582 | static void bnxt_accumulate_all_stats(struct bnxt *bp) | ||
| 10583 | { | ||
| 10584 | bnxt_accumulate_ring_stats(bp); | ||
| 10585 | bnxt_accumulate_port_stats(bp); | ||
| 10586 | } | ||
| 10587 | |||
| 10588 | /* Re-accumulate ring stats from DMA buffers if stale. | ||
| 10589 | * uAPIs for reading sw_stats should call this first. | ||
| 10590 | * | ||
| 10591 | * We promise user space update frequency of bp->stats_coal_ticks but | ||
| 10592 | * the update is a two step process - first device updates the DMA buffer, | ||
| 10593 | * then we have to update from that buffer to driver stats in the service work. | ||
| 10594 | * Worst case we would be 2x off from the desired frequency. | ||
| 10595 | * Sync the stats sooner, if stale. The 20% threshold was chosen arbitrarily. | ||
| 10596 | * | ||
| 10597 | * Ideally we would split the user-configured time into two portions, | ||
| 10598 | * i.e. also lower the DMA period by the 20%. But the DMA timer seems to have | ||
| 10599 | * too coarse granularity to play such tricks. | ||
| 10600 | */ | ||
| 10601 | void bnxt_sync_ring_stats(struct bnxt *bp) | ||
| 10602 | { | ||
| 10603 | unsigned long stale; | ||
| 10604 | |||
| 10605 | if (!netif_running(bp->dev) || !bp->stats_coal_ticks) | ||
| 10606 | return; | ||
| 10607 | |||
| 10608 | spin_lock(&bp->stats_lock); | ||
| 10609 | stale = usecs_to_jiffies(bp->stats_coal_ticks / 5); | ||
| 10610 | if (time_after_eq(jiffies, bp->stats_updated_jiffies + stale)) { | ||
| 10611 | bnxt_accumulate_ring_stats(bp); | ||
| 10612 | bp->stats_updated_jiffies = jiffies; | ||
| 10613 | } | ||
| 10614 | spin_unlock(&bp->stats_lock); | ||
| 10615 | } | ||
| 10616 | |||
| 10578 | static int bnxt_hwrm_port_qstats(struct bnxt *bp, u8 flags) | 10617 | static int bnxt_hwrm_port_qstats(struct bnxt *bp, u8 flags) |
| 10579 | { | 10618 | { |
| 10580 | struct hwrm_port_qstats_input *req; | 10619 | struct hwrm_port_qstats_input *req; |
| @@ -13577,6 +13616,7 @@ bnxt_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) · 2996 unmodified lines | |||
| 13577 | return; | 13616 | return; |
| 13578 | } | 13617 | } |
| 13579 | 13618 | ||
| 13619 | bnxt_sync_ring_stats(bp); | ||
| 13580 | bnxt_get_ring_stats(bp, stats); | 13620 | bnxt_get_ring_stats(bp, stats); |
| 13581 | bnxt_add_prev_stats(bp, stats); | 13621 | bnxt_add_prev_stats(bp, stats); |
| 13582 | 13622 | ||
| @@ -14753,7 +14793,10 @@ static void bnxt_sp_task(struct work_struct *work) · 1170 unmodified lines | |||
| 14753 | if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) { | 14793 | if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) { |
| 14754 | bnxt_hwrm_port_qstats(bp, 0); | 14794 | bnxt_hwrm_port_qstats(bp, 0); |
| 14755 | bnxt_hwrm_port_qstats_ext(bp, 0); | 14795 | bnxt_hwrm_port_qstats_ext(bp, 0); |
| 14796 | spin_lock(&bp->stats_lock); | ||
| 14756 | bnxt_accumulate_all_stats(bp); | 14797 | bnxt_accumulate_all_stats(bp); |
| 14798 | bp->stats_updated_jiffies = jiffies; | ||
| 14799 | spin_unlock(&bp->stats_lock); | ||
| 14757 | } | 14800 | } |
| 14758 | 14801 | ||
| 14759 | if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) { | 14802 | if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) { |
| @@ -15488,6 +15531,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev) · 728 unmodified lines | |||
| 15488 | INIT_DELAYED_WORK(&bp->fw_reset_task, bnxt_fw_reset_task); | 15531 | INIT_DELAYED_WORK(&bp->fw_reset_task, bnxt_fw_reset_task); |
| 15489 | 15532 | ||
| 15490 | spin_lock_init(&bp->ntp_fltr_lock); | 15533 | spin_lock_init(&bp->ntp_fltr_lock); |
| 15534 | spin_lock_init(&bp->stats_lock); | ||
| 15491 | #if BITS_PER_LONG == 32 | 15535 | #if BITS_PER_LONG == 32 |
| 15492 | spin_lock_init(&bp->db_lock); | 15536 | spin_lock_init(&bp->db_lock); |
| 15493 | #endif | 15537 | #endif |
| @@ -16056,6 +16100,7 @@ static void bnxt_get_queue_stats_rx(struct net_device *dev, int i, · 562 unmodified lines | |||
| 16056 | if (!bp->bnapi) | 16100 | if (!bp->bnapi) |
| 16057 | return; | 16101 | return; |
| 16058 | 16102 | ||
| 16103 | bnxt_sync_ring_stats(bp); | ||
| 16059 | cpr = &bp->bnapi[i]->cp_ring; | 16104 | cpr = &bp->bnapi[i]->cp_ring; |
| 16060 | sw = cpr->stats.sw_stats; | 16105 | sw = cpr->stats.sw_stats; |
| 16061 | 16106 | ||
| @@ -16084,6 +16129,7 @@ static void bnxt_get_queue_stats_tx(struct net_device *dev, int i, · 22 unmodified lines | |||
| 16084 | if (!bp->tx_ring) | 16129 | if (!bp->tx_ring) |
| 16085 | return; | 16130 | return; |
| 16086 | 16131 | ||
| 16132 | bnxt_sync_ring_stats(bp); | ||
| 16087 | bnapi = bp->tx_ring[bp->tx_ring_map[i]].bnapi; | 16133 | bnapi = bp->tx_ring[bp->tx_ring_map[i]].bnapi; |
| 16088 | sw = bnapi->cp_ring.stats.sw_stats; | 16134 | sw = bnapi->cp_ring.stats.sw_stats; |
| 16089 | 16135 | ||
| @@ -2620,6 +2620,10 @@ struct bnxt { · 2619 unmodified lines | |||
| 2620 | #define BNXT_MIN_STATS_COAL_TICKS 250000 | 2620 | #define BNXT_MIN_STATS_COAL_TICKS 250000 |
| 2621 | #define BNXT_MAX_STATS_COAL_TICKS 1000000 | 2621 | #define BNXT_MAX_STATS_COAL_TICKS 1000000 |
| 2622 | 2622 | ||
| 2623 | /* Protects stats_updated_jiffies and writes to sw_stats */ | ||
| 2624 | spinlock_t stats_lock; | ||
| 2625 | unsigned long stats_updated_jiffies; | ||
| 2626 | |||
| 2623 | struct work_struct sp_task; | 2627 | struct work_struct sp_task; |
| 2624 | unsigned long sp_event; | 2628 | unsigned long sp_event; |
| 2625 | #define BNXT_RX_NTP_FLTR_SP_EVENT 1 | 2629 | #define BNXT_RX_NTP_FLTR_SP_EVENT 1 |
| @@ -3027,6 +3031,7 @@ void bnxt_reenable_sriov(struct bnxt *bp); · 401 unmodified lines | |||
| 3027 | void bnxt_close_nic(struct bnxt *, bool, bool); | 3031 | void bnxt_close_nic(struct bnxt *, bool, bool); |
| 3028 | void bnxt_get_ring_drv_stats(struct bnxt *bp, | 3032 | void bnxt_get_ring_drv_stats(struct bnxt *bp, |
| 3029 | struct bnxt_total_ring_drv_stats *stats); | 3033 | struct bnxt_total_ring_drv_stats *stats); |
| 3034 | void bnxt_sync_ring_stats(struct bnxt *bp); | ||
| 3030 | bool bnxt_rfs_capable(struct bnxt *bp, bool new_rss_ctx); | 3035 | bool bnxt_rfs_capable(struct bnxt *bp, bool new_rss_ctx); |
| 3031 | int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words, | 3036 | int bnxt_dbg_hwrm_rd_reg(struct bnxt *bp, u32 reg_off, u16 num_words, |
| 3032 | u32 *reg_buf); | 3037 | u32 *reg_buf); |
| @@ -606,6 +606,7 @@ static void bnxt_get_ethtool_stats(struct net_device *dev, · 605 unmodified lines | |||
| 606 | goto skip_ring_stats; | 606 | goto skip_ring_stats; |
| 607 | } | 607 | } |
| 608 | 608 | ||
| 609 | bnxt_sync_ring_stats(bp); | ||
| 609 | tpa_stats = bnxt_get_num_tpa_ring_stats(bp); | 610 | tpa_stats = bnxt_get_num_tpa_ring_stats(bp); |
| 610 | for (i = 0; i < bp->cp_nr_rings; i++) { | 611 | for (i = 0; i < bp->cp_nr_rings; i++) { |
| 611 | struct bnxt_napi *bnapi = bp->bnapi[i]; | 612 | struct bnxt_napi *bnapi = bp->bnapi[i]; |
| @@ -4522,6 +4522,13 @@ static int macb_setup_tc(struct net_device *dev, enum tc_setup_type type, · 4521 unmodified lines | |||
| 4522 | } | 4522 | } |
| 4523 | } | 4523 | } |
| 4524 | 4524 | ||
| 4525 | static void macb_tx_timeout(struct net_device *dev, unsigned int q) | ||
| 4526 | { | ||
| 4527 | struct macb *bp = netdev_priv(dev); | ||
| 4528 | |||
| 4529 | macb_tx_restart(&bp->queues[q]); | ||
| 4530 | } | ||
| 4531 | |||
| 4525 | static const struct net_device_ops macb_netdev_ops = { | 4532 | static const struct net_device_ops macb_netdev_ops = { |
| 4526 | .ndo_open = macb_open, | 4533 | .ndo_open = macb_open, |
| 4527 | .ndo_stop = macb_close, | 4534 | .ndo_stop = macb_close, |
| @@ -4540,6 +4547,7 @@ static const struct net_device_ops macb_netdev_ops = { · 12 unmodified lines | |||
| 4540 | .ndo_hwtstamp_set = macb_hwtstamp_set, | 4547 | .ndo_hwtstamp_set = macb_hwtstamp_set, |
| 4541 | .ndo_hwtstamp_get = macb_hwtstamp_get, | 4548 | .ndo_hwtstamp_get = macb_hwtstamp_get, |
| 4542 | .ndo_setup_tc = macb_setup_tc, | 4549 | .ndo_setup_tc = macb_setup_tc, |
| 4550 | .ndo_tx_timeout = macb_tx_timeout, | ||
| 4543 | }; | 4551 | }; |
| 4544 | 4552 | ||
| 4545 | /* Configure peripheral capabilities according to device tree | 4553 | /* Configure peripheral capabilities according to device tree |
| @@ -2212,7 +2212,7 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev, · 2211 unmodified lines | |||
| 2212 | if (err) { | 2212 | if (err) { |
| 2213 | NL_SET_ERR_MSG_MOD(extack, | 2213 | NL_SET_ERR_MSG_MOD(extack, |
| 2214 | "Cannot join a bridge while VLAN uppers are present"); | 2214 | "Cannot join a bridge while VLAN uppers are present"); |
| 2215 | return 0; | 2215 | return err; |
| 2216 | } | 2216 | } |
| 2217 | 2217 | ||
| 2218 | netdev_for_each_lower_dev(upper_dev, other_dev, iter) { | 2218 | netdev_for_each_lower_dev(upper_dev, other_dev, iter) { |
| @@ -2233,6 +2233,7 @@ dpaa2_switch_prechangeupper_sanity_checks(struct net_device *netdev, · 14 unmodified lines | |||
| 2233 | static int dpaa2_switch_port_prechangeupper(struct net_device *netdev, | 2233 | static int dpaa2_switch_port_prechangeupper(struct net_device *netdev, |
| 2234 | struct netdev_notifier_changeupper_info *info) | 2234 | struct netdev_notifier_changeupper_info *info) |
| 2235 | { | 2235 | { |
| 2236 | struct ethsw_port_priv *port_priv; | ||
| 2236 | struct netlink_ext_ack *extack; | 2237 | struct netlink_ext_ack *extack; |
| 2237 | struct net_device *upper_dev; | 2238 | struct net_device *upper_dev; |
| 2238 | int err; | 2239 | int err; |
| @@ -2251,6 +2252,13 @@ static int dpaa2_switch_port_prechangeupper(struct net_device *netdev, · 12 unmodified lines | |||
| 2251 | 2252 | ||
| 2252 | if (!info->linking) | 2253 | if (!info->linking) |
| 2253 | dpaa2_switch_port_pre_bridge_leave(netdev); | 2254 | dpaa2_switch_port_pre_bridge_leave(netdev); |
| 2255 | } else if (is_vlan_dev(upper_dev)) { | ||
| 2256 | port_priv = netdev_priv(netdev); | ||
| 2257 | if (port_priv->fdb->bridge_dev) { | ||
| 2258 | NL_SET_ERR_MSG_MOD(extack, | ||
| 2259 | "Cannot accept VLAN uppers while bridged"); | ||
| 2260 | return -EOPNOTSUPP; | ||
| 2261 | } | ||
| 2254 | } | 2262 | } |
| 2255 | 2263 | ||
| 2256 | return 0; | 2264 | return 0; |
| @@ -322,6 +322,9 @@ static void enetc4_default_rings_allocation(struct enetc_pf *pf) · 321 unmodified lines | |||
| 322 | val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); | 322 | val = enetc4_psicfgr0_val_construct(false, num_tx_bdr, num_rx_bdr); |
| 323 | enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); | 323 | enetc_port_wr(hw, ENETC4_PSICFGR0(0), val); |
| 324 | 324 | ||
| 325 | if (!pf->caps.num_vsi) | ||
| 326 | return; | ||
| 327 | |||
| 325 | num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; | 328 | num_rx_bdr = pf->caps.num_rx_bdr - num_rx_bdr; |
| 326 | rx_rem = num_rx_bdr % pf->caps.num_vsi; | 329 | rx_rem = num_rx_bdr % pf->caps.num_vsi; |
| 327 | num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; | 330 | num_rx_bdr = num_rx_bdr / pf->caps.num_vsi; |
| @@ -984,7 +984,8 @@ const struct ethtool_ops gve_ethtool_ops = { · 983 unmodified lines | |||
| 984 | .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT | | 984 | .supported_ring_params = ETHTOOL_RING_USE_TCP_DATA_SPLIT | |
| 985 | ETHTOOL_RING_USE_RX_BUF_LEN, | 985 | ETHTOOL_RING_USE_RX_BUF_LEN, |
| 986 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 986 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 987 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM, | 987 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 988 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 988 | .get_drvinfo = gve_get_drvinfo, | 989 | .get_drvinfo = gve_get_drvinfo, |
| 989 | .get_strings = gve_get_strings, | 990 | .get_strings = gve_get_strings, |
| 990 | .get_sset_count = gve_get_sset_count, | 991 | .get_sset_count = gve_get_sset_count, |
| @@ -21,11 +21,13 @@ · 20 unmodified lines | |||
| 21 | static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) | 21 | static void gve_rx_free_hdr_bufs(struct gve_priv *priv, struct gve_rx_ring *rx) |
| 22 | { | 22 | { |
| 23 | struct device *hdev = &priv->pdev->dev; | 23 | struct device *hdev = &priv->pdev->dev; |
| 24 | int buf_count = rx->dqo.bufq.mask + 1; | ||
| 25 | 24 | ||
| 26 | if (rx->dqo.hdr_bufs.data) { | 25 | if (rx->dqo.hdr_bufs.data) { |
| 27 | dma_free_coherent(hdev, priv->header_buf_size * buf_count, | 26 | size_t size = |
| 28 | rx->dqo.hdr_bufs.data, rx->dqo.hdr_bufs.addr); | 27 | (size_t)priv->header_buf_size * rx->dqo.num_buf_states; |
| 28 | |||
| 29 | dma_free_coherent(hdev, size, rx->dqo.hdr_bufs.data, | ||
| 30 | rx->dqo.hdr_bufs.addr); | ||
| 29 | rx->dqo.hdr_bufs.data = NULL; | 31 | rx->dqo.hdr_bufs.data = NULL; |
| 30 | } | 32 | } |
| 31 | } | 33 | } |
| @@ -254,7 +256,7 @@ int gve_rx_alloc_ring_dqo(struct gve_priv *priv, · 222 unmodified lines | |||
| 254 | 256 | ||
| 255 | /* Allocate header buffers for header-split */ | 257 | /* Allocate header buffers for header-split */ |
| 256 | if (cfg->enable_header_split) | 258 | if (cfg->enable_header_split) |
| 257 | if (gve_rx_alloc_hdr_bufs(priv, rx, buffer_queue_slots)) | 259 | if (gve_rx_alloc_hdr_bufs(priv, rx, rx->dqo.num_buf_states)) |
| 258 | goto err; | 260 | goto err; |
| 259 | 261 | ||
| 260 | /* Allocate RX completion queue */ | 262 | /* Allocate RX completion queue */ |
| @@ -381,10 +383,13 @@ void gve_rx_post_buffers_dqo(struct gve_rx_ring *rx) · 120 unmodified lines | |||
| 381 | break; | 383 | break; |
| 382 | } | 384 | } |
| 383 | 385 | ||
| 384 | if (rx->dqo.hdr_bufs.data) | 386 | if (rx->dqo.hdr_bufs.data) { |
| 387 | u16 buf_id = le16_to_cpu(desc->buf_id); | ||
| 388 | |||
| 385 | desc->header_buf_addr = | 389 | desc->header_buf_addr = |
| 386 | cpu_to_le64(rx->dqo.hdr_bufs.addr + | 390 | cpu_to_le64(rx->dqo.hdr_bufs.addr + |
| 387 | priv->header_buf_size * bufq->tail); | 391 | (size_t)priv->header_buf_size * buf_id); |
| 392 | } | ||
| 388 | 393 | ||
| 389 | bufq->tail = (bufq->tail + 1) & bufq->mask; | 394 | bufq->tail = (bufq->tail + 1) & bufq->mask; |
| 390 | complq->num_free_slots--; | 395 | complq->num_free_slots--; |
| @@ -826,10 +831,13 @@ static int gve_rx_dqo(struct napi_struct *napi, struct gve_rx_ring *rx, · 435 unmodified lines | |||
| 826 | int unsplit = 0; | 831 | int unsplit = 0; |
| 827 | 832 | ||
| 828 | if (hdr_len && !hbo) { | 833 | if (hdr_len && !hbo) { |
| 829 | rx->ctx.skb_head = gve_rx_copy_data(priv->dev, napi, | 834 | size_t offset = |
| 830 | rx->dqo.hdr_bufs.data + | 835 | (size_t)buffer_id * priv->header_buf_size; |
| 831 | desc_idx * priv->header_buf_size, | 836 | |
| 832 | hdr_len); | 837 | rx->ctx.skb_head = |
| 838 | gve_rx_copy_data(priv->dev, napi, | ||
| 839 | rx->dqo.hdr_bufs.data + offset, | ||
| 840 | hdr_len); | ||
| 833 | if (unlikely(!rx->ctx.skb_head)) | 841 | if (unlikely(!rx->ctx.skb_head)) |
| 834 | goto error; | 842 | goto error; |
| 835 | rx->ctx.skb_tail = rx->ctx.skb_head; | 843 | rx->ctx.skb_tail = rx->ctx.skb_head; |
| @@ -811,12 +811,11 @@ static int hns3_get_link_ksettings(struct net_device *netdev, · 810 unmodified lines | |||
| 811 | } | 811 | } |
| 812 | 812 | ||
| 813 | static int hns3_check_ksettings_param(const struct net_device *netdev, | 813 | static int hns3_check_ksettings_param(const struct net_device *netdev, |
| 814 | const struct ethtool_link_ksettings *cmd) | 814 | const struct ethtool_link_ksettings *cmd, |
| 815 | u8 media_type) | ||
| 815 | { | 816 | { |
| 816 | struct hnae3_handle *handle = hns3_get_handle(netdev); | 817 | struct hnae3_handle *handle = hns3_get_handle(netdev); |
| 817 | const struct hnae3_ae_ops *ops = hns3_get_ops(handle); | 818 | const struct hnae3_ae_ops *ops = hns3_get_ops(handle); |
| 818 | u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN; | ||
| 819 | u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN; | ||
| 820 | u32 lane_num; | 819 | u32 lane_num; |
| 821 | u8 autoneg; | 820 | u8 autoneg; |
| 822 | u32 speed; | 821 | u32 speed; |
| @@ -836,9 +835,6 @@ static int hns3_check_ksettings_param(const struct net_device *netdev, · 13 unmodified lines | |||
| 836 | return 0; | 835 | return 0; |
| 837 | } | 836 | } |
| 838 | 837 | ||
| 839 | if (ops->get_media_type) | ||
| 840 | ops->get_media_type(handle, &media_type, &module_type); | ||
| 841 | |||
| 842 | if (cmd->base.duplex == DUPLEX_HALF && | 838 | if (cmd->base.duplex == DUPLEX_HALF && |
| 843 | media_type != HNAE3_MEDIA_TYPE_COPPER) { | 839 | media_type != HNAE3_MEDIA_TYPE_COPPER) { |
| 844 | netdev_err(netdev, | 840 | netdev_err(netdev, |
| @@ -863,6 +859,8 @@ static int hns3_set_link_ksettings(struct net_device *netdev, · 18 unmodified lines | |||
| 863 | struct hnae3_handle *handle = hns3_get_handle(netdev); | 859 | struct hnae3_handle *handle = hns3_get_handle(netdev); |
| 864 | struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle); | 860 | struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle); |
| 865 | const struct hnae3_ae_ops *ops = hns3_get_ops(handle); | 861 | const struct hnae3_ae_ops *ops = hns3_get_ops(handle); |
| 862 | u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN; | ||
| 863 | u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN; | ||
| 866 | int ret; | 864 | int ret; |
| 867 | 865 | ||
| 868 | /* Chip don't support this mode. */ | 866 | /* Chip don't support this mode. */ |
| @@ -878,22 +876,23 @@ static int hns3_set_link_ksettings(struct net_device *netdev, · 9 unmodified lines | |||
| 878 | cmd->base.autoneg, cmd->base.speed, cmd->base.duplex, | 876 | cmd->base.autoneg, cmd->base.speed, cmd->base.duplex, |
| 879 | cmd->lanes); | 877 | cmd->lanes); |
| 880 | 878 | ||
| 881 | /* Only support ksettings_set for netdev with phy attached for now */ | 879 | if (!ops->get_media_type) |
| 882 | if (netdev->phydev) { | 880 | return -EOPNOTSUPP; |
| 883 | if (cmd->base.speed == SPEED_1000 && | 881 | ops->get_media_type(handle, &media_type, &module_type); |
| 884 | cmd->base.autoneg == AUTONEG_DISABLE) | ||
| 885 | return -EINVAL; | ||
| 886 | 882 | ||
| 887 | return phy_ethtool_ksettings_set(netdev->phydev, cmd); | 883 | if (media_type == HNAE3_MEDIA_TYPE_COPPER) { |
| 888 | } else if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) && | 884 | if (!ops->set_phy_link_ksettings) |
| 889 | ops->set_phy_link_ksettings) { | 885 | return -EOPNOTSUPP; |
| 890 | return ops->set_phy_link_ksettings(handle, cmd); | 886 | ret = ops->set_phy_link_ksettings(handle, cmd); |
| 887 | if (ret != -ENODEV) | ||
| 888 | return ret; | ||
| 889 | /* PHY_INEXISTENT, use MAC-level configuration */ | ||
| 891 | } | 890 | } |
| 892 | 891 | ||
| 893 | if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) | 892 | if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2) |
| 894 | return -EOPNOTSUPP; | 893 | return -EOPNOTSUPP; |
| 895 | 894 | ||
| 896 | ret = hns3_check_ksettings_param(netdev, cmd); | 895 | ret = hns3_check_ksettings_param(netdev, cmd, media_type); |
| 897 | if (ret) | 896 | if (ret) |
| 898 | return ret; | 897 | return ret; |
| 899 | 898 | ||
| @@ -1504,6 +1504,11 @@ static int hclge_configure(struct hclge_dev *hdev) · 1503 unmodified lines | |||
| 1504 | hdev->hw.mac.req_autoneg = AUTONEG_ENABLE; | 1504 | hdev->hw.mac.req_autoneg = AUTONEG_ENABLE; |
| 1505 | hdev->hw.mac.req_duplex = DUPLEX_FULL; | 1505 | hdev->hw.mac.req_duplex = DUPLEX_FULL; |
| 1506 | 1506 | ||
| 1507 | /* When lane_num is 0, the firmware will automatically | ||
| 1508 | * select the appropriate lane_num based on the speed. | ||
| 1509 | */ | ||
| 1510 | hdev->hw.mac.req_lane_num = 0; | ||
| 1511 | |||
| 1507 | hclge_parse_link_mode(hdev, cfg.speed_ability); | 1512 | hclge_parse_link_mode(hdev, cfg.speed_ability); |
| 1508 | 1513 | ||
| 1509 | hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability); | 1514 | hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability); |
| @@ -2579,8 +2584,11 @@ static int hclge_cfg_mac_speed_dup_h(struct hnae3_handle *handle, int speed, · 1069 unmodified lines | |||
| 2579 | if (ret) | 2584 | if (ret) |
| 2580 | return ret; | 2585 | return ret; |
| 2581 | 2586 | ||
| 2582 | hdev->hw.mac.req_speed = (u32)speed; | 2587 | hdev->hw.mac.req_lane_num = lane_num; |
| 2583 | hdev->hw.mac.req_duplex = duplex; | 2588 | if (speed != SPEED_UNKNOWN) |
| 2589 | hdev->hw.mac.req_speed = (u32)speed; | ||
| 2590 | if (duplex != DUPLEX_UNKNOWN) | ||
| 2591 | hdev->hw.mac.req_duplex = duplex; | ||
| 2584 | 2592 | ||
| 2585 | return 0; | 2593 | return 0; |
| 2586 | } | 2594 | } |
| @@ -2611,6 +2619,7 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable) · 24 unmodified lines | |||
| 2611 | { | 2619 | { |
| 2612 | struct hclge_vport *vport = hclge_get_vport(handle); | 2620 | struct hclge_vport *vport = hclge_get_vport(handle); |
| 2613 | struct hclge_dev *hdev = vport->back; | 2621 | struct hclge_dev *hdev = vport->back; |
| 2622 | int ret; | ||
| 2614 | 2623 | ||
| 2615 | if (!hdev->hw.mac.support_autoneg) { | 2624 | if (!hdev->hw.mac.support_autoneg) { |
| 2616 | if (enable) { | 2625 | if (enable) { |
| @@ -2622,7 +2631,10 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable) · 5 unmodified lines | |||
| 2622 | } | 2631 | } |
| 2623 | } | 2632 | } |
| 2624 | 2633 | ||
| 2625 | return hclge_set_autoneg_en(hdev, enable); | 2634 | ret = hclge_set_autoneg_en(hdev, enable); |
| 2635 | if (!ret) | ||
| 2636 | hdev->hw.mac.req_autoneg = enable; | ||
| 2637 | return ret; | ||
| 2626 | } | 2638 | } |
| 2627 | 2639 | ||
| 2628 | static int hclge_get_autoneg(struct hnae3_handle *handle) | 2640 | static int hclge_get_autoneg(struct hnae3_handle *handle) |
| @@ -2884,20 +2896,6 @@ static int hclge_mac_init(struct hclge_dev *hdev) · 255 unmodified lines | |||
| 2884 | if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) | 2896 | if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state)) |
| 2885 | hdev->hw.mac.duplex = HCLGE_MAC_FULL; | 2897 | hdev->hw.mac.duplex = HCLGE_MAC_FULL; |
| 2886 | 2898 | ||
| 2887 | if (hdev->hw.mac.support_autoneg) { | ||
| 2888 | ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg); | ||
| 2889 | if (ret) | ||
| 2890 | return ret; | ||
| 2891 | } | ||
| 2892 | |||
| 2893 | if (!hdev->hw.mac.autoneg) { | ||
| 2894 | ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed, | ||
| 2895 | hdev->hw.mac.req_duplex, | ||
| 2896 | hdev->hw.mac.lane_num); | ||
| 2897 | if (ret) | ||
| 2898 | return ret; | ||
| 2899 | } | ||
| 2900 | |||
| 2901 | mac->link = 0; | 2899 | mac->link = 0; |
| 2902 | 2900 | ||
| 2903 | if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) { | 2901 | if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) { |
| @@ -3285,8 +3283,8 @@ static int hclge_get_phy_link_ksettings(struct hnae3_handle *handle, · 381 unmodified lines | |||
| 3285 | } | 3283 | } |
| 3286 | 3284 | ||
| 3287 | static int | 3285 | static int |
| 3288 | hclge_set_phy_link_ksettings(struct hnae3_handle *handle, | 3286 | hclge_ethtool_ksettings_set(struct hnae3_handle *handle, |
| 3289 | const struct ethtool_link_ksettings *cmd) | 3287 | const struct ethtool_link_ksettings *cmd) |
| 3290 | { | 3288 | { |
| 3291 | struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM]; | 3289 | struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM]; |
| 3292 | struct hclge_vport *vport = hclge_get_vport(handle); | 3290 | struct hclge_vport *vport = hclge_get_vport(handle); |
| @@ -3327,10 +3325,34 @@ hclge_set_phy_link_ksettings(struct hnae3_handle *handle, · 34 unmodified lines | |||
| 3327 | return ret; | 3325 | return ret; |
| 3328 | } | 3326 | } |
| 3329 | 3327 | ||
| 3330 | hdev->hw.mac.req_autoneg = cmd->base.autoneg; | ||
| 3331 | hdev->hw.mac.req_speed = cmd->base.speed; | ||
| 3332 | hdev->hw.mac.req_duplex = cmd->base.duplex; | ||
| 3333 | linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising); | 3328 | linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising); |
| 3329 | return 0; | ||
| 3330 | } | ||
| 3331 | |||
| 3332 | static int | ||
| 3333 | hclge_set_phy_link_ksettings(struct hnae3_handle *handle, | ||
| 3334 | const struct ethtool_link_ksettings *cmd) | ||
| 3335 | { | ||
| 3336 | struct hclge_vport *vport = hclge_get_vport(handle); | ||
| 3337 | struct hclge_dev *hdev = vport->back; | ||
| 3338 | int ret = -ENODEV; | ||
| 3339 | |||
| 3340 | if (hnae3_dev_phy_imp_supported(hdev)) { | ||
| 3341 | ret = hclge_ethtool_ksettings_set(handle, cmd); | ||
| 3342 | } else if (handle->netdev->phydev) { | ||
| 3343 | if (cmd->base.speed == SPEED_1000 && | ||
| 3344 | cmd->base.autoneg == AUTONEG_DISABLE) | ||
| 3345 | return -EINVAL; | ||
| 3346 | ret = phy_ethtool_ksettings_set(handle->netdev->phydev, cmd); | ||
| 3347 | } | ||
| 3348 | if (ret) | ||
| 3349 | return ret; | ||
| 3350 | |||
| 3351 | hdev->hw.mac.req_autoneg = cmd->base.autoneg; | ||
| 3352 | if (cmd->base.speed != SPEED_UNKNOWN) | ||
| 3353 | hdev->hw.mac.req_speed = cmd->base.speed; | ||
| 3354 | if (cmd->base.duplex != DUPLEX_UNKNOWN) | ||
| 3355 | hdev->hw.mac.req_duplex = cmd->base.duplex; | ||
| 3334 | 3356 | ||
| 3335 | return 0; | 3357 | return 0; |
| 3336 | } | 3358 | } |
| @@ -9294,6 +9316,27 @@ static int hclge_set_wol(struct hnae3_handle *handle, · 5957 unmodified lines | |||
| 9294 | return ret; | 9316 | return ret; |
| 9295 | } | 9317 | } |
| 9296 | 9318 | ||
| 9319 | static int hclge_set_autoneg_speed_dup(struct hclge_dev *hdev) | ||
| 9320 | { | ||
| 9321 | int ret; | ||
| 9322 | |||
| 9323 | if (hdev->hw.mac.support_autoneg) { | ||
| 9324 | ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.req_autoneg); | ||
| 9325 | if (ret) | ||
| 9326 | return ret; | ||
| 9327 | } | ||
| 9328 | |||
| 9329 | if (!hdev->hw.mac.req_autoneg) { | ||
| 9330 | ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed, | ||
| 9331 | hdev->hw.mac.req_duplex, | ||
| 9332 | hdev->hw.mac.req_lane_num); | ||
| 9333 | if (ret) | ||
| 9334 | return ret; | ||
| 9335 | } | ||
| 9336 | |||
| 9337 | return 0; | ||
| 9338 | } | ||
| 9339 | |||
| 9297 | static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) | 9340 | static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) |
| 9298 | { | 9341 | { |
| 9299 | struct pci_dev *pdev = ae_dev->pdev; | 9342 | struct pci_dev *pdev = ae_dev->pdev; |
| @@ -9455,6 +9498,20 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) · 155 unmodified lines | |||
| 9455 | if (ret) | 9498 | if (ret) |
| 9456 | goto err_ptp_uninit; | 9499 | goto err_ptp_uninit; |
| 9457 | 9500 | ||
| 9501 | if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) { | ||
| 9502 | hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg; | ||
| 9503 | if (hdev->hw.mac.autoneg == AUTONEG_DISABLE && | ||
| 9504 | hdev->hw.mac.speed != SPEED_UNKNOWN) | ||
| 9505 | hdev->hw.mac.req_speed = hdev->hw.mac.speed; | ||
| 9506 | } | ||
| 9507 | |||
| 9508 | ret = hclge_set_autoneg_speed_dup(hdev); | ||
| 9509 | if (ret) { | ||
| 9510 | dev_err(&pdev->dev, | ||
| 9511 | "failed to set autoneg speed duplex, ret = %d\n", ret); | ||
| 9512 | goto err_ptp_uninit; | ||
| 9513 | } | ||
| 9514 | |||
| 9458 | INIT_KFIFO(hdev->mac_tnl_log); | 9515 | INIT_KFIFO(hdev->mac_tnl_log); |
| 9459 | 9516 | ||
| 9460 | hclge_dcb_ops_set(hdev); | 9517 | hclge_dcb_ops_set(hdev); |
| @@ -9785,6 +9842,13 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) · 324 unmodified lines | |||
| 9785 | return ret; | 9842 | return ret; |
| 9786 | } | 9843 | } |
| 9787 | 9844 | ||
| 9845 | ret = hclge_set_autoneg_speed_dup(hdev); | ||
| 9846 | if (ret) { | ||
| 9847 | dev_err(&pdev->dev, | ||
| 9848 | "failed to set autoneg speed duplex, ret = %d\n", ret); | ||
| 9849 | return ret; | ||
| 9850 | } | ||
| 9851 | |||
| 9788 | ret = hclge_tp_port_init(hdev); | 9852 | ret = hclge_tp_port_init(hdev); |
| 9789 | if (ret) { | 9853 | if (ret) { |
| 9790 | dev_err(&pdev->dev, "failed to init tp port, ret = %d\n", | 9854 | dev_err(&pdev->dev, "failed to init tp port, ret = %d\n", |
| @@ -287,6 +287,7 @@ struct hclge_mac { · 286 unmodified lines | |||
| 287 | u8 support_autoneg; | 287 | u8 support_autoneg; |
| 288 | u8 speed_type; /* 0: sfp speed, 1: active speed */ | 288 | u8 speed_type; /* 0: sfp speed, 1: active speed */ |
| 289 | u8 lane_num; | 289 | u8 lane_num; |
| 290 | u8 req_lane_num; | ||
| 290 | u32 speed; | 291 | u32 speed; |
| 291 | u32 req_speed; | 292 | u32 req_speed; |
| 292 | u32 max_speed; | 293 | u32 max_speed; |
| @@ -3216,6 +3216,8 @@ static int ehea_create_device_sysfs(struct platform_device *dev) · 3215 unmodified lines | |||
| 3216 | goto out; | 3216 | goto out; |
| 3217 | 3217 | ||
| 3218 | ret = device_create_file(&dev->dev, &dev_attr_remove_port); | 3218 | ret = device_create_file(&dev->dev, &dev_attr_remove_port); |
| 3219 | if (ret) | ||
| 3220 | device_remove_file(&dev->dev, &dev_attr_probe_port); | ||
| 3219 | out: | 3221 | out: |
| 3220 | return ret; | 3222 | return ret; |
| 3221 | } | 3223 | } |
| @@ -3044,6 +3044,12 @@ static int emac_probe(struct platform_device *ofdev) · 3043 unmodified lines | |||
| 3044 | if (err) | 3044 | if (err) |
| 3045 | goto err_gone; | 3045 | goto err_gone; |
| 3046 | 3046 | ||
| 3047 | dev->emacp = devm_platform_ioremap_resource(ofdev, 0); | ||
| 3048 | if (IS_ERR(dev->emacp)) { | ||
| 3049 | err = PTR_ERR(dev->emacp); | ||
| 3050 | goto err_gone; | ||
| 3051 | } | ||
| 3052 | |||
| 3047 | /* Setup error IRQ handler */ | 3053 | /* Setup error IRQ handler */ |
| 3048 | dev->emac_irq = platform_get_irq(ofdev, 0); | 3054 | dev->emac_irq = platform_get_irq(ofdev, 0); |
| 3049 | if (dev->emac_irq < 0) { | 3055 | if (dev->emac_irq < 0) { |
| @@ -3061,13 +3067,6 @@ static int emac_probe(struct platform_device *ofdev) · 11 unmodified lines | |||
| 3061 | 3067 | ||
| 3062 | ndev->irq = dev->emac_irq; | 3068 | ndev->irq = dev->emac_irq; |
| 3063 | 3069 | ||
| 3064 | dev->emacp = devm_platform_ioremap_resource(ofdev, 0); | ||
| 3065 | if (IS_ERR(dev->emacp)) { | ||
| 3066 | dev_err(&ofdev->dev, "can't map device registers"); | ||
| 3067 | err = PTR_ERR(dev->emacp); | ||
| 3068 | goto err_gone; | ||
| 3069 | } | ||
| 3070 | |||
| 3071 | /* Wait for dependent devices */ | 3070 | /* Wait for dependent devices */ |
| 3072 | err = emac_wait_deps(dev); | 3071 | err = emac_wait_deps(dev); |
| 3073 | if (err) | 3072 | if (err) |
| @@ -1594,6 +1594,9 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) · 1593 unmodified lines | |||
| 1594 | phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; | 1594 | phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; |
| 1595 | if (speed == SPEED_100 || speed == SPEED_10) | 1595 | if (speed == SPEED_100 || speed == SPEED_10) |
| 1596 | phy_reg |= 0x3E8; | 1596 | phy_reg |= 0x3E8; |
| 1597 | else if (hw->mac.type == e1000_pch_mtp || | ||
| 1598 | hw->mac.type == e1000_pch_ptp) | ||
| 1599 | phy_reg |= 0x1D5; | ||
| 1597 | else | 1600 | else |
| 1598 | phy_reg |= 0xFA; | 1601 | phy_reg |= 0xFA; |
| 1599 | e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg); | 1602 | e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg); |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
| 26 | #include <linux/prefetch.h> | 26 | #include <linux/prefetch.h> |
| 27 | #include <linux/suspend.h> | 27 | #include <linux/suspend.h> |
| 28 | #include <linux/dmi.h> | ||
| 28 | 29 | ||
| 29 | #include "e1000.h" | 30 | #include "e1000.h" |
| 30 | #define CREATE_TRACE_POINTS | 31 | #define CREATE_TRACE_POINTS |
| @@ -58,6 +59,17 @@ static const struct e1000_info *e1000_info_tbl[] = { · 27 unmodified lines | |||
| 58 | [board_pch_ptp] = &e1000_pch_ptp_info, | 59 | [board_pch_ptp] = &e1000_pch_ptp_info, |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
| 62 | static const struct dmi_system_id disable_k1_list[] = { | ||
| 63 | { | ||
| 64 | .ident = "Dell Pro 16 Plus PB16250", | ||
| 65 | .matches = { | ||
| 66 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
| 67 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro 16 Plus PB16250"), | ||
| 68 | }, | ||
| 69 | }, | ||
| 70 | {} | ||
| 71 | }; | ||
| 72 | |||
| 61 | struct e1000_reg_info { | 73 | struct e1000_reg_info { |
| 62 | u32 ofs; | 74 | u32 ofs; |
| 63 | char *name; | 75 | char *name; |
| @@ -7670,7 +7682,8 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 7606 unmodified lines | |||
| 7670 | /* init PTP hardware clock */ | 7682 | /* init PTP hardware clock */ |
| 7671 | e1000e_ptp_init(adapter); | 7683 | e1000e_ptp_init(adapter); |
| 7672 | 7684 | ||
| 7673 | if (hw->mac.type >= e1000_pch_mtp) | 7685 | /* disable K1 by default on known problematic systems */ |
| 7686 | if (hw->mac.type >= e1000_pch_mtp && dmi_check_system(disable_k1_list)) | ||
| 7674 | adapter->flags2 |= FLAG2_DISABLE_K1; | 7687 | adapter->flags2 |= FLAG2_DISABLE_K1; |
| 7675 | 7688 | ||
| 7676 | /* reset the hardware with the new settings */ | 7689 | /* reset the hardware with the new settings */ |
| @@ -42,7 +42,7 @@ struct device *i40e_hw_to_dev(struct i40e_hw *hw); · 41 unmodified lines | |||
| 42 | #define i40e_debug(h, m, s, ...) \ | 42 | #define i40e_debug(h, m, s, ...) \ |
| 43 | do { \ | 43 | do { \ |
| 44 | if (((m) & (h)->debug_mask)) \ | 44 | if (((m) & (h)->debug_mask)) \ |
| 45 | dev_info(i40e_hw_to_dev(hw), s, ##__VA_ARGS__); \ | 45 | dev_info(i40e_hw_to_dev(h), s, ##__VA_ARGS__); \ |
| 46 | } while (0) | 46 | } while (0) |
| 47 | 47 | ||
| 48 | #endif /* _I40E_DEBUG_H_ */ | 48 | #endif /* _I40E_DEBUG_H_ */ |
| @@ -1855,6 +1855,7 @@ static const struct ethtool_ops iavf_ethtool_ops = { · 1854 unmodified lines | |||
| 1855 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | | 1855 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
| 1856 | ETHTOOL_COALESCE_USE_ADAPTIVE, | 1856 | ETHTOOL_COALESCE_USE_ADAPTIVE, |
| 1857 | .supported_input_xfrm = RXH_XFRM_SYM_XOR, | 1857 | .supported_input_xfrm = RXH_XFRM_SYM_XOR, |
| 1858 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 1858 | .get_drvinfo = iavf_get_drvinfo, | 1859 | .get_drvinfo = iavf_get_drvinfo, |
| 1859 | .get_link = ethtool_op_get_link, | 1860 | .get_link = ethtool_op_get_link, |
| 1860 | .get_ringparam = iavf_get_ringparam, | 1861 | .get_ringparam = iavf_get_ringparam, |
| @@ -3882,7 +3882,6 @@ ice_set_fc(struct ice_port_info *pi, u8 *aq_failures, bool ena_auto_link_update) · 3881 unmodified lines | |||
| 3882 | if (!pi || !aq_failures) | 3882 | if (!pi || !aq_failures) |
| 3883 | return -EINVAL; | 3883 | return -EINVAL; |
| 3884 | 3884 | ||
| 3885 | *aq_failures = 0; | ||
| 3886 | hw = pi->hw; | 3885 | hw = pi->hw; |
| 3887 | 3886 | ||
| 3888 | pcaps = kzalloc_obj(*pcaps); | 3887 | pcaps = kzalloc_obj(*pcaps); |
| @@ -4645,9 +4645,13 @@ ice_dpll_init_pins_info(struct ice_pf *pf, enum ice_dpll_pin_type pin_type) · 4644 unmodified lines | |||
| 4645 | static void ice_dpll_deinit_info(struct ice_pf *pf) | 4645 | static void ice_dpll_deinit_info(struct ice_pf *pf) |
| 4646 | { | 4646 | { |
| 4647 | kfree(pf->dplls.inputs); | 4647 | kfree(pf->dplls.inputs); |
| 4648 | pf->dplls.inputs = NULL; | ||
| 4648 | kfree(pf->dplls.outputs); | 4649 | kfree(pf->dplls.outputs); |
| 4650 | pf->dplls.outputs = NULL; | ||
| 4649 | kfree(pf->dplls.eec.input_prio); | 4651 | kfree(pf->dplls.eec.input_prio); |
| 4652 | pf->dplls.eec.input_prio = NULL; | ||
| 4650 | kfree(pf->dplls.pps.input_prio); | 4653 | kfree(pf->dplls.pps.input_prio); |
| 4654 | pf->dplls.pps.input_prio = NULL; | ||
| 4651 | } | 4655 | } |
| 4652 | 4656 | ||
| 4653 | /** | 4657 | /** |
| @@ -4748,12 +4752,16 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) · 94 unmodified lines | |||
| 4748 | 4752 | ||
| 4749 | alloc_size = sizeof(*de->input_prio) * d->num_inputs; | 4753 | alloc_size = sizeof(*de->input_prio) * d->num_inputs; |
| 4750 | de->input_prio = kzalloc(alloc_size, GFP_KERNEL); | 4754 | de->input_prio = kzalloc(alloc_size, GFP_KERNEL); |
| 4751 | if (!de->input_prio) | 4755 | if (!de->input_prio) { |
| 4752 | return -ENOMEM; | 4756 | ret = -ENOMEM; |
| 4757 | goto deinit_info; | ||
| 4758 | } | ||
| 4753 | 4759 | ||
| 4754 | dp->input_prio = kzalloc(alloc_size, GFP_KERNEL); | 4760 | dp->input_prio = kzalloc(alloc_size, GFP_KERNEL); |
| 4755 | if (!dp->input_prio) | 4761 | if (!dp->input_prio) { |
| 4756 | return -ENOMEM; | 4762 | ret = -ENOMEM; |
| 4763 | goto deinit_info; | ||
| 4764 | } | ||
| 4757 | 4765 | ||
| 4758 | ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); | 4766 | ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_INPUT); |
| 4759 | if (ret) | 4767 | if (ret) |
| @@ -4778,12 +4786,12 @@ static int ice_dpll_init_info(struct ice_pf *pf, bool cgu) · 18 unmodified lines | |||
| 4778 | ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, | 4786 | ret = ice_get_cgu_rclk_pin_info(&pf->hw, &d->base_rclk_idx, |
| 4779 | &pf->dplls.rclk.num_parents); | 4787 | &pf->dplls.rclk.num_parents); |
| 4780 | if (ret) | 4788 | if (ret) |
| 4781 | return ret; | 4789 | goto deinit_info; |
| 4782 | for (i = 0; i < pf->dplls.rclk.num_parents; i++) | 4790 | for (i = 0; i < pf->dplls.rclk.num_parents; i++) |
| 4783 | pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; | 4791 | pf->dplls.rclk.parent_idx[i] = d->base_rclk_idx + i; |
| 4784 | ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); | 4792 | ret = ice_dpll_init_pins_info(pf, ICE_DPLL_PIN_TYPE_RCLK_INPUT); |
| 4785 | if (ret) | 4793 | if (ret) |
| 4786 | return ret; | 4794 | goto deinit_info; |
| 4787 | de->mode = DPLL_MODE_AUTOMATIC; | 4795 | de->mode = DPLL_MODE_AUTOMATIC; |
| 4788 | dp->mode = DPLL_MODE_AUTOMATIC; | 4796 | dp->mode = DPLL_MODE_AUTOMATIC; |
| 4789 | 4797 | ||
| @@ -117,8 +117,6 @@ static int ice_eswitch_setup_repr(struct ice_pf *pf, struct ice_repr *repr) · 116 unmodified lines | |||
| 117 | if (!repr->dst) | 117 | if (!repr->dst) |
| 118 | return -ENOMEM; | 118 | return -ENOMEM; |
| 119 | 119 | ||
| 120 | netif_keep_dst(uplink_vsi->netdev); | ||
| 121 | |||
| 122 | dst = repr->dst; | 120 | dst = repr->dst; |
| 123 | dst->u.port_info.port_id = vsi->vsi_num; | 121 | dst->u.port_info.port_id = vsi->vsi_num; |
| 124 | dst->u.port_info.lower_dev = uplink_vsi->netdev; | 122 | dst->u.port_info.lower_dev = uplink_vsi->netdev; |
| @@ -312,6 +310,8 @@ static int ice_eswitch_enable_switchdev(struct ice_pf *pf) · 187 unmodified lines | |||
| 312 | if (ice_eswitch_br_offloads_init(pf)) | 310 | if (ice_eswitch_br_offloads_init(pf)) |
| 313 | goto err_br_offloads; | 311 | goto err_br_offloads; |
| 314 | 312 | ||
| 313 | netif_keep_dst(uplink_vsi->netdev); | ||
| 314 | |||
| 315 | pf->eswitch.is_running = true; | 315 | pf->eswitch.is_running = true; |
| 316 | 316 | ||
| 317 | return 0; | 317 | return 0; |
| @@ -3508,7 +3508,7 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) · 3507 unmodified lines | |||
| 3508 | struct ice_vsi *vsi = np->vsi; | 3508 | struct ice_vsi *vsi = np->vsi; |
| 3509 | struct ice_hw *hw = &pf->hw; | 3509 | struct ice_hw *hw = &pf->hw; |
| 3510 | struct ice_port_info *pi; | 3510 | struct ice_port_info *pi; |
| 3511 | u8 aq_failures; | 3511 | u8 aq_failures = 0; |
| 3512 | bool link_up; | 3512 | bool link_up; |
| 3513 | u32 is_an; | 3513 | u32 is_an; |
| 3514 | int err; | 3514 | int err; |
| @@ -3579,18 +3579,22 @@ ice_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) · 64 unmodified lines | |||
| 3579 | /* Set the FC mode and only restart AN if link is up */ | 3579 | /* Set the FC mode and only restart AN if link is up */ |
| 3580 | err = ice_set_fc(pi, &aq_failures, link_up); | 3580 | err = ice_set_fc(pi, &aq_failures, link_up); |
| 3581 | 3581 | ||
| 3582 | if (aq_failures & ICE_SET_FC_AQ_FAIL_GET) { | 3582 | switch (aq_failures) { |
| 3583 | case ICE_SET_FC_AQ_FAIL_GET: | ||
| 3583 | netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n", | 3584 | netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %d aq_err %s\n", |
| 3584 | err, libie_aq_str(hw->adminq.sq_last_status)); | 3585 | err, libie_aq_str(hw->adminq.sq_last_status)); |
| 3585 | err = -EAGAIN; | 3586 | err = -EAGAIN; |
| 3586 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_SET) { | 3587 | break; |
| 3588 | case ICE_SET_FC_AQ_FAIL_SET: | ||
| 3587 | netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n", | 3589 | netdev_info(netdev, "Set fc failed on the set_phy_config call with err %d aq_err %s\n", |
| 3588 | err, libie_aq_str(hw->adminq.sq_last_status)); | 3590 | err, libie_aq_str(hw->adminq.sq_last_status)); |
| 3589 | err = -EAGAIN; | 3591 | err = -EAGAIN; |
| 3590 | } else if (aq_failures & ICE_SET_FC_AQ_FAIL_UPDATE) { | 3592 | break; |
| 3593 | case ICE_SET_FC_AQ_FAIL_UPDATE: | ||
| 3591 | netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n", | 3594 | netdev_info(netdev, "Set fc failed on the get_link_info call with err %d aq_err %s\n", |
| 3592 | err, libie_aq_str(hw->adminq.sq_last_status)); | 3595 | err, libie_aq_str(hw->adminq.sq_last_status)); |
| 3593 | err = -EAGAIN; | 3596 | err = -EAGAIN; |
| 3597 | break; | ||
| 3594 | } | 3598 | } |
| 3595 | 3599 | ||
| 3596 | return err; | 3600 | return err; |
| @@ -4789,16 +4789,14 @@ static void ice_init_wakeup(struct ice_pf *pf) · 4788 unmodified lines | |||
| 4789 | device_set_wakeup_enable(ice_pf_to_dev(pf), false); | 4789 | device_set_wakeup_enable(ice_pf_to_dev(pf), false); |
| 4790 | } | 4790 | } |
| 4791 | 4791 | ||
| 4792 | static int ice_init_link(struct ice_pf *pf) | 4792 | static void ice_init_link(struct ice_pf *pf) |
| 4793 | { | 4793 | { |
| 4794 | struct device *dev = ice_pf_to_dev(pf); | 4794 | struct device *dev = ice_pf_to_dev(pf); |
| 4795 | int err; | 4795 | int err; |
| 4796 | 4796 | ||
| 4797 | err = ice_init_link_events(pf->hw.port_info); | 4797 | err = ice_init_link_events(pf->hw.port_info); |
| 4798 | if (err) { | 4798 | if (err) |
| 4799 | dev_err(dev, "ice_init_link_events failed: %d\n", err); | 4799 | dev_err(dev, "ice_init_link_events failed: %d\n", err); |
| 4800 | return err; | ||
| 4801 | } | ||
| 4802 | 4800 | ||
| 4803 | /* not a fatal error if this fails */ | 4801 | /* not a fatal error if this fails */ |
| 4804 | err = ice_init_nvm_phy_type(pf->hw.port_info); | 4802 | err = ice_init_nvm_phy_type(pf->hw.port_info); |
| @@ -4838,8 +4836,6 @@ static int ice_init_link(struct ice_pf *pf) · 33 unmodified lines | |||
| 4838 | } else { | 4836 | } else { |
| 4839 | set_bit(ICE_FLAG_NO_MEDIA, pf->flags); | 4837 | set_bit(ICE_FLAG_NO_MEDIA, pf->flags); |
| 4840 | } | 4838 | } |
| 4841 | |||
| 4842 | return err; | ||
| 4843 | } | 4839 | } |
| 4844 | 4840 | ||
| 4845 | static int ice_init_pf_sw(struct ice_pf *pf) | 4841 | static int ice_init_pf_sw(struct ice_pf *pf) |
| @@ -4982,13 +4978,11 @@ static int ice_init(struct ice_pf *pf) · 136 unmodified lines | |||
| 4982 | 4978 | ||
| 4983 | ice_init_wakeup(pf); | 4979 | ice_init_wakeup(pf); |
| 4984 | 4980 | ||
| 4985 | err = ice_init_link(pf); | 4981 | ice_init_link(pf); |
| 4986 | if (err) | ||
| 4987 | goto err_init_link; | ||
| 4988 | 4982 | ||
| 4989 | err = ice_send_version(pf); | 4983 | err = ice_send_version(pf); |
| 4990 | if (err) | 4984 | if (err) |
| 4991 | goto err_init_link; | 4985 | goto err_deinit_pf_sw; |
| 4992 | 4986 | ||
| 4993 | ice_verify_cacheline_size(pf); | 4987 | ice_verify_cacheline_size(pf); |
| 4994 | 4988 | ||
| @@ -5007,7 +5001,7 @@ static int ice_init(struct ice_pf *pf) · 12 unmodified lines | |||
| 5007 | 5001 | ||
| 5008 | return 0; | 5002 | return 0; |
| 5009 | 5003 | ||
| 5010 | err_init_link: | 5004 | err_deinit_pf_sw: |
| 5011 | ice_deinit_pf_sw(pf); | 5005 | ice_deinit_pf_sw(pf); |
| 5012 | err_init_pf_sw: | 5006 | err_init_pf_sw: |
| 5013 | ice_dealloc_vsis(pf); | 5007 | ice_dealloc_vsis(pf); |
| @@ -801,7 +801,7 @@ void ice_reset_all_vfs(struct ice_pf *pf) · 800 unmodified lines | |||
| 801 | * setup only when VF creates its first FDIR rule. | 801 | * setup only when VF creates its first FDIR rule. |
| 802 | */ | 802 | */ |
| 803 | if (vf->ctrl_vsi_idx != ICE_NO_VSI) | 803 | if (vf->ctrl_vsi_idx != ICE_NO_VSI) |
| 804 | ice_vf_ctrl_invalidate_vsi(vf); | 804 | ice_vf_ctrl_vsi_release(vf); |
| 805 | 805 | ||
| 806 | ice_vf_pre_vsi_rebuild(vf); | 806 | ice_vf_pre_vsi_rebuild(vf); |
| 807 | if (ice_vf_rebuild_vsi(vf)) { | 807 | if (ice_vf_rebuild_vsi(vf)) { |
| @@ -5900,6 +5900,9 @@ static int mvneta_resume(struct device *device) · 5899 unmodified lines | |||
| 5900 | rtnl_unlock(); | 5900 | rtnl_unlock(); |
| 5901 | mvneta_set_rx_mode(dev); | 5901 | mvneta_set_rx_mode(dev); |
| 5902 | 5902 | ||
| 5903 | if (!pp->neta_armada3700) | ||
| 5904 | on_each_cpu(mvneta_percpu_enable, pp, true); | ||
| 5905 | |||
| 5903 | return 0; | 5906 | return 0; |
| 5904 | } | 5907 | } |
| 5905 | #endif | 5908 | #endif |
| @@ -3423,6 +3423,36 @@ static int npc_create_srch_order(int cnt) · 3422 unmodified lines | |||
| 3423 | return 0; | 3423 | return 0; |
| 3424 | } | 3424 | } |
| 3425 | 3425 | ||
| 3426 | static int npc_subbanks_srch_order_init(struct rvu *rvu) | ||
| 3427 | { | ||
| 3428 | struct npc_subbank *sb; | ||
| 3429 | int sb_idx; | ||
| 3430 | int i, j; | ||
| 3431 | int rc; | ||
| 3432 | |||
| 3433 | for (i = 0; i < npc_priv->num_subbanks; i++) { | ||
| 3434 | sb_idx = subbank_srch_order[i]; | ||
| 3435 | sb = &npc_priv->sb[sb_idx]; | ||
| 3436 | sb->arr_idx = i; | ||
| 3437 | |||
| 3438 | dev_dbg(rvu->dev, "%s: sb->idx=%u sb->arr_idx=%u\n", | ||
| 3439 | __func__, sb->idx, sb->arr_idx); | ||
| 3440 | |||
| 3441 | rc = xa_err(xa_store(&npc_priv->xa_sb_free, sb->arr_idx, | ||
| 3442 | xa_mk_value(sb->idx), GFP_KERNEL)); | ||
| 3443 | if (rc) { | ||
| 3444 | dev_err(rvu->dev, | ||
| 3445 | "%s: xa_store(xa_sb_free) failed at slot %d (sb=%d): %d\n", | ||
| 3446 | __func__, i, sb_idx, rc); | ||
| 3447 | for (j = 0; j < i; j++) | ||
| 3448 | xa_erase(&npc_priv->xa_sb_free, j); | ||
| 3449 | return rc; | ||
| 3450 | } | ||
| 3451 | } | ||
| 3452 | |||
| 3453 | return 0; | ||
| 3454 | } | ||
| 3455 | |||
| 3426 | static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx) | 3456 | static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx) |
| 3427 | { | 3457 | { |
| 3428 | mutex_init(&sb->lock); | 3458 | mutex_init(&sb->lock); |
| @@ -3435,16 +3465,6 @@ static void npc_subbank_init(struct rvu *rvu, struct npc_subbank *sb, int idx) · 6 unmodified lines | |||
| 3435 | 3465 | ||
| 3436 | sb->flags = NPC_SUBBANK_FLAG_FREE; | 3466 | sb->flags = NPC_SUBBANK_FLAG_FREE; |
| 3437 | sb->idx = idx; | 3467 | sb->idx = idx; |
| 3438 | sb->arr_idx = subbank_srch_order[idx]; | ||
| 3439 | |||
| 3440 | dev_dbg(rvu->dev, "%s: sb->idx=%u sb->arr_idx=%u\n", | ||
| 3441 | __func__, sb->idx, sb->arr_idx); | ||
| 3442 | |||
| 3443 | /* Keep first and last subbank at end of free array; so that | ||
| 3444 | * it will be used at last | ||
| 3445 | */ | ||
| 3446 | xa_store(&npc_priv->xa_sb_free, sb->arr_idx, | ||
| 3447 | xa_mk_value(sb->idx), GFP_KERNEL); | ||
| 3448 | } | 3468 | } |
| 3449 | 3469 | ||
| 3450 | static int npc_pcifunc_map_create(struct rvu *rvu) | 3470 | static int npc_pcifunc_map_create(struct rvu *rvu) |
| @@ -3569,15 +3589,18 @@ static int npc_defrag_alloc_free_slots(struct rvu *rvu, · 118 unmodified lines | |||
| 3569 | alloc_cnt2 = 0; | 3589 | alloc_cnt2 = 0; |
| 3570 | 3590 | ||
| 3571 | rc = __npc_subbank_alloc(rvu, sb, | 3591 | rc = __npc_subbank_alloc(rvu, sb, |
| 3572 | NPC_MCAM_KEY_X2, sb->b0b, | 3592 | f->key_type, sb->b0b, |
| 3573 | sb->b0t, | 3593 | sb->b0t, |
| 3574 | NPC_MCAM_LOWER_PRIO, | 3594 | NPC_MCAM_LOWER_PRIO, |
| 3575 | false, cnt, save, cnt, true, | 3595 | false, cnt, save, cnt, true, |
| 3576 | &alloc_cnt1); | 3596 | &alloc_cnt1); |
| 3577 | 3597 | ||
| 3578 | if (alloc_cnt1 < cnt) { | 3598 | /* X4 entries only occupy bank 0 (b0b..b0t); see npc_subbank_idx_2_mcam_idx(). |
| 3599 | * X2 uses both halves of the subbank, so spill into bank 1 if needed. | ||
| 3600 | */ | ||
| 3601 | if (alloc_cnt1 < cnt && f->key_type == NPC_MCAM_KEY_X2) { | ||
| 3579 | rc = __npc_subbank_alloc(rvu, sb, | 3602 | rc = __npc_subbank_alloc(rvu, sb, |
| 3580 | NPC_MCAM_KEY_X2, sb->b1b, | 3603 | f->key_type, sb->b1b, |
| 3581 | sb->b1t, | 3604 | sb->b1t, |
| 3582 | NPC_MCAM_LOWER_PRIO, | 3605 | NPC_MCAM_LOWER_PRIO, |
| 3583 | false, cnt - alloc_cnt1, | 3606 | false, cnt - alloc_cnt1, |
| @@ -4635,6 +4658,7 @@ static int npc_priv_init(struct rvu *rvu) · 1051 unmodified lines | |||
| 4635 | int num_subbanks, subbank_depth; | 4658 | int num_subbanks, subbank_depth; |
| 4636 | u64 npc_const1, npc_const2 = 0; | 4659 | u64 npc_const1, npc_const2 = 0; |
| 4637 | struct npc_subbank *sb; | 4660 | struct npc_subbank *sb; |
| 4661 | int ret = -ENOMEM; | ||
| 4638 | u64 cfg; | 4662 | u64 cfg; |
| 4639 | int i; | 4663 | int i; |
| 4640 | 4664 | ||
| @@ -4727,13 +4751,19 @@ static int npc_priv_init(struct rvu *rvu) · 86 unmodified lines | |||
| 4727 | for (i = 0, sb = npc_priv->sb; i < num_subbanks; i++, sb++) | 4751 | for (i = 0, sb = npc_priv->sb; i < num_subbanks; i++, sb++) |
| 4728 | npc_subbank_init(rvu, sb, i); | 4752 | npc_subbank_init(rvu, sb, i); |
| 4729 | 4753 | ||
| 4754 | ret = npc_subbanks_srch_order_init(rvu); | ||
| 4755 | if (ret) | ||
| 4756 | goto fail3; | ||
| 4757 | |||
| 4730 | /* Get number of pcifuncs in the system */ | 4758 | /* Get number of pcifuncs in the system */ |
| 4731 | npc_priv->pf_cnt = npc_pcifunc_map_create(rvu); | 4759 | npc_priv->pf_cnt = npc_pcifunc_map_create(rvu); |
| 4732 | npc_priv->xa_pf2idx_map = kcalloc(npc_priv->pf_cnt, | 4760 | npc_priv->xa_pf2idx_map = kcalloc(npc_priv->pf_cnt, |
| 4733 | sizeof(struct xarray), | 4761 | sizeof(struct xarray), |
| 4734 | GFP_KERNEL); | 4762 | GFP_KERNEL); |
| 4735 | if (!npc_priv->xa_pf2idx_map) | 4763 | if (!npc_priv->xa_pf2idx_map) { |
| 4764 | ret = -ENOMEM; | ||
| 4736 | goto fail3; | 4765 | goto fail3; |
| 4766 | } | ||
| 4737 | 4767 | ||
| 4738 | for (i = 0; i < npc_priv->pf_cnt; i++) | 4768 | for (i = 0; i < npc_priv->pf_cnt; i++) |
| 4739 | xa_init_flags(&npc_priv->xa_pf2idx_map[i], XA_FLAGS_ALLOC); | 4769 | xa_init_flags(&npc_priv->xa_pf2idx_map[i], XA_FLAGS_ALLOC); |
| @@ -4760,7 +4790,7 @@ fail2: · 20 unmodified lines | |||
| 4760 | fail1: | 4790 | fail1: |
| 4761 | kfree(npc_priv); | 4791 | kfree(npc_priv); |
| 4762 | npc_priv = NULL; | 4792 | npc_priv = NULL; |
| 4763 | return -ENOMEM; | 4793 | return ret; |
| 4764 | } | 4794 | } |
| 4765 | 4795 | ||
| 4766 | void npc_cn20k_deinit(struct rvu *rvu) | 4796 | void npc_cn20k_deinit(struct rvu *rvu) |
| @@ -120,13 +120,13 @@ void mcs_get_rx_secy_stats(struct mcs *mcs, struct mcs_secy_stats *stats, int id · 119 unmodified lines | |||
| 120 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYUNTAGGEDX(id); | 120 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYUNTAGGEDX(id); |
| 121 | stats->pkt_untaged_cnt = mcs_reg_read(mcs, reg); | 121 | stats->pkt_untaged_cnt = mcs_reg_read(mcs, reg); |
| 122 | 122 | ||
| 123 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX(id); | ||
| 124 | stats->pkt_ctl_cnt = mcs_reg_read(mcs, reg); | ||
| 125 | |||
| 126 | if (mcs->hw->mcs_blks > 1) { | 123 | if (mcs->hw->mcs_blks > 1) { |
| 127 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOTAGX(id); | 124 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYNOTAGX(id); |
| 128 | stats->pkt_notag_cnt = mcs_reg_read(mcs, reg); | 125 | stats->pkt_notag_cnt = mcs_reg_read(mcs, reg); |
| 126 | return; | ||
| 129 | } | 127 | } |
| 128 | reg = MCSX_CSE_RX_MEM_SLAVE_INPKTSSECYCTLX(id); | ||
| 129 | stats->pkt_ctl_cnt = mcs_reg_read(mcs, reg); | ||
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void mcs_get_flowid_stats(struct mcs *mcs, struct mcs_flowid_stats *stats, | 132 | void mcs_get_flowid_stats(struct mcs *mcs, struct mcs_flowid_stats *stats, |
| @@ -178,6 +178,15 @@ int rvu_mbox_handler_lmtst_tbl_setup(struct rvu *rvu, · 177 unmodified lines | |||
| 178 | * pcifunc (will be the one who is calling this mailbox). | 178 | * pcifunc (will be the one who is calling this mailbox). |
| 179 | */ | 179 | */ |
| 180 | if (req->base_pcifunc) { | 180 | if (req->base_pcifunc) { |
| 181 | /* A VF is untrusted and must not redirect its LMTLINE to | ||
| 182 | * another PF's region, so confine VF callers to their own PF. | ||
| 183 | */ | ||
| 184 | if (is_vf(req->hdr.pcifunc) && | ||
| 185 | (!is_pf_func_valid(rvu, req->base_pcifunc) || | ||
| 186 | rvu_get_pf(rvu->pdev, req->hdr.pcifunc) != | ||
| 187 | rvu_get_pf(rvu->pdev, req->base_pcifunc))) | ||
| 188 | return -EPERM; | ||
| 189 | |||
| 181 | /* Calculating the LMT table index equivalent to primary | 190 | /* Calculating the LMT table index equivalent to primary |
| 182 | * pcifunc. | 191 | * pcifunc. |
| 183 | */ | 192 | */ |
| @@ -482,10 +482,11 @@ static int rvu_dbg_mcs_rx_secy_stats_display(struct seq_file *filp, void *unused · 481 unmodified lines | |||
| 482 | seq_printf(filp, "secy%d: Tagged ctrl pkts: %lld\n", secy_id, | 482 | seq_printf(filp, "secy%d: Tagged ctrl pkts: %lld\n", secy_id, |
| 483 | stats.pkt_tagged_ctl_cnt); | 483 | stats.pkt_tagged_ctl_cnt); |
| 484 | seq_printf(filp, "secy%d: Untaged pkts: %lld\n", secy_id, stats.pkt_untaged_cnt); | 484 | seq_printf(filp, "secy%d: Untaged pkts: %lld\n", secy_id, stats.pkt_untaged_cnt); |
| 485 | seq_printf(filp, "secy%d: Ctrl pkts: %lld\n", secy_id, stats.pkt_ctl_cnt); | ||
| 486 | if (mcs->hw->mcs_blks > 1) | 485 | if (mcs->hw->mcs_blks > 1) |
| 487 | seq_printf(filp, "secy%d: pkts notag: %lld\n", secy_id, | 486 | seq_printf(filp, "secy%d: pkts notag: %lld\n", secy_id, |
| 488 | stats.pkt_notag_cnt); | 487 | stats.pkt_notag_cnt); |
| 488 | else | ||
| 489 | seq_printf(filp, "secy%d: Ctrl pkts: %lld\n", secy_id, stats.pkt_ctl_cnt); | ||
| 489 | } | 490 | } |
| 490 | mutex_unlock(&mcs->stats_lock); | 491 | mutex_unlock(&mcs->stats_lock); |
| 491 | return 0; | 492 | return 0; |
| @@ -2809,6 +2810,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu) · 2317 unmodified lines | |||
| 2809 | &rvu_dbg_npa_ndc_hits_miss_fops); | 2810 | &rvu_dbg_npa_ndc_hits_miss_fops); |
| 2810 | } | 2811 | } |
| 2811 | 2812 | ||
| 2813 | /* Per-lmac CGX debugfs files need both RVU and CGX handle; inode->i_private | ||
| 2814 | * points here so seq_file ops avoid pci_get_device(PCI_DEVID_OCTEONTX2_RVU_AF). | ||
| 2815 | */ | ||
| 2816 | struct rvu_cgx_lmac_dbgfs_ctx { | ||
| 2817 | struct rvu *rvu; | ||
| 2818 | void *cgxd; | ||
| 2819 | }; | ||
| 2820 | |||
| 2812 | #define PRINT_CGX_CUML_NIXRX_STATUS(idx, name) \ | 2821 | #define PRINT_CGX_CUML_NIXRX_STATUS(idx, name) \ |
| 2813 | ({ \ | 2822 | ({ \ |
| 2814 | u64 cnt; \ | 2823 | u64 cnt; \ |
| @@ -2831,18 +2840,14 @@ static void rvu_dbg_npa_init(struct rvu *rvu) · 16 unmodified lines | |||
| 2831 | 2840 | ||
| 2832 | static int cgx_print_stats(struct seq_file *s, int lmac_id) | 2841 | static int cgx_print_stats(struct seq_file *s, int lmac_id) |
| 2833 | { | 2842 | { |
| 2843 | struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; | ||
| 2834 | struct cgx_link_user_info linfo; | 2844 | struct cgx_link_user_info linfo; |
| 2845 | struct rvu *rvu = dctx->rvu; | ||
| 2835 | struct mac_ops *mac_ops; | 2846 | struct mac_ops *mac_ops; |
| 2836 | void *cgxd = s->private; | 2847 | void *cgxd = dctx->cgxd; |
| 2837 | u64 ucast, mcast, bcast; | 2848 | u64 ucast, mcast, bcast; |
| 2838 | int stat = 0, err = 0; | 2849 | int stat = 0, err = 0; |
| 2839 | u64 tx_stat, rx_stat; | 2850 | u64 tx_stat, rx_stat; |
| 2840 | struct rvu *rvu; | ||
| 2841 | |||
| 2842 | rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, | ||
| 2843 | PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); | ||
| 2844 | if (!rvu) | ||
| 2845 | return -ENODEV; | ||
| 2846 | 2851 | ||
| 2847 | mac_ops = get_mac_ops(cgxd); | 2852 | mac_ops = get_mac_ops(cgxd); |
| 2848 | /* There can be no CGX devices at all */ | 2853 | /* There can be no CGX devices at all */ |
| @@ -2949,20 +2954,16 @@ RVU_DEBUG_SEQ_FOPS(cgx_stat, cgx_stat_display, NULL); · 100 unmodified lines | |||
| 2949 | 2954 | ||
| 2950 | static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id) | 2955 | static int cgx_print_dmac_flt(struct seq_file *s, int lmac_id) |
| 2951 | { | 2956 | { |
| 2957 | struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; | ||
| 2958 | struct rvu *rvu = dctx->rvu; | ||
| 2952 | struct pci_dev *pdev = NULL; | 2959 | struct pci_dev *pdev = NULL; |
| 2953 | void *cgxd = s->private; | 2960 | void *cgxd = dctx->cgxd; |
| 2954 | char *bcast, *mcast; | 2961 | char *bcast, *mcast; |
| 2955 | u16 index, domain; | 2962 | u16 index, domain; |
| 2956 | u8 dmac[ETH_ALEN]; | 2963 | u8 dmac[ETH_ALEN]; |
| 2957 | struct rvu *rvu; | ||
| 2958 | u64 cfg, mac; | 2964 | u64 cfg, mac; |
| 2959 | int pf; | 2965 | int pf; |
| 2960 | 2966 | ||
| 2961 | rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, | ||
| 2962 | PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); | ||
| 2963 | if (!rvu) | ||
| 2964 | return -ENODEV; | ||
| 2965 | |||
| 2966 | pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id); | 2967 | pf = cgxlmac_to_pf(rvu, cgx_get_cgxid(cgxd), lmac_id); |
| 2967 | domain = 2; | 2968 | domain = 2; |
| 2968 | 2969 | ||
| @@ -3009,17 +3010,13 @@ RVU_DEBUG_SEQ_FOPS(cgx_dmac_flt, cgx_dmac_flt_display, NULL); · 40 unmodified lines | |||
| 3009 | 3010 | ||
| 3010 | static int cgx_print_fwdata(struct seq_file *s, int lmac_id) | 3011 | static int cgx_print_fwdata(struct seq_file *s, int lmac_id) |
| 3011 | { | 3012 | { |
| 3013 | struct rvu_cgx_lmac_dbgfs_ctx *dctx = s->private; | ||
| 3012 | struct cgx_lmac_fwdata_s *fwdata; | 3014 | struct cgx_lmac_fwdata_s *fwdata; |
| 3013 | void *cgxd = s->private; | 3015 | struct rvu *rvu = dctx->rvu; |
| 3016 | void *cgxd = dctx->cgxd; | ||
| 3014 | struct phy_s *phy; | 3017 | struct phy_s *phy; |
| 3015 | struct rvu *rvu; | ||
| 3016 | int cgx_id, i; | 3018 | int cgx_id, i; |
| 3017 | 3019 | ||
| 3018 | rvu = pci_get_drvdata(pci_get_device(PCI_VENDOR_ID_CAVIUM, | ||
| 3019 | PCI_DEVID_OCTEONTX2_RVU_AF, NULL)); | ||
| 3020 | if (!rvu) | ||
| 3021 | return -ENODEV; | ||
| 3022 | |||
| 3023 | if (!rvu->fwdata) | 3020 | if (!rvu->fwdata) |
| 3024 | return -EAGAIN; | 3021 | return -EAGAIN; |
| 3025 | 3022 | ||
| @@ -3100,6 +3097,7 @@ RVU_DEBUG_SEQ_FOPS(cgx_fwdata, cgx_fwdata_display, NULL); · 74 unmodified lines | |||
| 3100 | 3097 | ||
| 3101 | static void rvu_dbg_cgx_init(struct rvu *rvu) | 3098 | static void rvu_dbg_cgx_init(struct rvu *rvu) |
| 3102 | { | 3099 | { |
| 3100 | struct rvu_cgx_lmac_dbgfs_ctx *ctx; | ||
| 3103 | struct mac_ops *mac_ops; | 3101 | struct mac_ops *mac_ops; |
| 3104 | unsigned long lmac_bmap; | 3102 | unsigned long lmac_bmap; |
| 3105 | int i, lmac_id; | 3103 | int i, lmac_id; |
| @@ -3126,6 +3124,13 @@ static void rvu_dbg_cgx_init(struct rvu *rvu) · 20 unmodified lines | |||
| 3126 | rvu->rvu_dbg.cgx = debugfs_create_dir(dname, | 3124 | rvu->rvu_dbg.cgx = debugfs_create_dir(dname, |
| 3127 | rvu->rvu_dbg.cgx_root); | 3125 | rvu->rvu_dbg.cgx_root); |
| 3128 | 3126 | ||
| 3127 | ctx = devm_kzalloc(rvu->dev, sizeof(*ctx), GFP_KERNEL); | ||
| 3128 | if (!ctx) | ||
| 3129 | continue; | ||
| 3130 | |||
| 3131 | ctx->rvu = rvu; | ||
| 3132 | ctx->cgxd = cgx; | ||
| 3133 | |||
| 3129 | for_each_set_bit(lmac_id, &lmac_bmap, rvu->hw->lmac_per_cgx) { | 3134 | for_each_set_bit(lmac_id, &lmac_bmap, rvu->hw->lmac_per_cgx) { |
| 3130 | /* lmac debugfs dir */ | 3135 | /* lmac debugfs dir */ |
| 3131 | sprintf(dname, "lmac%d", lmac_id); | 3136 | sprintf(dname, "lmac%d", lmac_id); |
| @@ -3133,13 +3138,13 @@ static void rvu_dbg_cgx_init(struct rvu *rvu) · 1 unmodified line | |||
| 3133 | debugfs_create_dir(dname, rvu->rvu_dbg.cgx); | 3138 | debugfs_create_dir(dname, rvu->rvu_dbg.cgx); |
| 3134 | 3139 | ||
| 3135 | debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac, | 3140 | debugfs_create_file_aux_num("stats", 0600, rvu->rvu_dbg.lmac, |
| 3136 | cgx, lmac_id, &rvu_dbg_cgx_stat_fops); | 3141 | ctx, lmac_id, &rvu_dbg_cgx_stat_fops); |
| 3137 | debugfs_create_file_aux_num("mac_filter", 0600, | 3142 | debugfs_create_file_aux_num("mac_filter", 0600, |
| 3138 | rvu->rvu_dbg.lmac, cgx, lmac_id, | 3143 | rvu->rvu_dbg.lmac, ctx, lmac_id, |
| 3139 | &rvu_dbg_cgx_dmac_flt_fops); | 3144 | &rvu_dbg_cgx_dmac_flt_fops); |
| 3140 | debugfs_create_file("fwdata", 0600, | 3145 | debugfs_create_file_aux_num("fwdata", 0600, |
| 3141 | rvu->rvu_dbg.lmac, cgx, | 3146 | rvu->rvu_dbg.lmac, ctx, |
| 3142 | &rvu_dbg_cgx_fwdata_fops); | 3147 | lmac_id, &rvu_dbg_cgx_fwdata_fops); |
| 3143 | } | 3148 | } |
| 3144 | } | 3149 | } |
| 3145 | } | 3150 | } |
| @@ -1511,7 +1511,9 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id, · 1510 unmodified lines | |||
| 1511 | struct rvu_devlink *rvu_dl = devlink_priv(devlink); | 1511 | struct rvu_devlink *rvu_dl = devlink_priv(devlink); |
| 1512 | struct rvu *rvu = rvu_dl->rvu; | 1512 | struct rvu *rvu = rvu_dl->rvu; |
| 1513 | u16 max_nix0_lf, max_nix1_lf; | 1513 | u16 max_nix0_lf, max_nix1_lf; |
| 1514 | struct npc_mcam *mcam; | 1514 | struct rvu_block *block; |
| 1515 | int blkaddr = 0; | ||
| 1516 | int free_lfs; | ||
| 1515 | u64 cfg; | 1517 | u64 cfg; |
| 1516 | 1518 | ||
| 1517 | cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2); | 1519 | cfg = rvu_read64(rvu, BLKADDR_NIX0, NIX_AF_CONST2); |
| @@ -1519,14 +1521,23 @@ static int rvu_af_dl_nix_maxlf_validate(struct devlink *devlink, u32 id, · 1 unmodified line | |||
| 1519 | cfg = rvu_read64(rvu, BLKADDR_NIX1, NIX_AF_CONST2); | 1521 | cfg = rvu_read64(rvu, BLKADDR_NIX1, NIX_AF_CONST2); |
| 1520 | max_nix1_lf = cfg & 0xFFF; | 1522 | max_nix1_lf = cfg & 0xFFF; |
| 1521 | 1523 | ||
| 1522 | /* Do not allow user to modify maximum NIX LFs while mcam entries | 1524 | /* Do not allow user to modify maximum NIX LFs while NIX LFs |
| 1523 | * have already been assigned. | 1525 | * have already been assigned. Note that modifying NIX LFs count |
| 1526 | * can be done only before any LF attach requests from PFs and VFs | ||
| 1527 | * and not later or concurrently. | ||
| 1524 | */ | 1528 | */ |
| 1525 | mcam = &rvu->hw->mcam; | 1529 | blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr); |
| 1526 | if (mcam->bmap_fcnt < mcam->bmap_entries) { | 1530 | while (blkaddr) { |
| 1527 | NL_SET_ERR_MSG_MOD(extack, | 1531 | block = &rvu->hw->block[blkaddr]; |
| 1528 | "mcam entries have already been assigned, can't resize"); | 1532 | |
| 1529 | return -EPERM; | 1533 | free_lfs = rvu_rsrc_free_count(&block->lf); |
| 1534 | if (free_lfs != block->lf.max) { | ||
| 1535 | NL_SET_ERR_MSG_MOD(extack, | ||
| 1536 | "NIX LFs already assigned, can't resize"); | ||
| 1537 | return -EPERM; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | blkaddr = rvu_get_next_nix_blkaddr(rvu, blkaddr); | ||
| 1530 | } | 1541 | } |
| 1531 | 1542 | ||
| 1532 | if (max_nix0_lf && val->vu16 > max_nix0_lf) { | 1543 | if (max_nix0_lf && val->vu16 > max_nix0_lf) { |
| @@ -528,19 +528,24 @@ static int nix_setup_bpids(struct rvu *rvu, struct nix_hw *hw, int blkaddr) · 527 unmodified lines | |||
| 528 | bp->fn_map = devm_kcalloc(rvu->dev, bp->bpids.max, | 528 | bp->fn_map = devm_kcalloc(rvu->dev, bp->bpids.max, |
| 529 | sizeof(u16), GFP_KERNEL); | 529 | sizeof(u16), GFP_KERNEL); |
| 530 | if (!bp->fn_map) | 530 | if (!bp->fn_map) |
| 531 | return -ENOMEM; | 531 | goto free_bpids; |
| 532 | 532 | ||
| 533 | bp->intf_map = devm_kcalloc(rvu->dev, bp->bpids.max, | 533 | bp->intf_map = devm_kcalloc(rvu->dev, bp->bpids.max, |
| 534 | sizeof(u8), GFP_KERNEL); | 534 | sizeof(u8), GFP_KERNEL); |
| 535 | if (!bp->intf_map) | 535 | if (!bp->intf_map) |
| 536 | return -ENOMEM; | 536 | goto free_bpids; |
| 537 | 537 | ||
| 538 | bp->ref_cnt = devm_kcalloc(rvu->dev, bp->bpids.max, | 538 | bp->ref_cnt = devm_kcalloc(rvu->dev, bp->bpids.max, |
| 539 | sizeof(u8), GFP_KERNEL); | 539 | sizeof(u8), GFP_KERNEL); |
| 540 | if (!bp->ref_cnt) | 540 | if (!bp->ref_cnt) |
| 541 | return -ENOMEM; | 541 | goto free_bpids; |
| 542 | 542 | ||
| 543 | return 0; | 543 | return 0; |
| 544 | |||
| 545 | free_bpids: | ||
| 546 | rvu_free_bitmap(&bp->bpids); | ||
| 547 | bp->bpids.bmap = NULL; | ||
| 548 | return -ENOMEM; | ||
| 544 | } | 549 | } |
| 545 | 550 | ||
| 546 | void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc) | 551 | void rvu_nix_flr_free_bpids(struct rvu *rvu, u16 pcifunc) |
| @@ -2225,7 +2225,7 @@ int npc_install_mcam_drop_rule(struct rvu *rvu, int mcam_idx, u16 *counter_idx, · 2224 unmodified lines | |||
| 2225 | return err; | 2225 | return err; |
| 2226 | } | 2226 | } |
| 2227 | 2227 | ||
| 2228 | dev_err(rvu->dev, | 2228 | dev_dbg(rvu->dev, |
| 2229 | "%s: Installed single drop on non hit rule at %d, cntr=%d\n", | 2229 | "%s: Installed single drop on non hit rule at %d, cntr=%d\n", |
| 2230 | __func__, mcam_idx, req.cntr); | 2230 | __func__, mcam_idx, req.cntr); |
| 2231 | 2231 | ||
| @@ -182,6 +182,7 @@ static void cn10k_mcs_free_rsrc(struct otx2_nic *pfvf, enum mcs_direction dir, · 181 unmodified lines | |||
| 182 | clear_req->id = hw_rsrc_id; | 182 | clear_req->id = hw_rsrc_id; |
| 183 | clear_req->type = type; | 183 | clear_req->type = type; |
| 184 | clear_req->dir = dir; | 184 | clear_req->dir = dir; |
| 185 | clear_req->all = all; | ||
| 185 | 186 | ||
| 186 | req = otx2_mbox_alloc_msg_mcs_free_resources(mbox); | 187 | req = otx2_mbox_alloc_msg_mcs_free_resources(mbox); |
| 187 | if (!req) | 188 | if (!req) |
| @@ -1776,11 +1777,16 @@ fail: · 1588 unmodified lines | |||
| 1776 | 1777 | ||
| 1777 | void cn10k_mcs_free(struct otx2_nic *pfvf) | 1778 | void cn10k_mcs_free(struct otx2_nic *pfvf) |
| 1778 | { | 1779 | { |
| 1780 | struct cn10k_mcs_cfg *cfg = pfvf->macsec_cfg; | ||
| 1781 | |||
| 1779 | if (!test_bit(CN10K_HW_MACSEC, &pfvf->hw.cap_flag)) | 1782 | if (!test_bit(CN10K_HW_MACSEC, &pfvf->hw.cap_flag)) |
| 1780 | return; | 1783 | return; |
| 1781 | 1784 | ||
| 1782 | cn10k_mcs_free_rsrc(pfvf, MCS_TX, MCS_RSRC_TYPE_SECY, 0, true); | 1785 | if (!list_empty(&cfg->txsc_list)) { |
| 1783 | cn10k_mcs_free_rsrc(pfvf, MCS_RX, MCS_RSRC_TYPE_SECY, 0, true); | 1786 | cn10k_mcs_free_rsrc(pfvf, MCS_TX, MCS_RSRC_TYPE_SECY, 0, true); |
| 1787 | cn10k_mcs_free_rsrc(pfvf, MCS_RX, MCS_RSRC_TYPE_SECY, 0, true); | ||
| 1788 | } | ||
| 1789 | |||
| 1784 | kfree(pfvf->macsec_cfg); | 1790 | kfree(pfvf->macsec_cfg); |
| 1785 | pfvf->macsec_cfg = NULL; | 1791 | pfvf->macsec_cfg = NULL; |
| 1786 | } | 1792 | } |
| @@ -1575,6 +1575,7 @@ static void otx2_free_sq_res(struct otx2_nic *pf) · 1574 unmodified lines | |||
| 1575 | qmem_free(pf->dev, sq->sqe_ring); | 1575 | qmem_free(pf->dev, sq->sqe_ring); |
| 1576 | qmem_free(pf->dev, sq->cpt_resp); | 1576 | qmem_free(pf->dev, sq->cpt_resp); |
| 1577 | qmem_free(pf->dev, sq->tso_hdrs); | 1577 | qmem_free(pf->dev, sq->tso_hdrs); |
| 1578 | qmem_free(pf->dev, sq->timestamps); | ||
| 1578 | kfree(sq->sg); | 1579 | kfree(sq->sg); |
| 1579 | kfree(sq->sqb_ptrs); | 1580 | kfree(sq->sqb_ptrs); |
| 1580 | } | 1581 | } |
| @@ -373,7 +373,7 @@ static int prestera_port_sfp_bind(struct prestera_port *port) · 372 unmodified lines | |||
| 373 | struct device_node *ports, *node; | 373 | struct device_node *ports, *node; |
| 374 | struct fwnode_handle *fwnode; | 374 | struct fwnode_handle *fwnode; |
| 375 | struct phylink *phy_link; | 375 | struct phylink *phy_link; |
| 376 | int err; | 376 | int err = 0; |
| 377 | 377 | ||
| 378 | if (!sw->np) | 378 | if (!sw->np) |
| 379 | return 0; | 379 | return 0; |
| @@ -4960,6 +4960,11 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) · 4959 unmodified lines | |||
| 4960 | if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) | 4960 | if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) |
| 4961 | mac_ops = &rt5350_phylink_ops; | 4961 | mac_ops = &rt5350_phylink_ops; |
| 4962 | 4962 | ||
| 4963 | if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && | ||
| 4964 | id == MTK_GMAC2_ID) | ||
| 4965 | __set_bit(PHY_INTERFACE_MODE_INTERNAL, | ||
| 4966 | mac->phylink_config.supported_interfaces); | ||
| 4967 | |||
| 4963 | phylink = phylink_create(&mac->phylink_config, | 4968 | phylink = phylink_create(&mac->phylink_config, |
| 4964 | of_fwnode_handle(mac->of_node), | 4969 | of_fwnode_handle(mac->of_node), |
| 4965 | phy_mode, mac_ops); | 4970 | phy_mode, mac_ops); |
| @@ -4970,11 +4975,6 @@ static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) · 4 unmodified lines | |||
| 4970 | 4975 | ||
| 4971 | mac->phylink = phylink; | 4976 | mac->phylink = phylink; |
| 4972 | 4977 | ||
| 4973 | if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_2P5GPHY) && | ||
| 4974 | id == MTK_GMAC2_ID) | ||
| 4975 | __set_bit(PHY_INTERFACE_MODE_INTERNAL, | ||
| 4976 | mac->phylink_config.supported_interfaces); | ||
| 4977 | |||
| 4978 | SET_NETDEV_DEV(eth->netdev[id], eth->dev); | 4978 | SET_NETDEV_DEV(eth->netdev[id], eth->dev); |
| 4979 | eth->netdev[id]->watchdog_timeo = 5 * HZ; | 4979 | eth->netdev[id]->watchdog_timeo = 5 * HZ; |
| 4980 | eth->netdev[id]->netdev_ops = &mtk_netdev_ops; | 4980 | eth->netdev[id]->netdev_ops = &mtk_netdev_ops; |
| @@ -918,7 +918,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) · 917 unmodified lines | |||
| 918 | mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), | 918 | mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib), |
| 919 | &ppe->mib_phys, GFP_KERNEL); | 919 | &ppe->mib_phys, GFP_KERNEL); |
| 920 | if (!mib) | 920 | if (!mib) |
| 921 | return NULL; | 921 | goto err_free_l2_flows; |
| 922 | 922 | ||
| 923 | ppe->mib_table = mib; | 923 | ppe->mib_table = mib; |
| 924 | 924 | ||
| @@ -926,7 +926,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int index) · 1 unmodified line | |||
| 926 | GFP_KERNEL); | 926 | GFP_KERNEL); |
| 927 | 927 | ||
| 928 | if (!acct) | 928 | if (!acct) |
| 929 | return NULL; | 929 | goto err_free_l2_flows; |
| 930 | 930 | ||
| 931 | ppe->acct_table = acct; | 931 | ppe->acct_table = acct; |
| 932 | } | 932 | } |
| @@ -143,7 +143,7 @@ config MLX5_CORE_IPOIB · 142 unmodified lines | |||
| 143 | config MLX5_MACSEC | 143 | config MLX5_MACSEC |
| 144 | bool "Connect-X support for MACSec offload" | 144 | bool "Connect-X support for MACSec offload" |
| 145 | depends on MLX5_CORE_EN | 145 | depends on MLX5_CORE_EN |
| 146 | depends on MACSEC | 146 | depends on MACSEC=y || MACSEC=MLX5_CORE |
| 147 | default n | 147 | default n |
| 148 | help | 148 | help |
| 149 | Build support for MACsec cryptography-offload acceleration in the NIC. | 149 | Build support for MACsec cryptography-offload acceleration in the NIC. |
| @@ -2721,7 +2721,8 @@ const struct ethtool_ops mlx5e_ethtool_ops = { · 2720 unmodified lines | |||
| 2721 | .rxfh_max_num_contexts = MLX5E_MAX_NUM_RSS, | 2721 | .rxfh_max_num_contexts = MLX5E_MAX_NUM_RSS, |
| 2722 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 2722 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 2723 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | | 2723 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 2724 | ETHTOOL_OP_NEEDS_RTNL_SPFLAGS, | 2724 | ETHTOOL_OP_NEEDS_RTNL_SPFLAGS | |
| 2725 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 2725 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | | 2726 | .supported_coalesce_params = ETHTOOL_COALESCE_USECS | |
| 2726 | ETHTOOL_COALESCE_MAX_FRAMES | | 2727 | ETHTOOL_COALESCE_MAX_FRAMES | |
| 2727 | ETHTOOL_COALESCE_USE_ADAPTIVE | | 2728 | ETHTOOL_COALESCE_USE_ADAPTIVE | |
| @@ -419,7 +419,8 @@ static const struct ethtool_ops mlx5e_rep_ethtool_ops = { · 418 unmodified lines | |||
| 419 | ETHTOOL_COALESCE_MAX_FRAMES | | 419 | ETHTOOL_COALESCE_MAX_FRAMES | |
| 420 | ETHTOOL_COALESCE_USE_ADAPTIVE, | 420 | ETHTOOL_COALESCE_USE_ADAPTIVE, |
| 421 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 421 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 422 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM, | 422 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 423 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 423 | .get_drvinfo = mlx5e_rep_get_drvinfo, | 424 | .get_drvinfo = mlx5e_rep_get_drvinfo, |
| 424 | .get_link = ethtool_op_get_link, | 425 | .get_link = ethtool_op_get_link, |
| 425 | .get_strings = mlx5e_rep_get_strings, | 426 | .get_strings = mlx5e_rep_get_strings, |
| @@ -286,7 +286,8 @@ const struct ethtool_ops mlx5i_ethtool_ops = { · 285 unmodified lines | |||
| 286 | ETHTOOL_COALESCE_MAX_FRAMES | | 286 | ETHTOOL_COALESCE_MAX_FRAMES | |
| 287 | ETHTOOL_COALESCE_USE_ADAPTIVE, | 287 | ETHTOOL_COALESCE_USE_ADAPTIVE, |
| 288 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 288 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 289 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM, | 289 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 290 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 290 | .get_drvinfo = mlx5i_get_drvinfo, | 291 | .get_drvinfo = mlx5i_get_drvinfo, |
| 291 | .get_strings = mlx5i_get_strings, | 292 | .get_strings = mlx5i_get_strings, |
| 292 | .get_sset_count = mlx5i_get_sset_count, | 293 | .get_sset_count = mlx5i_get_sset_count, |
| @@ -309,6 +310,7 @@ const struct ethtool_ops mlx5i_ethtool_ops = { · 16 unmodified lines | |||
| 309 | }; | 310 | }; |
| 310 | 311 | ||
| 311 | const struct ethtool_ops mlx5i_pkey_ethtool_ops = { | 312 | const struct ethtool_ops mlx5i_pkey_ethtool_ops = { |
| 313 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 312 | .get_drvinfo = mlx5i_get_drvinfo, | 314 | .get_drvinfo = mlx5i_get_drvinfo, |
| 313 | .get_link = ethtool_op_get_link, | 315 | .get_link = ethtool_op_get_link, |
| 314 | .get_ts_info = mlx5i_get_ts_info, | 316 | .get_ts_info = mlx5i_get_ts_info, |
| @@ -297,7 +297,6 @@ void mlx5_core_reps_aux_devs_remove(struct mlx5_core_dev *dev); · 296 unmodified lines | |||
| 297 | void mlx5_fw_reporters_create(struct mlx5_core_dev *dev); | 297 | void mlx5_fw_reporters_create(struct mlx5_core_dev *dev); |
| 298 | int mlx5_query_mtpps(struct mlx5_core_dev *dev, u32 *mtpps, u32 mtpps_size); | 298 | int mlx5_query_mtpps(struct mlx5_core_dev *dev, u32 *mtpps, u32 mtpps_size); |
| 299 | int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size); | 299 | int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size); |
| 300 | int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode); | ||
| 301 | int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode); | 300 | int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode); |
| 302 | 301 | ||
| 303 | struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev); | 302 | struct mlx5_dm *mlx5_dm_create(struct mlx5_core_dev *dev); |
| @@ -908,25 +908,6 @@ int mlx5_set_mtpps(struct mlx5_core_dev *mdev, u32 *mtpps, u32 mtpps_size) · 907 unmodified lines | |||
| 908 | sizeof(out), MLX5_REG_MTPPS, 0, 1); | 908 | sizeof(out), MLX5_REG_MTPPS, 0, 1); |
| 909 | } | 909 | } |
| 910 | 910 | ||
| 911 | int mlx5_query_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 *arm, u8 *mode) | ||
| 912 | { | ||
| 913 | u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; | ||
| 914 | u32 in[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; | ||
| 915 | int err = 0; | ||
| 916 | |||
| 917 | MLX5_SET(mtppse_reg, in, pin, pin); | ||
| 918 | |||
| 919 | err = mlx5_core_access_reg(mdev, in, sizeof(in), out, | ||
| 920 | sizeof(out), MLX5_REG_MTPPSE, 0, 0); | ||
| 921 | if (err) | ||
| 922 | return err; | ||
| 923 | |||
| 924 | *arm = MLX5_GET(mtppse_reg, in, event_arm); | ||
| 925 | *mode = MLX5_GET(mtppse_reg, in, event_generation_mode); | ||
| 926 | |||
| 927 | return err; | ||
| 928 | } | ||
| 929 | |||
| 930 | int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode) | 911 | int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode) |
| 931 | { | 912 | { |
| 932 | u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; | 913 | u32 out[MLX5_ST_SZ_DW(mtppse_reg)] = {0}; |
| @@ -2024,7 +2024,8 @@ static const struct ethtool_ops fbnic_ethtool_ops = { · 2023 unmodified lines | |||
| 2024 | ETHTOOL_OP_NEEDS_RTNL_GPAUSEPARAM | | 2024 | ETHTOOL_OP_NEEDS_RTNL_GPAUSEPARAM | |
| 2025 | ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM | | 2025 | ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM | |
| 2026 | ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 2026 | ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 2027 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM, | 2027 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 2028 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 2028 | .get_drvinfo = fbnic_get_drvinfo, | 2029 | .get_drvinfo = fbnic_get_drvinfo, |
| 2029 | .get_regs_len = fbnic_get_regs_len, | 2030 | .get_regs_len = fbnic_get_regs_len, |
| 2030 | .get_regs = fbnic_get_regs, | 2031 | .get_regs = fbnic_get_regs, |
| @@ -526,15 +526,10 @@ int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership) · 525 unmodified lines | |||
| 526 | goto free_message; | 526 | goto free_message; |
| 527 | } | 527 | } |
| 528 | 528 | ||
| 529 | err = fbnic_mbx_map_tlv_msg(fbd, msg); | ||
| 530 | if (err) | ||
| 531 | goto free_message; | ||
| 532 | |||
| 533 | /* Initialize heartbeat, set last response to 1 second in the past | 529 | /* Initialize heartbeat, set last response to 1 second in the past |
| 534 | * so that we will trigger a timeout if the firmware doesn't respond | 530 | * so that we will trigger a timeout if the firmware doesn't respond |
| 535 | */ | 531 | */ |
| 536 | fbd->last_heartbeat_response = req_time - HZ; | 532 | fbd->last_heartbeat_response = req_time - HZ; |
| 537 | |||
| 538 | fbd->last_heartbeat_request = req_time; | 533 | fbd->last_heartbeat_request = req_time; |
| 539 | 534 | ||
| 540 | /* Set prev_firmware_time to 0 to avoid triggering firmware crash | 535 | /* Set prev_firmware_time to 0 to avoid triggering firmware crash |
| @@ -542,6 +537,10 @@ int fbnic_fw_xmit_ownership_msg(struct fbnic_dev *fbd, bool take_ownership) · 1 unmodified line | |||
| 542 | */ | 537 | */ |
| 543 | fbd->prev_firmware_time = 0; | 538 | fbd->prev_firmware_time = 0; |
| 544 | 539 | ||
| 540 | err = fbnic_mbx_map_tlv_msg(fbd, msg); | ||
| 541 | if (err) | ||
| 542 | goto free_message; | ||
| 543 | |||
| 545 | /* Set heartbeat detection based on if we are taking ownership */ | 544 | /* Set heartbeat detection based on if we are taking ownership */ |
| 546 | fbd->fw_heartbeat_enabled = take_ownership; | 545 | fbd->fw_heartbeat_enabled = take_ownership; |
| 547 | 546 | ||
| @@ -264,8 +264,11 @@ static int fbnic_set_mac(struct net_device *netdev, void *p) · 263 unmodified lines | |||
| 264 | 264 | ||
| 265 | eth_hw_addr_set(netdev, addr->sa_data); | 265 | eth_hw_addr_set(netdev, addr->sa_data); |
| 266 | 266 | ||
| 267 | if (netif_running(netdev)) | 267 | if (netif_running(netdev)) { |
| 268 | netif_addr_lock_bh(netdev); | ||
| 268 | __fbnic_set_rx_mode(fbn->fbd, &netdev->uc, &netdev->mc); | 269 | __fbnic_set_rx_mode(fbn->fbd, &netdev->uc, &netdev->mc); |
| 270 | netif_addr_unlock_bh(netdev); | ||
| 271 | } | ||
| 269 | 272 | ||
| 270 | return 0; | 273 | return 0; |
| 271 | } | 274 | } |
| @@ -310,8 +313,10 @@ void fbnic_clear_rx_mode(struct fbnic_dev *fbd) · 38 unmodified lines | |||
| 310 | /* Write updates to hardware */ | 313 | /* Write updates to hardware */ |
| 311 | fbnic_write_macda(fbd); | 314 | fbnic_write_macda(fbd); |
| 312 | 315 | ||
| 316 | netif_addr_lock_bh(netdev); | ||
| 313 | __dev_uc_unsync(netdev, NULL); | 317 | __dev_uc_unsync(netdev, NULL); |
| 314 | __dev_mc_unsync(netdev, NULL); | 318 | __dev_mc_unsync(netdev, NULL); |
| 319 | netif_addr_unlock_bh(netdev); | ||
| 315 | } | 320 | } |
| 316 | 321 | ||
| 317 | static int fbnic_hwtstamp_get(struct net_device *netdev, | 322 | static int fbnic_hwtstamp_get(struct net_device *netdev, |
| @@ -135,7 +135,9 @@ void fbnic_up(struct fbnic_net *fbn) · 134 unmodified lines | |||
| 135 | 135 | ||
| 136 | fbnic_rss_reinit_hw(fbn->fbd, fbn); | 136 | fbnic_rss_reinit_hw(fbn->fbd, fbn); |
| 137 | 137 | ||
| 138 | netif_addr_lock_bh(fbn->netdev); | ||
| 138 | __fbnic_set_rx_mode(fbn->fbd, &fbn->netdev->uc, &fbn->netdev->mc); | 139 | __fbnic_set_rx_mode(fbn->fbd, &fbn->netdev->uc, &fbn->netdev->mc); |
| 140 | netif_addr_unlock_bh(fbn->netdev); | ||
| 139 | 141 | ||
| 140 | /* Enable Tx/Rx processing */ | 142 | /* Enable Tx/Rx processing */ |
| 141 | fbnic_napi_enable(fbn); | 143 | fbnic_napi_enable(fbn); |
| @@ -180,7 +182,9 @@ static int fbnic_fw_config_after_crash(struct fbnic_dev *fbd) · 38 unmodified lines | |||
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | fbnic_rpc_reset_valid_entries(fbd); | 184 | fbnic_rpc_reset_valid_entries(fbd); |
| 185 | netif_addr_lock_bh(fbd->netdev); | ||
| 183 | __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); | 186 | __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); |
| 187 | netif_addr_unlock_bh(fbd->netdev); | ||
| 184 | 188 | ||
| 185 | return 0; | 189 | return 0; |
| 186 | } | 190 | } |
| @@ -244,7 +244,9 @@ void fbnic_bmc_rpc_check(struct fbnic_dev *fbd) · 243 unmodified lines | |||
| 244 | 244 | ||
| 245 | if (fbd->fw_cap.need_bmc_tcam_reinit) { | 245 | if (fbd->fw_cap.need_bmc_tcam_reinit) { |
| 246 | fbnic_bmc_rpc_init(fbd); | 246 | fbnic_bmc_rpc_init(fbd); |
| 247 | netif_addr_lock_bh(fbd->netdev); | ||
| 247 | __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); | 248 | __fbnic_set_rx_mode(fbd, &fbd->netdev->uc, &fbd->netdev->mc); |
| 249 | netif_addr_unlock_bh(fbd->netdev); | ||
| 248 | fbd->fw_cap.need_bmc_tcam_reinit = false; | 250 | fbd->fw_cap.need_bmc_tcam_reinit = false; |
| 249 | } | 251 | } |
| 250 | 252 | ||
| @@ -765,11 +765,13 @@ int sparx5_register_notifier_blocks(struct sparx5 *s5) · 764 unmodified lines | |||
| 765 | sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0); | 765 | sparx5_owq = alloc_ordered_workqueue("sparx5_order", 0); |
| 766 | if (!sparx5_owq) { | 766 | if (!sparx5_owq) { |
| 767 | err = -ENOMEM; | 767 | err = -ENOMEM; |
| 768 | goto err_switchdev_blocking_nb; | 768 | goto err_alloc_workqueue; |
| 769 | } | 769 | } |
| 770 | 770 | ||
| 771 | return 0; | 771 | return 0; |
| 772 | 772 | ||
| 773 | err_alloc_workqueue: | ||
| 774 | unregister_switchdev_blocking_notifier(&s5->switchdev_blocking_nb); | ||
| 773 | err_switchdev_blocking_nb: | 775 | err_switchdev_blocking_nb: |
| 774 | unregister_switchdev_notifier(&s5->switchdev_nb); | 776 | unregister_switchdev_notifier(&s5->switchdev_nb); |
| 775 | err_switchdev_nb: | 777 | err_switchdev_nb: |
| @@ -210,6 +210,8 @@ static int mana_gd_query_max_resources(struct pci_dev *pdev) · 209 unmodified lines | |||
| 210 | } else { | 210 | } else { |
| 211 | /* If dynamic allocation is enabled we have already allocated | 211 | /* If dynamic allocation is enabled we have already allocated |
| 212 | * hwc msi | 212 | * hwc msi |
| 213 | * Also, we make sure in this case the following is always true | ||
| 214 | * (num_msix_usable - 1 HWC) <= num_online_cpus() | ||
| 213 | */ | 215 | */ |
| 214 | gc->num_msix_usable = min(resp.max_msix, num_online_cpus() + 1); | 216 | gc->num_msix_usable = min(resp.max_msix, num_online_cpus() + 1); |
| 215 | } | 217 | } |
| @@ -1909,8 +1911,8 @@ void mana_gd_free_res_map(struct gdma_resource *r) · 1693 unmodified lines | |||
| 1909 | * do the same thing. | 1911 | * do the same thing. |
| 1910 | */ | 1912 | */ |
| 1911 | 1913 | ||
| 1912 | static int irq_setup(unsigned int *irqs, unsigned int len, int node, | 1914 | static int mana_irq_setup_numa_aware(unsigned int *irqs, unsigned int len, |
| 1913 | bool skip_first_cpu) | 1915 | int node, bool skip_first_cpu) |
| 1914 | { | 1916 | { |
| 1915 | const struct cpumask *next, *prev = cpu_none_mask; | 1917 | const struct cpumask *next, *prev = cpu_none_mask; |
| 1916 | cpumask_var_t cpus __free(free_cpumask_var); | 1918 | cpumask_var_t cpus __free(free_cpumask_var); |
| @@ -1946,11 +1948,24 @@ done: · 29 unmodified lines | |||
| 1946 | return 0; | 1948 | return 0; |
| 1947 | } | 1949 | } |
| 1948 | 1950 | ||
| 1951 | /* must be called with cpus_read_lock() held */ | ||
| 1952 | static void mana_irq_setup_linear(unsigned int *irqs, unsigned int len) | ||
| 1953 | { | ||
| 1954 | int cpu; | ||
| 1955 | |||
| 1956 | for_each_online_cpu(cpu) { | ||
| 1957 | if (len == 0) | ||
| 1958 | break; | ||
| 1959 | |||
| 1960 | irq_set_affinity_and_hint(*irqs++, cpumask_of(cpu)); | ||
| 1961 | len--; | ||
| 1962 | } | ||
| 1963 | } | ||
| 1964 | |||
| 1949 | static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) | 1965 | static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) |
| 1950 | { | 1966 | { |
| 1951 | struct gdma_context *gc = pci_get_drvdata(pdev); | 1967 | struct gdma_context *gc = pci_get_drvdata(pdev); |
| 1952 | struct gdma_irq_context *gic; | 1968 | struct gdma_irq_context *gic; |
| 1953 | bool skip_first_cpu = false; | ||
| 1954 | int *irqs, err, i, msi; | 1969 | int *irqs, err, i, msi; |
| 1955 | 1970 | ||
| 1956 | irqs = kmalloc_objs(int, nvec); | 1971 | irqs = kmalloc_objs(int, nvec); |
| @@ -1958,10 +1973,12 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) · 1 unmodified line | |||
| 1958 | return -ENOMEM; | 1973 | return -ENOMEM; |
| 1959 | 1974 | ||
| 1960 | /* | 1975 | /* |
| 1976 | * In this function, num_msix_usable = HWC IRQ + Queue IRQ. | ||
| 1977 | * nvec is only Queue IRQ (HWC already setup). | ||
| 1961 | * While processing the next pci irq vector, we start with index 1, | 1978 | * While processing the next pci irq vector, we start with index 1, |
| 1962 | * as IRQ vector at index 0 is already processed for HWC. | 1979 | * as IRQ vector at index 0 is already processed for HWC. |
| 1963 | * However, the population of irqs array starts with index 0, to be | 1980 | * However, the population of irqs array starts with index 0, to be |
| 1964 | * further used in irq_setup() | 1981 | * further used in mana_irq_setup_numa_aware() |
| 1965 | */ | 1982 | */ |
| 1966 | for (i = 1; i <= nvec; i++) { | 1983 | for (i = 1; i <= nvec; i++) { |
| 1967 | msi = i; | 1984 | msi = i; |
| @@ -1975,18 +1992,51 @@ static int mana_gd_setup_dyn_irqs(struct pci_dev *pdev, int nvec) · 7 unmodified lines | |||
| 1975 | } | 1992 | } |
| 1976 | 1993 | ||
| 1977 | /* | 1994 | /* |
| 1978 | * When calling irq_setup() for dynamically added IRQs, if number of | 1995 | * When calling mana_irq_setup_numa_aware() for dynamically added IRQs, |
| 1979 | * CPUs is more than or equal to allocated MSI-X, we need to skip the | 1996 | * if number of CPUs is more than or equal to allocated MSI-X, we need to |
| 1980 | * first CPU sibling group since they are already affinitized to HWC IRQ | 1997 | * skip the first CPU sibling group since they are already affinitized to |
| 1998 | * HWC IRQ | ||
| 1981 | */ | 1999 | */ |
| 1982 | cpus_read_lock(); | 2000 | cpus_read_lock(); |
| 1983 | if (gc->num_msix_usable <= num_online_cpus()) | 2001 | if (gc->num_msix_usable <= num_online_cpus()) { |
| 1984 | skip_first_cpu = true; | 2002 | err = mana_irq_setup_numa_aware(irqs, nvec, gc->numa_node, |
| 2003 | true); | ||
| 2004 | if (err) { | ||
| 2005 | cpus_read_unlock(); | ||
| 2006 | goto free_irq; | ||
| 2007 | } | ||
| 2008 | } else { | ||
| 2009 | /* | ||
| 2010 | * When num_msix_usable are more than num_online_cpus, our | ||
| 2011 | * queue IRQs should be equal to num of online vCPUs. | ||
| 2012 | * We try to make sure queue IRQs spread across all vCPUs. | ||
| 2013 | * In such a case NUMA or CPU core affinity does not matter. | ||
| 2014 | * Note: in this case the total mana IRQ should always be | ||
| 2015 | * num_online_cpus + 1. The first HWC IRQ is already handled | ||
| 2016 | * in HWC setup calls | ||
| 2017 | * However, if CPUs went offline since num_msix_usable was | ||
| 2018 | * computed, queue IRQs will be more than num_online_cpus(). | ||
| 2019 | * In such cases remaining extra IRQs will retain their default | ||
| 2020 | * affinity. | ||
| 2021 | */ | ||
| 2022 | int first_unassigned = num_online_cpus(); | ||
| 1985 | 2023 | ||
| 1986 | err = irq_setup(irqs, nvec, gc->numa_node, skip_first_cpu); | 2024 | if (nvec > first_unassigned) { |
| 1987 | if (err) { | 2025 | char buf[32]; |
| 1988 | cpus_read_unlock(); | 2026 | |
| 1989 | goto free_irq; | 2027 | if (first_unassigned == nvec - 1) |
| 2028 | snprintf(buf, sizeof(buf), "%d", | ||
| 2029 | first_unassigned); | ||
| 2030 | else | ||
| 2031 | snprintf(buf, sizeof(buf), "%d-%d", | ||
| 2032 | first_unassigned, nvec - 1); | ||
| 2033 | |||
| 2034 | dev_dbg(&pdev->dev, | ||
| 2035 | "MANA IRQ indices #%s will retain the default CPU affinity\n", | ||
| 2036 | buf); | ||
| 2037 | } | ||
| 2038 | |||
| 2039 | mana_irq_setup_linear(irqs, nvec); | ||
| 1990 | } | 2040 | } |
| 1991 | 2041 | ||
| 1992 | cpus_read_unlock(); | 2042 | cpus_read_unlock(); |
| @@ -2041,7 +2091,7 @@ static int mana_gd_setup_irqs(struct pci_dev *pdev, int nvec) · 48 unmodified lines | |||
| 2041 | nvec -= 1; | 2091 | nvec -= 1; |
| 2042 | } | 2092 | } |
| 2043 | 2093 | ||
| 2044 | err = irq_setup(irqs, nvec, gc->numa_node, false); | 2094 | err = mana_irq_setup_numa_aware(irqs, nvec, gc->numa_node, false); |
| 2045 | if (err) { | 2095 | if (err) { |
| 2046 | cpus_read_unlock(); | 2096 | cpus_read_unlock(); |
| 2047 | goto free_irq; | 2097 | goto free_irq; |
| @@ -237,7 +237,8 @@ static int mana_xdp_set(struct net_device *ndev, struct bpf_prog *prog, · 236 unmodified lines | |||
| 237 | bpf_prog_put(old_prog); | 237 | bpf_prog_put(old_prog); |
| 238 | 238 | ||
| 239 | if (prog) | 239 | if (prog) |
| 240 | ndev->max_mtu = MANA_XDP_MTU_MAX; | 240 | ndev->max_mtu = min_t(unsigned int, MANA_XDP_MTU_MAX, |
| 241 | gc->adapter_mtu - ETH_HLEN); | ||
| 241 | else | 242 | else |
| 242 | ndev->max_mtu = gc->adapter_mtu - ETH_HLEN; | 243 | ndev->max_mtu = gc->adapter_mtu - ETH_HLEN; |
| 243 | 244 | ||
| @@ -1233,12 +1233,24 @@ int mana_gd_query_device_cfg(struct gdma_context *gc, u32 proto_major_ver, · 1232 unmodified lines | |||
| 1233 | *max_num_vports = resp.max_num_vports; | 1233 | *max_num_vports = resp.max_num_vports; |
| 1234 | 1234 | ||
| 1235 | if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) { | 1235 | if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) { |
| 1236 | if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { | 1236 | if (resp.adapter_mtu == 0) { |
| 1237 | /* | ||
| 1238 | * Some older PF firmware versions report an | ||
| 1239 | * adapter_mtu of 0. MANA hardware always supports the | ||
| 1240 | * standard Ethernet MTU, so fall back to ETH_FRAME_LEN. | ||
| 1241 | * Jumbo frames will not be available in this case. | ||
| 1242 | */ | ||
| 1243 | dev_info(dev, | ||
| 1244 | "PF reported adapter_mtu of 0, falling back to %u (jumbo frames disabled)\n", | ||
| 1245 | ETH_FRAME_LEN); | ||
| 1246 | gc->adapter_mtu = ETH_FRAME_LEN; | ||
| 1247 | } else if (resp.adapter_mtu < ETH_MIN_MTU + ETH_HLEN) { | ||
| 1237 | dev_err(dev, "Adapter MTU too small: %u\n", | 1248 | dev_err(dev, "Adapter MTU too small: %u\n", |
| 1238 | resp.adapter_mtu); | 1249 | resp.adapter_mtu); |
| 1239 | return -EPROTO; | 1250 | return -EPROTO; |
| 1251 | } else { | ||
| 1252 | gc->adapter_mtu = resp.adapter_mtu; | ||
| 1240 | } | 1253 | } |
| 1241 | gc->adapter_mtu = resp.adapter_mtu; | ||
| 1242 | } else { | 1254 | } else { |
| 1243 | gc->adapter_mtu = ETH_FRAME_LEN; | 1255 | gc->adapter_mtu = ETH_FRAME_LEN; |
| 1244 | } | 1256 | } |
| @@ -597,7 +597,8 @@ static int mana_get_link_ksettings(struct net_device *ndev, · 596 unmodified lines | |||
| 597 | const struct ethtool_ops mana_ethtool_ops = { | 597 | const struct ethtool_ops mana_ethtool_ops = { |
| 598 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES, | 598 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_CQE_FRAMES, |
| 599 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | | 599 | .op_needs_rtnl = ETHTOOL_OP_NEEDS_RTNL_SCHANNELS | |
| 600 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM, | 600 | ETHTOOL_OP_NEEDS_RTNL_SRINGPARAM | |
| 601 | ETHTOOL_OP_NEEDS_RTNL_GLINK, | ||
| 601 | .get_ethtool_stats = mana_get_ethtool_stats, | 602 | .get_ethtool_stats = mana_get_ethtool_stats, |
| 602 | .get_sset_count = mana_get_sset_count, | 603 | .get_sset_count = mana_get_sset_count, |
| 603 | .get_strings = mana_get_strings, | 604 | .get_strings = mana_get_strings, |
| @@ -1420,13 +1420,25 @@ pch_gbe_alloc_rx_buffers_pool(struct pch_gbe_adapter *adapter, · 1419 unmodified lines | |||
| 1420 | return 0; | 1420 | return 0; |
| 1421 | } | 1421 | } |
| 1422 | 1422 | ||
| 1423 | static void pch_gbe_free_rx_buffers_pool(struct pch_gbe_adapter *adapter, | ||
| 1424 | struct pch_gbe_rx_ring *rx_ring) | ||
| 1425 | { | ||
| 1426 | dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size, | ||
| 1427 | rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic); | ||
| 1428 | rx_ring->rx_buff_pool_logic = 0; | ||
| 1429 | rx_ring->rx_buff_pool_size = 0; | ||
| 1430 | rx_ring->rx_buff_pool = NULL; | ||
| 1431 | } | ||
| 1432 | |||
| 1423 | /** | 1433 | /** |
| 1424 | * pch_gbe_alloc_tx_buffers - Allocate transmit buffers | 1434 | * pch_gbe_alloc_tx_buffers - Allocate transmit buffers |
| 1425 | * @adapter: Board private structure | 1435 | * @adapter: Board private structure |
| 1426 | * @tx_ring: Tx descriptor ring | 1436 | * @tx_ring: Tx descriptor ring |
| 1437 | * | ||
| 1438 | * Return: 0 on success, -ENOMEM if a TX skb allocation fails. | ||
| 1427 | */ | 1439 | */ |
| 1428 | static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter, | 1440 | static int pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter, |
| 1429 | struct pch_gbe_tx_ring *tx_ring) | 1441 | struct pch_gbe_tx_ring *tx_ring) |
| 1430 | { | 1442 | { |
| 1431 | struct pch_gbe_buffer *buffer_info; | 1443 | struct pch_gbe_buffer *buffer_info; |
| 1432 | struct sk_buff *skb; | 1444 | struct sk_buff *skb; |
| @@ -1440,12 +1452,17 @@ static void pch_gbe_alloc_tx_buffers(struct pch_gbe_adapter *adapter, · 7 unmodified lines | |||
| 1440 | for (i = 0; i < tx_ring->count; i++) { | 1452 | for (i = 0; i < tx_ring->count; i++) { |
| 1441 | buffer_info = &tx_ring->buffer_info[i]; | 1453 | buffer_info = &tx_ring->buffer_info[i]; |
| 1442 | skb = netdev_alloc_skb(adapter->netdev, bufsz); | 1454 | skb = netdev_alloc_skb(adapter->netdev, bufsz); |
| 1455 | if (!skb) { | ||
| 1456 | pch_gbe_clean_tx_ring(adapter, tx_ring); | ||
| 1457 | return -ENOMEM; | ||
| 1458 | } | ||
| 1443 | skb_reserve(skb, PCH_GBE_DMA_ALIGN); | 1459 | skb_reserve(skb, PCH_GBE_DMA_ALIGN); |
| 1444 | buffer_info->skb = skb; | 1460 | buffer_info->skb = skb; |
| 1445 | tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); | 1461 | tx_desc = PCH_GBE_TX_DESC(*tx_ring, i); |
| 1446 | tx_desc->gbec_status = (DSC_INIT16); | 1462 | tx_desc->gbec_status = (DSC_INIT16); |
| 1447 | } | 1463 | } |
| 1448 | return; | 1464 | |
| 1465 | return 0; | ||
| 1449 | } | 1466 | } |
| 1450 | 1467 | ||
| 1451 | /** | 1468 | /** |
| @@ -1887,7 +1904,12 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) · 435 unmodified lines | |||
| 1887 | "Error: can't bring device up - alloc rx buffers pool failed\n"); | 1904 | "Error: can't bring device up - alloc rx buffers pool failed\n"); |
| 1888 | goto freeirq; | 1905 | goto freeirq; |
| 1889 | } | 1906 | } |
| 1890 | pch_gbe_alloc_tx_buffers(adapter, tx_ring); | 1907 | err = pch_gbe_alloc_tx_buffers(adapter, tx_ring); |
| 1908 | if (err) { | ||
| 1909 | netdev_err(netdev, | ||
| 1910 | "Error: can't bring device up - alloc tx buffers failed\n"); | ||
| 1911 | goto freebuf; | ||
| 1912 | } | ||
| 1891 | pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count); | 1913 | pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count); |
| 1892 | adapter->tx_queue_len = netdev->tx_queue_len; | 1914 | adapter->tx_queue_len = netdev->tx_queue_len; |
| 1893 | pch_gbe_enable_dma_rx(&adapter->hw); | 1915 | pch_gbe_enable_dma_rx(&adapter->hw); |
| @@ -1901,6 +1923,8 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter) · 7 unmodified lines | |||
| 1901 | 1923 | ||
| 1902 | return 0; | 1924 | return 0; |
| 1903 | 1925 | ||
| 1926 | freebuf: | ||
| 1927 | pch_gbe_free_rx_buffers_pool(adapter, rx_ring); | ||
| 1904 | freeirq: | 1928 | freeirq: |
| 1905 | pch_gbe_free_irq(adapter); | 1929 | pch_gbe_free_irq(adapter); |
| 1906 | out: | 1930 | out: |
| @@ -1936,11 +1960,7 @@ void pch_gbe_down(struct pch_gbe_adapter *adapter) · 29 unmodified lines | |||
| 1936 | pch_gbe_clean_tx_ring(adapter, adapter->tx_ring); | 1960 | pch_gbe_clean_tx_ring(adapter, adapter->tx_ring); |
| 1937 | pch_gbe_clean_rx_ring(adapter, adapter->rx_ring); | 1961 | pch_gbe_clean_rx_ring(adapter, adapter->rx_ring); |
| 1938 | 1962 | ||
| 1939 | dma_free_coherent(&adapter->pdev->dev, rx_ring->rx_buff_pool_size, | 1963 | pch_gbe_free_rx_buffers_pool(adapter, rx_ring); |
| 1940 | rx_ring->rx_buff_pool, rx_ring->rx_buff_pool_logic); | ||
| 1941 | rx_ring->rx_buff_pool_logic = 0; | ||
| 1942 | rx_ring->rx_buff_pool_size = 0; | ||
| 1943 | rx_ring->rx_buff_pool = NULL; | ||
| 1944 | } | 1964 | } |
| 1945 | 1965 | ||
| 1946 | /** | 1966 | /** |
| @@ -1924,6 +1924,9 @@ static int ofdpa_port_fdb(struct ofdpa_port *ofdpa_port, · 1923 unmodified lines | |||
| 1924 | flags |= OFDPA_OP_FLAG_REFRESH; | 1924 | flags |= OFDPA_OP_FLAG_REFRESH; |
| 1925 | } | 1925 | } |
| 1926 | 1926 | ||
| 1927 | if (found && removing) | ||
| 1928 | kfree(found); | ||
| 1929 | |||
| 1927 | return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id); | 1930 | return ofdpa_port_fdb_learn(ofdpa_port, flags, addr, vlan_id); |
| 1928 | } | 1931 | } |
| 1929 | 1932 | ||
| @@ -18,10 +18,12 @@ · 17 unmodified lines | |||
| 18 | #include "stmmac_platform.h" | 18 | #include "stmmac_platform.h" |
| 19 | 19 | ||
| 20 | /* ctrl register bits */ | 20 | /* ctrl register bits */ |
| 21 | #define CTRL_PHY_INTF_RGMII BIT(3) | 21 | #define CTRL_PHY_INTF_MODE GENMASK(4, 3) |
| 22 | #define CTRL_PHY_INTF_MII BIT(4) | 22 | #define CTRL_PHY_INTF_RMII FIELD_PREP(CTRL_PHY_INTF_MODE, 0) |
| 23 | #define CTRL_WAKE_IRQ_EN BIT(9) | 23 | #define CTRL_PHY_INTF_RGMII FIELD_PREP(CTRL_PHY_INTF_MODE, 1) |
| 24 | #define CTRL_PHY_IRQ_EN BIT(12) | 24 | #define CTRL_PHY_INTF_MII FIELD_PREP(CTRL_PHY_INTF_MODE, 3) |
| 25 | #define CTRL_LPI_IRQ_EN BIT(9) | ||
| 26 | #define CTRL_WAKE_IRQ_EN BIT(12) | ||
| 25 | 27 | ||
| 26 | /* dline register bits */ | 28 | /* dline register bits */ |
| 27 | #define RGMII_RX_DLINE_EN BIT(0) | 29 | #define RGMII_RX_DLINE_EN BIT(0) |
| @@ -118,7 +120,7 @@ static void spacemit_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, · 90 unmodified lines | |||
| 118 | 120 | ||
| 119 | static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) | 121 | static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) |
| 120 | { | 122 | { |
| 121 | unsigned int mask = CTRL_PHY_INTF_MII | CTRL_PHY_INTF_RGMII; | 123 | unsigned int mask = CTRL_PHY_INTF_MODE; |
| 122 | struct spacmit_dwmac *dwmac = bsp_priv; | 124 | struct spacmit_dwmac *dwmac = bsp_priv; |
| 123 | unsigned int val = 0; | 125 | unsigned int val = 0; |
| 124 | 126 | ||
| @@ -128,6 +130,7 @@ static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) · 3 unmodified lines | |||
| 128 | break; | 130 | break; |
| 129 | 131 | ||
| 130 | case PHY_INTF_SEL_RMII: | 132 | case PHY_INTF_SEL_RMII: |
| 133 | val = CTRL_PHY_INTF_RMII; | ||
| 131 | break; | 134 | break; |
| 132 | 135 | ||
| 133 | case PHY_INTF_SEL_RGMII: | 136 | case PHY_INTF_SEL_RGMII: |
| @@ -2978,10 +2978,10 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 2977 unmodified lines | |||
| 2978 | dev->max_mtu = GEM_MAX_MTU; | 2978 | dev->max_mtu = GEM_MAX_MTU; |
| 2979 | 2979 | ||
| 2980 | /* Register with kernel */ | 2980 | /* Register with kernel */ |
| 2981 | if (register_netdev(dev)) { | 2981 | err = register_netdev(dev); |
| 2982 | if (err) { | ||
| 2982 | pr_err("Cannot register net device, aborting\n"); | 2983 | pr_err("Cannot register net device, aborting\n"); |
| 2983 | err = -ENOMEM; | 2984 | goto err_out_clear_drvdata; |
| 2984 | goto err_out_free_consistent; | ||
| 2985 | } | 2985 | } |
| 2986 | 2986 | ||
| 2987 | /* Undo the get_cell with appropriate locking (we could use | 2987 | /* Undo the get_cell with appropriate locking (we could use |
| @@ -2995,8 +2995,13 @@ static int gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) · 7 unmodified lines | |||
| 2995 | dev->dev_addr); | 2995 | dev->dev_addr); |
| 2996 | return 0; | 2996 | return 0; |
| 2997 | 2997 | ||
| 2998 | err_out_clear_drvdata: | ||
| 2999 | pci_set_drvdata(pdev, NULL); | ||
| 3000 | netif_napi_del(&gp->napi); | ||
| 3001 | |||
| 2998 | err_out_free_consistent: | 3002 | err_out_free_consistent: |
| 2999 | gem_remove_one(pdev); | 3003 | dma_free_coherent(&pdev->dev, sizeof(struct gem_init_block), |
| 3004 | gp->init_block, gp->gblock_dvma); | ||
| 3000 | err_out_iounmap: | 3005 | err_out_iounmap: |
| 3001 | gem_put_cell(gp); | 3006 | gem_put_cell(gp); |
| 3002 | iounmap(gp->regs); | 3007 | iounmap(gp->regs); |
| @@ -79,12 +79,14 @@ int spl2sw_phy_connect(struct spl2sw_common *comm) · 78 unmodified lines | |||
| 79 | void spl2sw_phy_remove(struct spl2sw_common *comm) | 79 | void spl2sw_phy_remove(struct spl2sw_common *comm) |
| 80 | { | 80 | { |
| 81 | struct net_device *ndev; | 81 | struct net_device *ndev; |
| 82 | struct spl2sw_mac *mac; | ||
| 82 | int i; | 83 | int i; |
| 83 | 84 | ||
| 84 | for (i = 0; i < MAX_NETDEV_NUM; i++) | 85 | for (i = 0; i < MAX_NETDEV_NUM; i++) |
| 85 | if (comm->ndev[i]) { | 86 | if (comm->ndev[i]) { |
| 86 | ndev = comm->ndev[i]; | 87 | ndev = comm->ndev[i]; |
| 87 | if (ndev) | 88 | mac = netdev_priv(ndev); |
| 88 | phy_disconnect(ndev->phydev); | 89 | phy_disconnect(ndev->phydev); |
| 90 | of_node_put(mac->phy_node); | ||
| 89 | } | 91 | } |
| 90 | } | 92 | } |
| @@ -93,8 +93,8 @@ void prueth_ndev_del_tx_napi(struct prueth_emac *emac, int num) · 92 unmodified lines | |||
| 93 | } | 93 | } |
| 94 | EXPORT_SYMBOL_GPL(prueth_ndev_del_tx_napi); | 94 | EXPORT_SYMBOL_GPL(prueth_ndev_del_tx_napi); |
| 95 | 95 | ||
| 96 | static int emac_xsk_xmit_zc(struct prueth_emac *emac, | 96 | static void emac_xsk_xmit_zc(struct prueth_emac *emac, |
| 97 | unsigned int q_idx) | 97 | unsigned int q_idx) |
| 98 | { | 98 | { |
| 99 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[q_idx]; | 99 | struct prueth_tx_chn *tx_chn = &emac->tx_chns[q_idx]; |
| 100 | struct xsk_buff_pool *pool = tx_chn->xsk_pool; | 100 | struct xsk_buff_pool *pool = tx_chn->xsk_pool; |
| @@ -115,7 +115,7 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, · 14 unmodified lines | |||
| 115 | * necessary | 115 | * necessary |
| 116 | */ | 116 | */ |
| 117 | if (descs_avail <= MAX_SKB_FRAGS) | 117 | if (descs_avail <= MAX_SKB_FRAGS) |
| 118 | return 0; | 118 | return; |
| 119 | 119 | ||
| 120 | descs_avail -= MAX_SKB_FRAGS; | 120 | descs_avail -= MAX_SKB_FRAGS; |
| 121 | 121 | ||
| @@ -170,8 +170,8 @@ static int emac_xsk_xmit_zc(struct prueth_emac *emac, · 48 unmodified lines | |||
| 170 | num_tx++; | 170 | num_tx++; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | xsk_tx_release(tx_chn->xsk_pool); | 173 | if (num_tx) |
| 174 | return num_tx; | 174 | xsk_tx_release(tx_chn->xsk_pool); |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | void prueth_xmit_free(struct prueth_tx_chn *tx_chn, | 177 | void prueth_xmit_free(struct prueth_tx_chn *tx_chn, |
| @@ -279,9 +279,6 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn, · 101 unmodified lines | |||
| 279 | num_tx++; | 279 | num_tx++; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | if (!num_tx) | ||
| 283 | return 0; | ||
| 284 | |||
| 285 | netif_txq = netdev_get_tx_queue(ndev, chn); | 282 | netif_txq = netdev_get_tx_queue(ndev, chn); |
| 286 | netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); | 283 | netdev_tx_completed_queue(netif_txq, num_tx, total_bytes); |
| 287 | 284 | ||
| @@ -297,16 +294,18 @@ int emac_tx_complete_packets(struct prueth_emac *emac, int chn, · 9 unmodified lines | |||
| 297 | __netif_tx_unlock(netif_txq); | 294 | __netif_tx_unlock(netif_txq); |
| 298 | } | 295 | } |
| 299 | 296 | ||
| 300 | if (tx_chn->xsk_pool) { | 297 | if (budget && tx_chn->xsk_pool) { |
| 301 | if (xsk_frames_done) | 298 | if (xsk_frames_done) { |
| 302 | xsk_tx_completed(tx_chn->xsk_pool, xsk_frames_done); | 299 | xsk_tx_completed(tx_chn->xsk_pool, xsk_frames_done); |
| 300 | txq_trans_cond_update(netif_txq); | ||
| 301 | } | ||
| 303 | 302 | ||
| 304 | if (xsk_uses_need_wakeup(tx_chn->xsk_pool)) | 303 | if (xsk_uses_need_wakeup(tx_chn->xsk_pool)) |
| 305 | xsk_set_tx_need_wakeup(tx_chn->xsk_pool); | 304 | xsk_set_tx_need_wakeup(tx_chn->xsk_pool); |
| 306 | 305 | ||
| 307 | netif_txq = netdev_get_tx_queue(ndev, chn); | 306 | __netif_tx_lock(netif_txq, smp_processor_id()); |
| 308 | txq_trans_cond_update(netif_txq); | ||
| 309 | emac_xsk_xmit_zc(emac, chn); | 307 | emac_xsk_xmit_zc(emac, chn); |
| 308 | __netif_tx_unlock(netif_txq); | ||
| 310 | } | 309 | } |
| 311 | 310 | ||
| 312 | return num_tx; | 311 | return num_tx; |
| @@ -1652,28 +1651,35 @@ void icssg_ndo_get_stats64(struct net_device *ndev, · 1339 unmodified lines | |||
| 1652 | stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); | 1651 | stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors"); |
| 1653 | stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); | 1652 | stats->multicast = emac_get_stat_by_name(emac, "rx_multicast_frames"); |
| 1654 | 1653 | ||
| 1655 | stats->rx_errors = ndev->stats.rx_errors + | 1654 | stats->rx_errors = ndev->stats.rx_errors; |
| 1656 | emac_get_stat_by_name(emac, "FW_RX_ERROR") + | 1655 | stats->rx_dropped = ndev->stats.rx_dropped; |
| 1657 | emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") + | ||
| 1658 | emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") + | ||
| 1659 | emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") + | ||
| 1660 | emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN"); | ||
| 1661 | stats->rx_dropped = ndev->stats.rx_dropped + | ||
| 1662 | emac_get_stat_by_name(emac, "FW_DROPPED_PKT") + | ||
| 1663 | emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") + | ||
| 1664 | emac_get_stat_by_name(emac, "FW_INF_SAV") + | ||
| 1665 | emac_get_stat_by_name(emac, "FW_INF_SA_DL") + | ||
| 1666 | emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") + | ||
| 1667 | emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") + | ||
| 1668 | emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") + | ||
| 1669 | emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") + | ||
| 1670 | emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER"); | ||
| 1671 | stats->tx_errors = ndev->stats.tx_errors; | 1656 | stats->tx_errors = ndev->stats.tx_errors; |
| 1672 | stats->tx_dropped = ndev->stats.tx_dropped + | 1657 | stats->tx_dropped = ndev->stats.tx_dropped; |
| 1673 | emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") + | 1658 | |
| 1674 | emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") + | 1659 | if (!emac->prueth->pa_stats) |
| 1675 | emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") + | 1660 | return; |
| 1676 | emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF"); | 1661 | |
| 1662 | stats->rx_errors += | ||
| 1663 | emac_get_stat_by_name(emac, "FW_RX_ERROR") + | ||
| 1664 | emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") + | ||
| 1665 | emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") + | ||
| 1666 | emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") + | ||
| 1667 | emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN"); | ||
| 1668 | stats->rx_dropped += | ||
| 1669 | emac_get_stat_by_name(emac, "FW_DROPPED_PKT") + | ||
| 1670 | emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") + | ||
| 1671 | emac_get_stat_by_name(emac, "FW_INF_SAV") + | ||
| 1672 | emac_get_stat_by_name(emac, "FW_INF_SA_DL") + | ||
| 1673 | emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") + | ||
| 1674 | emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") + | ||
| 1675 | emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") + | ||
| 1676 | emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") + | ||
| 1677 | emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER"); | ||
| 1678 | stats->tx_dropped += | ||
| 1679 | emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") + | ||
| 1680 | emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") + | ||
| 1681 | emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") + | ||
| 1682 | emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF"); | ||
| 1677 | } | 1683 | } |
| 1678 | EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64); | 1684 | EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64); |
| 1679 | 1685 | ||
| @@ -715,7 +715,6 @@ static int ngbe_probe(struct pci_dev *pdev, · 714 unmodified lines | |||
| 715 | netdev->features |= NETIF_F_GRO; | 715 | netdev->features |= NETIF_F_GRO; |
| 716 | 716 | ||
| 717 | netdev->priv_flags |= IFF_UNICAST_FLT; | 717 | netdev->priv_flags |= IFF_UNICAST_FLT; |
| 718 | netdev->priv_flags |= IFF_SUPP_NOFCS; | ||
| 719 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; | 718 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
| 720 | 719 | ||
| 721 | netdev->min_mtu = ETH_MIN_MTU; | 720 | netdev->min_mtu = ETH_MIN_MTU; |
| @@ -796,7 +796,6 @@ static int txgbe_probe(struct pci_dev *pdev, · 795 unmodified lines | |||
| 796 | netdev->features |= NETIF_F_RX_UDP_TUNNEL_PORT; | 796 | netdev->features |= NETIF_F_RX_UDP_TUNNEL_PORT; |
| 797 | 797 | ||
| 798 | netdev->priv_flags |= IFF_UNICAST_FLT; | 798 | netdev->priv_flags |= IFF_UNICAST_FLT; |
| 799 | netdev->priv_flags |= IFF_SUPP_NOFCS; | ||
| 800 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; | 799 | netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
| 801 | 800 | ||
| 802 | netdev->min_mtu = ETH_MIN_MTU; | 801 | netdev->min_mtu = ETH_MIN_MTU; |
| @@ -954,13 +954,27 @@ static int geneve_gro_complete(struct sock *sk, struct sk_buff *skb, · 953 unmodified lines | |||
| 954 | struct genevehdr *gh; | 954 | struct genevehdr *gh; |
| 955 | struct packet_offload *ptype; | 955 | struct packet_offload *ptype; |
| 956 | __be16 type; | 956 | __be16 type; |
| 957 | int gh_len; | 957 | unsigned int gh_len; |
| 958 | int err = -ENOSYS; | 958 | int err = -ENOSYS; |
| 959 | 959 | ||
| 960 | gh = (struct genevehdr *)(skb->data + nhoff); | 960 | gh = (struct genevehdr *)(skb->data + nhoff); |
| 961 | gh_len = geneve_hlen(gh); | 961 | gh_len = geneve_hlen(gh); |
| 962 | type = gh->proto_type; | 962 | type = gh->proto_type; |
| 963 | geneve_opt_gro_hint_off(gh, &type, &gh_len); | 963 | geneve_sk_gro_hint_off(sk, gh, &type, &gh_len); |
| 964 | |||
| 965 | /* Bail out if we are about to dispatch past the inner network header | ||
| 966 | * gro_receive() validated. An inner VLAN tag only pushes | ||
| 967 | * inner_network_offset out, so use a lower bound. | ||
| 968 | */ | ||
| 969 | if (skb->encapsulation) { | ||
| 970 | unsigned int inner_nh = nhoff + gh_len; | ||
| 971 | |||
| 972 | if (type == htons(ETH_P_TEB)) | ||
| 973 | inner_nh += ETH_HLEN; | ||
| 974 | |||
| 975 | if (unlikely(inner_nh > NAPI_GRO_CB(skb)->inner_network_offset)) | ||
| 976 | return -EINVAL; | ||
| 977 | } | ||
| 964 | 978 | ||
| 965 | /* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */ | 979 | /* since skb->encapsulation is set, eth_gro_complete() sets the inner mac header */ |
| 966 | if (likely(type == htons(ETH_P_TEB))) | 980 | if (likely(type == htons(ETH_P_TEB))) |
| @@ -595,7 +595,7 @@ static int ca8210_test_int_driver_write( · 594 unmodified lines | |||
| 595 | fifo_buffer = kmemdup(buf, len, GFP_KERNEL); | 595 | fifo_buffer = kmemdup(buf, len, GFP_KERNEL); |
| 596 | if (!fifo_buffer) | 596 | if (!fifo_buffer) |
| 597 | return -ENOMEM; | 597 | return -ENOMEM; |
| 598 | kfifo_in(&test->up_fifo, &fifo_buffer, 4); | 598 | kfifo_in(&test->up_fifo, &fifo_buffer, sizeof(fifo_buffer)); |
| 599 | wake_up_interruptible(&priv->test.readq); | 599 | wake_up_interruptible(&priv->test.readq); |
| 600 | 600 | ||
| 601 | return 0; | 601 | return 0; |
| @@ -919,9 +919,10 @@ static int ca8210_spi_transfer( · 317 unmodified lines | |||
| 919 | if (status < 0) { | 919 | if (status < 0) { |
| 920 | dev_crit( | 920 | dev_crit( |
| 921 | &spi->dev, | 921 | &spi->dev, |
| 922 | "status %d from spi_sync in write\n", | 922 | "status %d from spi_async in write\n", |
| 923 | status | 923 | status |
| 924 | ); | 924 | ); |
| 925 | kfree(cas_ctl); | ||
| 925 | } | 926 | } |
| 926 | 927 | ||
| 927 | return status; | 928 | return status; |
| @@ -2525,6 +2526,7 @@ static ssize_t ca8210_test_int_user_read( · 1597 unmodified lines | |||
| 2525 | struct ca8210_priv *priv = filp->private_data; | 2526 | struct ca8210_priv *priv = filp->private_data; |
| 2526 | unsigned char *fifo_buffer; | 2527 | unsigned char *fifo_buffer; |
| 2527 | unsigned long bytes_not_copied; | 2528 | unsigned long bytes_not_copied; |
| 2529 | unsigned int copied; | ||
| 2528 | 2530 | ||
| 2529 | if (filp->f_flags & O_NONBLOCK) { | 2531 | if (filp->f_flags & O_NONBLOCK) { |
| 2530 | /* Non-blocking mode */ | 2532 | /* Non-blocking mode */ |
| @@ -2538,7 +2540,8 @@ static ssize_t ca8210_test_int_user_read( · 7 unmodified lines | |||
| 2538 | ); | 2540 | ); |
| 2539 | } | 2541 | } |
| 2540 | 2542 | ||
| 2541 | if (kfifo_out(&priv->test.up_fifo, &fifo_buffer, 4) != 4) { | 2543 | copied = kfifo_out(&priv->test.up_fifo, &fifo_buffer, sizeof(fifo_buffer)); |
| 2544 | if (copied != sizeof(fifo_buffer)) { | ||
| 2542 | dev_err( | 2545 | dev_err( |
| 2543 | &priv->spi->dev, | 2546 | &priv->spi->dev, |
| 2544 | "test_interface: Wrong number of elements popped from upstream fifo\n" | 2547 | "test_interface: Wrong number of elements popped from upstream fifo\n" |
| @@ -190,8 +190,10 @@ struct netconsole_target { · 189 unmodified lines | |||
| 190 | bool extended; | 190 | bool extended; |
| 191 | bool release; | 191 | bool release; |
| 192 | struct netpoll np; | 192 | struct netpoll np; |
| 193 | /* protected by target_list_lock */ | 193 | /* protected by target_list_lock; +1 gives scnprintf() room for its |
| 194 | char buf[MAX_PRINT_CHUNK]; | 194 | * NUL terminator so a full MAX_PRINT_CHUNK payload is not truncated |
| 195 | */ | ||
| 196 | char buf[MAX_PRINT_CHUNK + 1]; | ||
| 195 | struct work_struct resume_wq; | 197 | struct work_struct resume_wq; |
| 196 | }; | 198 | }; |
| 197 | 199 | ||
| @@ -1938,7 +1940,7 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt, · 1740 unmodified lines | |||
| 1938 | if (release_len) { | 1940 | if (release_len) { |
| 1939 | release = init_utsname()->release; | 1941 | release = init_utsname()->release; |
| 1940 | 1942 | ||
| 1941 | scnprintf(nt->buf, MAX_PRINT_CHUNK, "%s,%.*s", release, | 1943 | scnprintf(nt->buf, sizeof(nt->buf), "%s,%.*s", release, |
| 1942 | msg_len, msg); | 1944 | msg_len, msg); |
| 1943 | msg_len += release_len; | 1945 | msg_len += release_len; |
| 1944 | } else { | 1946 | } else { |
| @@ -1947,12 +1949,12 @@ static void send_msg_no_fragmentation(struct netconsole_target *nt, · 2 unmodified lines | |||
| 1947 | 1949 | ||
| 1948 | if (userdata) | 1950 | if (userdata) |
| 1949 | msg_len += scnprintf(&nt->buf[msg_len], | 1951 | msg_len += scnprintf(&nt->buf[msg_len], |
| 1950 | MAX_PRINT_CHUNK - msg_len, "%s", | 1952 | sizeof(nt->buf) - msg_len, "%s", |
| 1951 | userdata); | 1953 | userdata); |
| 1952 | 1954 | ||
| 1953 | if (sysdata) | 1955 | if (sysdata) |
| 1954 | msg_len += scnprintf(&nt->buf[msg_len], | 1956 | msg_len += scnprintf(&nt->buf[msg_len], |
| 1955 | MAX_PRINT_CHUNK - msg_len, "%s", | 1957 | sizeof(nt->buf) - msg_len, "%s", |
| 1956 | sysdata); | 1958 | sysdata); |
| 1957 | 1959 | ||
| 1958 | send_udp(nt, nt->buf, msg_len); | 1960 | send_udp(nt, nt->buf, msg_len); |
| @@ -1802,7 +1802,8 @@ static int rtl822x_config_aneg(struct phy_device *phydev) · 1801 unmodified lines | |||
| 1802 | ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, | 1802 | ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, |
| 1803 | RTL_MDIO_AN_10GBT_CTRL, | 1803 | RTL_MDIO_AN_10GBT_CTRL, |
| 1804 | MDIO_AN_10GBT_CTRL_ADV2_5G | | 1804 | MDIO_AN_10GBT_CTRL_ADV2_5G | |
| 1805 | MDIO_AN_10GBT_CTRL_ADV5G, adv); | 1805 | MDIO_AN_10GBT_CTRL_ADV5G | |
| 1806 | MDIO_AN_10GBT_CTRL_ADV10G, adv); | ||
| 1806 | if (ret < 0) | 1807 | if (ret < 0) |
| 1807 | return ret; | 1808 | return ret; |
| 1808 | } | 1809 | } |
| @@ -200,7 +200,7 @@ static const struct pd692x0_msg pd692x0_msg_template_list[PD692X0_MSG_CNT] = { · 199 unmodified lines | |||
| 200 | }, | 200 | }, |
| 201 | [PD692X0_MSG_SET_USER_BYTE] = { | 201 | [PD692X0_MSG_SET_USER_BYTE] = { |
| 202 | .key = PD692X0_KEY_PRG, | 202 | .key = PD692X0_KEY_PRG, |
| 203 | .sub = {0x41, PD692X0_USER_BYTE}, | 203 | .sub = {0x41, PD692X0_USER_BYTE, 0x4e}, |
| 204 | .data = {0x4e, 0x4e, 0x4e, 0x4e, | 204 | .data = {0x4e, 0x4e, 0x4e, 0x4e, |
| 205 | 0x4e, 0x4e, 0x4e, 0x4e}, | 205 | 0x4e, 0x4e, 0x4e, 0x4e}, |
| 206 | }, | 206 | }, |
| @@ -783,8 +783,12 @@ static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf, · 782 unmodified lines | |||
| 783 | return true; | 783 | return true; |
| 784 | } | 784 | } |
| 785 | 785 | ||
| 786 | /* Start of packet, validate the frame header */ | 786 | /* Start of packet, validate the frame header. tbnet_poll() puts the |
| 787 | if (frame_count == 0 || frame_count > TBNET_RING_SIZE / 4) { | 787 | * first frame in the skb linear area and every further frame in a page |
| 788 | * fragment, so a packet may not span more than MAX_SKB_FRAGS + 1 frames | ||
| 789 | * without overflowing skb_shinfo()->frags[]. | ||
| 790 | */ | ||
| 791 | if (frame_count == 0 || frame_count > MAX_SKB_FRAGS + 1) { | ||
| 788 | net->stats.rx_length_errors++; | 792 | net->stats.rx_length_errors++; |
| 789 | return false; | 793 | return false; |
| 790 | } | 794 | } |
| @@ -276,6 +276,14 @@ kalmia_rx_fixup(struct usbnet *dev, struct sk_buff *skb) · 275 unmodified lines | |||
| 276 | "Received header: %6phC. Package length: %i\n", | 276 | "Received header: %6phC. Package length: %i\n", |
| 277 | header_start, skb->len - KALMIA_HEADER_LENGTH); | 277 | header_start, skb->len - KALMIA_HEADER_LENGTH); |
| 278 | 278 | ||
| 279 | /* both framing headers must be present before we subtract | ||
| 280 | * them, otherwise usb_packet_length underflows and the | ||
| 281 | * device-supplied ether_packet_length drives an out of bounds | ||
| 282 | * access below | ||
| 283 | */ | ||
| 284 | if (skb->len < 2 * KALMIA_HEADER_LENGTH) | ||
| 285 | return 0; | ||
| 286 | |||
| 279 | /* subtract start header and end header */ | 287 | /* subtract start header and end header */ |
| 280 | usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); | 288 | usb_packet_length = skb->len - (2 * KALMIA_HEADER_LENGTH); |
| 281 | ether_packet_length = get_unaligned_le16(&header_start[2]); | 289 | ether_packet_length = get_unaligned_le16(&header_start[2]); |
| @@ -1452,6 +1452,15 @@ static inline u32 lan78xx_hash(char addr[ETH_ALEN]) · 1451 unmodified lines | |||
| 1452 | return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; | 1452 | return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; |
| 1453 | } | 1453 | } |
| 1454 | 1454 | ||
| 1455 | static int lan78xx_write_mchash_table(struct lan78xx_net *dev) | ||
| 1456 | { | ||
| 1457 | struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); | ||
| 1458 | |||
| 1459 | return lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, | ||
| 1460 | DP_SEL_VHF_VLAN_LEN, | ||
| 1461 | DP_SEL_VHF_HASH_LEN, pdata->mchash_table); | ||
| 1462 | } | ||
| 1463 | |||
| 1455 | static void lan78xx_deferred_multicast_write(struct work_struct *param) | 1464 | static void lan78xx_deferred_multicast_write(struct work_struct *param) |
| 1456 | { | 1465 | { |
| 1457 | struct lan78xx_priv *pdata = | 1466 | struct lan78xx_priv *pdata = |
| @@ -1462,9 +1471,7 @@ static void lan78xx_deferred_multicast_write(struct work_struct *param) · 4 unmodified lines | |||
| 1462 | netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n", | 1471 | netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x\n", |
| 1463 | pdata->rfe_ctl); | 1472 | pdata->rfe_ctl); |
| 1464 | 1473 | ||
| 1465 | ret = lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, | 1474 | ret = lan78xx_write_mchash_table(dev); |
| 1466 | DP_SEL_VHF_VLAN_LEN, | ||
| 1467 | DP_SEL_VHF_HASH_LEN, pdata->mchash_table); | ||
| 1468 | if (ret < 0) | 1475 | if (ret < 0) |
| 1469 | goto multicast_write_done; | 1476 | goto multicast_write_done; |
| 1470 | 1477 | ||
| @@ -1557,6 +1564,7 @@ static void lan78xx_set_multicast(struct net_device *netdev) · 86 unmodified lines | |||
| 1557 | } | 1564 | } |
| 1558 | 1565 | ||
| 1559 | static void lan78xx_rx_urb_submit_all(struct lan78xx_net *dev); | 1566 | static void lan78xx_rx_urb_submit_all(struct lan78xx_net *dev); |
| 1567 | static int lan78xx_write_vlan_table(struct lan78xx_net *dev); | ||
| 1560 | 1568 | ||
| 1561 | static int lan78xx_mac_reset(struct lan78xx_net *dev) | 1569 | static int lan78xx_mac_reset(struct lan78xx_net *dev) |
| 1562 | { | 1570 | { |
| @@ -2514,6 +2522,17 @@ static void lan78xx_mac_link_up(struct phylink_config *config, · 951 unmodified lines | |||
| 2514 | if (ret < 0) | 2522 | if (ret < 0) |
| 2515 | goto link_up_fail; | 2523 | goto link_up_fail; |
| 2516 | 2524 | ||
| 2525 | /* The RFE clears the VLAN/DA hash filter (VHF) on a link down/up | ||
| 2526 | * cycle, so reprogram both tables from their shadow copies. | ||
| 2527 | */ | ||
| 2528 | ret = lan78xx_write_vlan_table(dev); | ||
| 2529 | if (ret < 0) | ||
| 2530 | goto link_up_fail; | ||
| 2531 | |||
| 2532 | ret = lan78xx_write_mchash_table(dev); | ||
| 2533 | if (ret < 0) | ||
| 2534 | goto link_up_fail; | ||
| 2535 | |||
| 2517 | netif_start_queue(net); | 2536 | netif_start_queue(net); |
| 2518 | 2537 | ||
| 2519 | return; | 2538 | return; |
| @@ -3065,14 +3084,20 @@ static int lan78xx_set_features(struct net_device *netdev, · 545 unmodified lines | |||
| 3065 | return lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); | 3084 | return lan78xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); |
| 3066 | } | 3085 | } |
| 3067 | 3086 | ||
| 3087 | static int lan78xx_write_vlan_table(struct lan78xx_net *dev) | ||
| 3088 | { | ||
| 3089 | struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); | ||
| 3090 | |||
| 3091 | return lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, 0, | ||
| 3092 | DP_SEL_VHF_VLAN_LEN, pdata->vlan_table); | ||
| 3093 | } | ||
| 3094 | |||
| 3068 | static void lan78xx_deferred_vlan_write(struct work_struct *param) | 3095 | static void lan78xx_deferred_vlan_write(struct work_struct *param) |
| 3069 | { | 3096 | { |
| 3070 | struct lan78xx_priv *pdata = | 3097 | struct lan78xx_priv *pdata = |
| 3071 | container_of(param, struct lan78xx_priv, set_vlan); | 3098 | container_of(param, struct lan78xx_priv, set_vlan); |
| 3072 | struct lan78xx_net *dev = pdata->dev; | ||
| 3073 | 3099 | ||
| 3074 | lan78xx_dataport_write(dev, DP_SEL_RSEL_VLAN_DA_, 0, | 3100 | lan78xx_write_vlan_table(pdata->dev); |
| 3075 | DP_SEL_VHF_VLAN_LEN, pdata->vlan_table); | ||
| 3076 | } | 3101 | } |
| 3077 | 3102 | ||
| 3078 | static int lan78xx_vlan_rx_add_vid(struct net_device *netdev, | 3103 | static int lan78xx_vlan_rx_add_vid(struct net_device *netdev, |
| @@ -1137,6 +1137,8 @@ static int veth_enable_xdp_range(struct net_device *dev, int start, int end, · 1136 unmodified lines | |||
| 1137 | err_reg_mem: | 1137 | err_reg_mem: |
| 1138 | xdp_rxq_info_unreg(&priv->rq[i].xdp_rxq); | 1138 | xdp_rxq_info_unreg(&priv->rq[i].xdp_rxq); |
| 1139 | err_rxq_reg: | 1139 | err_rxq_reg: |
| 1140 | if (!napi_already_on) | ||
| 1141 | netif_napi_del(&priv->rq[i].xdp_napi); | ||
| 1140 | for (i--; i >= start; i--) { | 1142 | for (i--; i >= start; i--) { |
| 1141 | struct veth_rq *rq = &priv->rq[i]; | 1143 | struct veth_rq *rq = &priv->rq[i]; |
| 1142 | 1144 | ||
| @@ -1999,15 +1999,18 @@ static struct sk_buff *receive_big(struct net_device *dev, · 1998 unmodified lines | |||
| 1999 | struct virtnet_rq_stats *stats) | 1999 | struct virtnet_rq_stats *stats) |
| 2000 | { | 2000 | { |
| 2001 | struct page *page = buf; | 2001 | struct page *page = buf; |
| 2002 | unsigned long max_len; | ||
| 2002 | struct sk_buff *skb; | 2003 | struct sk_buff *skb; |
| 2003 | 2004 | ||
| 2005 | max_len = (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE - | ||
| 2006 | sizeof(struct padded_vnet_hdr) + vi->hdr_len; | ||
| 2007 | |||
| 2004 | /* Make sure that len does not exceed the size allocated in | 2008 | /* Make sure that len does not exceed the size allocated in |
| 2005 | * add_recvbuf_big. | 2009 | * add_recvbuf_big. |
| 2006 | */ | 2010 | */ |
| 2007 | if (unlikely(len > (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE)) { | 2011 | if (unlikely(len > max_len)) { |
| 2008 | pr_debug("%s: rx error: len %u exceeds allocated size %lu\n", | 2012 | pr_debug("%s: rx error: len %u exceeds allocated size %lu\n", |
| 2009 | dev->name, len, | 2013 | dev->name, len, max_len); |
| 2010 | (vi->big_packets_num_skbfrags + 1) * PAGE_SIZE); | ||
| 2011 | goto err; | 2014 | goto err; |
| 2012 | } | 2015 | } |
| 2013 | 2016 | ||
| @@ -619,7 +619,6 @@ static void ppp_start(struct net_device *dev) · 618 unmodified lines | |||
| 619 | struct proto *proto = &ppp->protos[i]; | 619 | struct proto *proto = &ppp->protos[i]; |
| 620 | 620 | ||
| 621 | proto->dev = dev; | 621 | proto->dev = dev; |
| 622 | timer_setup(&proto->timer, ppp_timer, 0); | ||
| 623 | proto->state = CLOSED; | 622 | proto->state = CLOSED; |
| 624 | } | 623 | } |
| 625 | ppp->protos[IDX_LCP].pid = PID_LCP; | 624 | ppp->protos[IDX_LCP].pid = PID_LCP; |
| @@ -639,6 +638,15 @@ static void ppp_close(struct net_device *dev) · 13 unmodified lines | |||
| 639 | ppp_tx_flush(); | 638 | ppp_tx_flush(); |
| 640 | } | 639 | } |
| 641 | 640 | ||
| 641 | static void ppp_timer_release(struct net_device *dev) | ||
| 642 | { | ||
| 643 | struct ppp *ppp = get_ppp(dev); | ||
| 644 | int i; | ||
| 645 | |||
| 646 | for (i = 0; i < IDX_COUNT; i++) | ||
| 647 | timer_shutdown_sync(&ppp->protos[i].timer); | ||
| 648 | } | ||
| 649 | |||
| 642 | static struct hdlc_proto proto = { | 650 | static struct hdlc_proto proto = { |
| 643 | .start = ppp_start, | 651 | .start = ppp_start, |
| 644 | .stop = ppp_stop, | 652 | .stop = ppp_stop, |
| @@ -647,6 +655,7 @@ static struct hdlc_proto proto = { · 2 unmodified lines | |||
| 647 | .ioctl = ppp_ioctl, | 655 | .ioctl = ppp_ioctl, |
| 648 | .netif_rx = ppp_rx, | 656 | .netif_rx = ppp_rx, |
| 649 | .module = THIS_MODULE, | 657 | .module = THIS_MODULE, |
| 658 | .detach = ppp_timer_release, | ||
| 650 | }; | 659 | }; |
| 651 | 660 | ||
| 652 | static const struct header_ops ppp_header_ops = { | 661 | static const struct header_ops ppp_header_ops = { |
| @@ -657,7 +666,7 @@ static int ppp_ioctl(struct net_device *dev, struct if_settings *ifs) · 4 unmodified lines | |||
| 657 | { | 666 | { |
| 658 | hdlc_device *hdlc = dev_to_hdlc(dev); | 667 | hdlc_device *hdlc = dev_to_hdlc(dev); |
| 659 | struct ppp *ppp; | 668 | struct ppp *ppp; |
| 660 | int result; | 669 | int i, result; |
| 661 | 670 | ||
| 662 | switch (ifs->type) { | 671 | switch (ifs->type) { |
| 663 | case IF_GET_PROTO: | 672 | case IF_GET_PROTO: |
| @@ -685,6 +694,8 @@ static int ppp_ioctl(struct net_device *dev, struct if_settings *ifs) · 21 unmodified lines | |||
| 685 | return result; | 694 | return result; |
| 686 | 695 | ||
| 687 | ppp = get_ppp(dev); | 696 | ppp = get_ppp(dev); |
| 697 | for (i = 0; i < IDX_COUNT; i++) | ||
| 698 | timer_setup(&ppp->protos[i].timer, ppp_timer, 0); | ||
| 688 | spin_lock_init(&ppp->lock); | 699 | spin_lock_init(&ppp->lock); |
| 689 | ppp->req_timeout = 2; | 700 | ppp->req_timeout = 2; |
| 690 | ppp->cr_retries = 10; | 701 | ppp->cr_retries = 10; |
| @@ -1487,11 +1487,11 @@ static int ixp4xx_hss_probe(struct platform_device *pdev) · 1486 unmodified lines | |||
| 1487 | "unable to get CLK internal GPIO\n"); | 1487 | "unable to get CLK internal GPIO\n"); |
| 1488 | 1488 | ||
| 1489 | ndev = alloc_hdlcdev(port); | 1489 | ndev = alloc_hdlcdev(port); |
| 1490 | port->netdev = alloc_hdlcdev(port); | 1490 | if (!ndev) { |
| 1491 | if (!port->netdev) { | ||
| 1492 | err = -ENOMEM; | 1491 | err = -ENOMEM; |
| 1493 | goto err_plat; | 1492 | goto err_plat; |
| 1494 | } | 1493 | } |
| 1494 | port->netdev = ndev; | ||
| 1495 | 1495 | ||
| 1496 | SET_NETDEV_DEV(ndev, &pdev->dev); | 1496 | SET_NETDEV_DEV(ndev, &pdev->dev); |
| 1497 | hdlc = dev_to_hdlc(ndev); | 1497 | hdlc = dev_to_hdlc(ndev); |
| @@ -1063,6 +1063,9 @@ err_free_tx_ring: · 1062 unmodified lines | |||
| 1063 | while (i--) | 1063 | while (i--) |
| 1064 | t7xx_cldma_ring_free(md_ctrl, &md_ctrl->tx_ring[i], DMA_TO_DEVICE); | 1064 | t7xx_cldma_ring_free(md_ctrl, &md_ctrl->tx_ring[i], DMA_TO_DEVICE); |
| 1065 | 1065 | ||
| 1066 | dma_pool_destroy(md_ctrl->gpd_dmapool); | ||
| 1067 | md_ctrl->gpd_dmapool = NULL; | ||
| 1068 | |||
| 1066 | return ret; | 1069 | return ret; |
| 1067 | } | 1070 | } |
| 1068 | 1071 | ||
| @@ -101,7 +101,8 @@ void afs_process_oob_queue(struct work_struct *work) · 100 unmodified lines | |||
| 101 | struct sk_buff *oob; | 101 | struct sk_buff *oob; |
| 102 | enum rxrpc_oob_type type; | 102 | enum rxrpc_oob_type type; |
| 103 | 103 | ||
| 104 | while ((oob = rxrpc_kernel_dequeue_oob(net->socket, &type))) { | 104 | while (READ_ONCE(net->live) && |
| 105 | (oob = rxrpc_kernel_dequeue_oob(net->socket, &type))) { | ||
| 105 | switch (type) { | 106 | switch (type) { |
| 106 | case RXRPC_OOB_CHALLENGE: | 107 | case RXRPC_OOB_CHALLENGE: |
| 107 | afs_respond_to_challenge(oob); | 108 | afs_respond_to_challenge(oob); |
| @@ -128,8 +128,14 @@ void afs_close_socket(struct afs_net *net) · 127 unmodified lines | |||
| 128 | _enter(""); | 128 | _enter(""); |
| 129 | 129 | ||
| 130 | cancel_work_sync(&net->charge_preallocation_work); | 130 | cancel_work_sync(&net->charge_preallocation_work); |
| 131 | cancel_work_sync(&net->rx_oob_work); | ||
| 132 | /* Future work items should now see ->live is false. */ | ||
| 133 | |||
| 131 | kernel_listen(net->socket, 0); | 134 | kernel_listen(net->socket, 0); |
| 135 | |||
| 136 | /* Make sure work items are no longer running. */ | ||
| 132 | flush_workqueue(afs_async_calls); | 137 | flush_workqueue(afs_async_calls); |
| 138 | cancel_work_sync(&net->charge_preallocation_work); | ||
| 133 | 139 | ||
| 134 | if (net->spare_incoming_call) { | 140 | if (net->spare_incoming_call) { |
| 135 | afs_put_call(net->spare_incoming_call); | 141 | afs_put_call(net->spare_incoming_call); |
| @@ -143,6 +149,7 @@ void afs_close_socket(struct afs_net *net) · 7 unmodified lines | |||
| 143 | 149 | ||
| 144 | kernel_sock_shutdown(net->socket, SHUT_RDWR); | 150 | kernel_sock_shutdown(net->socket, SHUT_RDWR); |
| 145 | flush_workqueue(afs_async_calls); | 151 | flush_workqueue(afs_async_calls); |
| 152 | cancel_work_sync(&net->rx_oob_work); | ||
| 146 | net->socket->sk->sk_user_data = NULL; | 153 | net->socket->sk->sk_user_data = NULL; |
| 147 | sock_release(net->socket); | 154 | sock_release(net->socket); |
| 148 | key_put(net->fs_cm_token_key); | 155 | key_put(net->fs_cm_token_key); |
| @@ -984,5 +991,6 @@ static void afs_rx_notify_oob(struct sock *sk, struct sk_buff *oob) · 835 unmodified lines | |||
| 984 | { | 991 | { |
| 985 | struct afs_net *net = sk->sk_user_data; | 992 | struct afs_net *net = sk->sk_user_data; |
| 986 | 993 | ||
| 987 | schedule_work(&net->rx_oob_work); | 994 | if (READ_ONCE(net->live)) |
| 995 | queue_work(afs_wq, &net->rx_oob_work); | ||
| 988 | } | 996 | } |
| @@ -942,6 +942,7 @@ struct kernel_ethtool_ts_info { · 941 unmodified lines | |||
| 942 | #define ETHTOOL_OP_NEEDS_RTNL_GPAUSEPARAM BIT(5) | 942 | #define ETHTOOL_OP_NEEDS_RTNL_GPAUSEPARAM BIT(5) |
| 943 | #define ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM BIT(6) | 943 | #define ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM BIT(6) |
| 944 | #define ETHTOOL_OP_NEEDS_RTNL_RSS BIT(7) | 944 | #define ETHTOOL_OP_NEEDS_RTNL_RSS BIT(7) |
| 945 | #define ETHTOOL_OP_NEEDS_RTNL_GLINK BIT(8) | ||
| 945 | 946 | ||
| 946 | /** | 947 | /** |
| 947 | * struct ethtool_ops - optional netdev operations | 948 | * struct ethtool_ops - optional netdev operations |
| @@ -978,6 +979,7 @@ struct kernel_ethtool_ts_info { · 30 unmodified lines | |||
| 978 | * - phylink helpers (note that phydev is currently unsupported!) | 979 | * - phylink helpers (note that phydev is currently unsupported!) |
| 979 | * - netdev_update_features() | 980 | * - netdev_update_features() |
| 980 | * - netif_set_real_num_tx_queues() | 981 | * - netif_set_real_num_tx_queues() |
| 982 | * - ethtool_op_get_link() (syncs link watch under rtnl_lock) | ||
| 981 | * | 983 | * |
| 982 | * @get_drvinfo: Report driver/device information. Modern drivers no | 984 | * @get_drvinfo: Report driver/device information. Modern drivers no |
| 983 | * longer have to implement this callback. Most fields are | 985 | * longer have to implement this callback. Most fields are |
| @@ -1131,6 +1131,9 @@ struct netdev_net_notifier { · 1130 unmodified lines | |||
| 1131 | * netdev_hw_addr_list_for_each(ha, uc). Return 0 on success or a | 1131 | * netdev_hw_addr_list_for_each(ha, uc). Return 0 on success or a |
| 1132 | * negative errno to request a retry via the core backoff. | 1132 | * negative errno to request a retry via the core backoff. |
| 1133 | * | 1133 | * |
| 1134 | * void (*ndo_work)(struct net_device *dev, unsigned long events); | ||
| 1135 | * Run deferred work scheduled with netdev_work_sched(@events). | ||
| 1136 | * | ||
| 1134 | * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); | 1137 | * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); |
| 1135 | * This function is called when the Media Access Control address | 1138 | * This function is called when the Media Access Control address |
| 1136 | * needs to be changed. If this interface is not defined, the | 1139 | * needs to be changed. If this interface is not defined, the |
| @@ -1460,6 +1463,8 @@ struct net_device_ops { · 323 unmodified lines | |||
| 1460 | struct net_device *dev, | 1463 | struct net_device *dev, |
| 1461 | struct netdev_hw_addr_list *uc, | 1464 | struct netdev_hw_addr_list *uc, |
| 1462 | struct netdev_hw_addr_list *mc); | 1465 | struct netdev_hw_addr_list *mc); |
| 1466 | void (*ndo_work)(struct net_device *dev, | ||
| 1467 | unsigned long events); | ||
| 1463 | int (*ndo_set_mac_address)(struct net_device *dev, | 1468 | int (*ndo_set_mac_address)(struct net_device *dev, |
| 1464 | void *addr); | 1469 | void *addr); |
| 1465 | int (*ndo_validate_addr)(struct net_device *dev); | 1470 | int (*ndo_validate_addr)(struct net_device *dev); |
| @@ -1930,8 +1935,11 @@ enum netdev_reg_state { · 464 unmodified lines | |||
| 1930 | * has been enabled due to the need to listen to | 1935 | * has been enabled due to the need to listen to |
| 1931 | * additional unicast addresses in a device that | 1936 | * additional unicast addresses in a device that |
| 1932 | * does not implement ndo_set_rx_mode() | 1937 | * does not implement ndo_set_rx_mode() |
| 1933 | * @rx_mode_node: List entry for rx_mode work processing | 1938 | * @work_node: List entry for async netdev_work processing |
| 1934 | * @rx_mode_tracker: Refcount tracker for rx_mode work | 1939 | * @work_tracker: Refcount tracker for async netdev_work |
| 1940 | * @work_pending: Driver-defined pending netdev_work, passed to | ||
| 1941 | * ndo_work() (see netdev_work_sched()) | ||
| 1942 | * @work_core_pending: Core-defined pending netdev_work (NETDEV_WORK_*) | ||
| 1935 | * @rx_mode_addr_cache: Recycled snapshot entries for rx_mode work | 1943 | * @rx_mode_addr_cache: Recycled snapshot entries for rx_mode work |
| 1936 | * @rx_mode_retry_timer: Timer that re-queues rx_mode work after failure | 1944 | * @rx_mode_retry_timer: Timer that re-queues rx_mode work after failure |
| 1937 | * @rx_mode_retry_count: Number of consecutive retries already scheduled | 1945 | * @rx_mode_retry_count: Number of consecutive retries already scheduled |
| @@ -2326,8 +2334,10 @@ struct net_device { · 388 unmodified lines | |||
| 2326 | unsigned int promiscuity; | 2334 | unsigned int promiscuity; |
| 2327 | unsigned int allmulti; | 2335 | unsigned int allmulti; |
| 2328 | bool uc_promisc; | 2336 | bool uc_promisc; |
| 2329 | struct list_head rx_mode_node; | 2337 | struct list_head work_node; |
| 2330 | netdevice_tracker rx_mode_tracker; | 2338 | netdevice_tracker work_tracker; |
| 2339 | unsigned long work_pending; | ||
| 2340 | unsigned long work_core_pending; | ||
| 2331 | struct netdev_hw_addr_list rx_mode_addr_cache; | 2341 | struct netdev_hw_addr_list rx_mode_addr_cache; |
| 2332 | struct timer_list rx_mode_retry_timer; | 2342 | struct timer_list rx_mode_retry_timer; |
| 2333 | unsigned int rx_mode_retry_count; | 2343 | unsigned int rx_mode_retry_count; |
| @@ -5176,6 +5186,9 @@ void dev_fetch_sw_netstats(struct rtnl_link_stats64 *s, · 2842 unmodified lines | |||
| 5176 | const struct pcpu_sw_netstats __percpu *netstats); | 5186 | const struct pcpu_sw_netstats __percpu *netstats); |
| 5177 | void dev_get_tstats64(struct net_device *dev, struct rtnl_link_stats64 *s); | 5187 | void dev_get_tstats64(struct net_device *dev, struct rtnl_link_stats64 *s); |
| 5178 | 5188 | ||
| 5189 | void netdev_work_sched(struct net_device *dev, unsigned long events); | ||
| 5190 | unsigned long netdev_work_cancel(struct net_device *dev, unsigned long mask); | ||
| 5191 | |||
| 5179 | enum { | 5192 | enum { |
| 5180 | NESTED_SYNC_IMM_BIT, | 5193 | NESTED_SYNC_IMM_BIT, |
| 5181 | NESTED_SYNC_TODO_BIT, | 5194 | NESTED_SYNC_TODO_BIT, |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | * @match: the match extension | 18 | * @match: the match extension |
| 19 | * @target: the target extension | 19 | * @target: the target extension |
| 20 | * @matchinfo: per-match data | 20 | * @matchinfo: per-match data |
| 21 | * @targetinfo: per-target data | 21 | * @targinfo: per-target data |
| 22 | * @state: pointer to hook state this packet came from | 22 | * @state: pointer to hook state this packet came from |
| 23 | * @fragoff: packet is a fragment, this is the data offset | 23 | * @fragoff: packet is a fragment, this is the data offset |
| 24 | * @thoff: position of transport header relative to skb->data | 24 | * @thoff: position of transport header relative to skb->data |
| @@ -77,7 +77,9 @@ static inline u_int8_t xt_family(const struct xt_action_param *par) · 52 unmodified lines | |||
| 77 | * @match: struct xt_match through which this function was invoked | 77 | * @match: struct xt_match through which this function was invoked |
| 78 | * @matchinfo: per-match data | 78 | * @matchinfo: per-match data |
| 79 | * @hook_mask: via which hooks the new rule is reachable | 79 | * @hook_mask: via which hooks the new rule is reachable |
| 80 | * Other fields as above. | 80 | * @family: actual NFPROTO_* through which the function is invoked |
| 81 | * (helpful when match->family == NFPROTO_UNSPEC) | ||
| 82 | * @nft_compat: running from the nft compat layer if true | ||
| 81 | */ | 83 | */ |
| 82 | struct xt_mtchk_param { | 84 | struct xt_mtchk_param { |
| 83 | struct net *net; | 85 | struct net *net; |
| @@ -91,8 +93,13 @@ struct xt_mtchk_param { · 7 unmodified lines | |||
| 91 | }; | 93 | }; |
| 92 | 94 | ||
| 93 | /** | 95 | /** |
| 94 | * struct xt_mdtor_param - match destructor parameters | 96 | * struct xt_mtdtor_param - match destructor parameters |
| 95 | * Fields as above. | 97 | * |
| 98 | * @net: network namespace through which the check was invoked | ||
| 99 | * @match: struct xt_match through which this function was invoked | ||
| 100 | * @matchinfo: per-match data | ||
| 101 | * @family: actual NFPROTO_* through which the function is invoked | ||
| 102 | * (helpful when match->family == NFPROTO_UNSPEC) | ||
| 96 | */ | 103 | */ |
| 97 | struct xt_mtdtor_param { | 104 | struct xt_mtdtor_param { |
| 98 | struct net *net; | 105 | struct net *net; |
| @@ -105,10 +112,16 @@ struct xt_mtdtor_param { · 6 unmodified lines | |||
| 105 | * struct xt_tgchk_param - parameters for target extensions' | 112 | * struct xt_tgchk_param - parameters for target extensions' |
| 106 | * checkentry functions | 113 | * checkentry functions |
| 107 | * | 114 | * |
| 115 | * @net: network namespace through which the check was invoked | ||
| 116 | * @table: table the rule is tried to be inserted into | ||
| 108 | * @entryinfo: the family-specific rule data | 117 | * @entryinfo: the family-specific rule data |
| 109 | * (struct ipt_entry, ip6t_entry, arpt_entry, ebt_entry) | 118 | * (struct ipt_entry, ip6t_entry, arpt_entry, ebt_entry) |
| 110 | * | 119 | * @target: the target extension |
| 111 | * Other fields see above. | 120 | * @targinfo: per-target data |
| 121 | * @hook_mask: via which hooks the new rule is reachable | ||
| 122 | * @family: actual NFPROTO_* through which the function is invoked | ||
| 123 | * (helpful when match->family == NFPROTO_UNSPEC) | ||
| 124 | * @nft_compat: running from the nft compat layer if true | ||
| 112 | */ | 125 | */ |
| 113 | struct xt_tgchk_param { | 126 | struct xt_tgchk_param { |
| 114 | struct net *net; | 127 | struct net *net; |
| @@ -336,9 +349,9 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size); · 221 unmodified lines | |||
| 336 | void xt_free_table_info(struct xt_table_info *info); | 349 | void xt_free_table_info(struct xt_table_info *info); |
| 337 | 350 | ||
| 338 | /** | 351 | /** |
| 339 | * xt_recseq - recursive seqcount for netfilter use | 352 | * var xt_recseq - recursive seqcount for netfilter use |
| 340 | * | 353 | * |
| 341 | * Packet processing changes the seqcount only if no recursion happened | 354 | * Packet processing changes the seqcount only if no recursion happened. |
| 342 | * get_counters() can use read_seqcount_begin()/read_seqcount_retry(), | 355 | * get_counters() can use read_seqcount_begin()/read_seqcount_retry(), |
| 343 | * because we use the normal seqcount convention : | 356 | * because we use the normal seqcount convention : |
| 344 | * Low order bit set to 1 if a writer is active. | 357 | * Low order bit set to 1 if a writer is active. |
| @@ -164,8 +164,11 @@ static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb) · 163 unmodified lines | |||
| 164 | if (!new_md) | 164 | if (!new_md) |
| 165 | return ERR_PTR(-ENOMEM); | 165 | return ERR_PTR(-ENOMEM); |
| 166 | 166 | ||
| 167 | memcpy(&new_md->u.tun_info, &md_dst->u.tun_info, | 167 | /* Copy in two stages to keep the __counted_by happy. */ |
| 168 | sizeof(struct ip_tunnel_info) + md_size); | 168 | new_md->u.tun_info = md_dst->u.tun_info; |
| 169 | memcpy(ip_tunnel_info_opts(&new_md->u.tun_info), | ||
| 170 | ip_tunnel_info_opts(&md_dst->u.tun_info), md_size); | ||
| 171 | |||
| 169 | #ifdef CONFIG_DST_CACHE | 172 | #ifdef CONFIG_DST_CACHE |
| 170 | /* Unclone the dst cache if there is one */ | 173 | /* Unclone the dst cache if there is one */ |
| 171 | if (new_md->u.tun_info.dst_cache.cache) { | 174 | if (new_md->u.tun_info.dst_cache.cache) { |
| @@ -374,7 +374,7 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp, · 373 unmodified lines | |||
| 374 | struct fib_result *res, unsigned int flags) | 374 | struct fib_result *res, unsigned int flags) |
| 375 | { | 375 | { |
| 376 | struct fib_table *tb; | 376 | struct fib_table *tb; |
| 377 | int err = -ENETUNREACH; | 377 | int err = -EAGAIN; |
| 378 | 378 | ||
| 379 | flags |= FIB_LOOKUP_NOREF; | 379 | flags |= FIB_LOOKUP_NOREF; |
| 380 | if (net->ipv4.fib_has_custom_rules) | 380 | if (net->ipv4.fib_has_custom_rules) |
| @@ -388,17 +388,16 @@ static inline int fib_lookup(struct net *net, struct flowi4 *flp, · 7 unmodified lines | |||
| 388 | if (tb) | 388 | if (tb) |
| 389 | err = fib_table_lookup(tb, flp, res, flags); | 389 | err = fib_table_lookup(tb, flp, res, flags); |
| 390 | 390 | ||
| 391 | if (!err) | 391 | if (err != -EAGAIN) |
| 392 | goto out; | 392 | goto out; |
| 393 | 393 | ||
| 394 | tb = rcu_dereference_rtnl(net->ipv4.fib_default); | 394 | tb = rcu_dereference_rtnl(net->ipv4.fib_default); |
| 395 | if (tb) | 395 | if (tb) |
| 396 | err = fib_table_lookup(tb, flp, res, flags); | 396 | err = fib_table_lookup(tb, flp, res, flags); |
| 397 | 397 | ||
| 398 | out: | ||
| 399 | if (err == -EAGAIN) | 398 | if (err == -EAGAIN) |
| 400 | err = -ENETUNREACH; | 399 | err = -ENETUNREACH; |
| 401 | 400 | out: | |
| 402 | rcu_read_unlock(); | 401 | rcu_read_unlock(); |
| 403 | 402 | ||
| 404 | return err; | 403 | return err; |
| @@ -26,6 +26,7 @@ struct nf_conntrack_expect { · 25 unmodified lines | |||
| 26 | possible_net_t net; | 26 | possible_net_t net; |
| 27 | 27 | ||
| 28 | /* We expect this tuple, with the following mask */ | 28 | /* We expect this tuple, with the following mask */ |
| 29 | struct nf_conntrack_tuple master_tuple; | ||
| 29 | struct nf_conntrack_tuple tuple; | 30 | struct nf_conntrack_tuple tuple; |
| 30 | struct nf_conntrack_tuple_mask mask; | 31 | struct nf_conntrack_tuple_mask mask; |
| 31 | 32 | ||
| @@ -54,8 +55,8 @@ struct nf_conntrack_expect { · 22 unmodified lines | |||
| 54 | /* The conntrack of the master connection */ | 55 | /* The conntrack of the master connection */ |
| 55 | struct nf_conn *master; | 56 | struct nf_conn *master; |
| 56 | 57 | ||
| 57 | /* Timer function; deletes the expectation. */ | 58 | /* jiffies32 when this expectation expires */ |
| 58 | struct timer_list timeout; | 59 | u32 timeout; |
| 59 | 60 | ||
| 60 | #if IS_ENABLED(CONFIG_NF_NAT) | 61 | #if IS_ENABLED(CONFIG_NF_NAT) |
| 61 | union nf_inet_addr saved_addr; | 62 | union nf_inet_addr saved_addr; |
| @@ -69,6 +70,14 @@ struct nf_conntrack_expect { · 7 unmodified lines | |||
| 69 | struct rcu_head rcu; | 70 | struct rcu_head rcu; |
| 70 | }; | 71 | }; |
| 71 | 72 | ||
| 73 | static inline bool nf_ct_exp_is_expired(const struct nf_conntrack_expect *exp) | ||
| 74 | { | ||
| 75 | if (READ_ONCE(exp->flags) & NF_CT_EXPECT_DEAD) | ||
| 76 | return true; | ||
| 77 | |||
| 78 | return (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) <= 0; | ||
| 79 | } | ||
| 80 | |||
| 72 | static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) | 81 | static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) |
| 73 | { | 82 | { |
| 74 | return read_pnet(&exp->net); | 83 | return read_pnet(&exp->net); |
| @@ -130,7 +139,6 @@ static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) · 55 unmodified lines | |||
| 130 | 139 | ||
| 131 | void nf_ct_remove_expectations(struct nf_conn *ct); | 140 | void nf_ct_remove_expectations(struct nf_conn *ct); |
| 132 | void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); | 141 | void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); |
| 133 | bool nf_ct_remove_expect(struct nf_conntrack_expect *exp); | ||
| 134 | 142 | ||
| 135 | void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data), void *data); | 143 | void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, void *data), void *data); |
| 136 | void nf_ct_expect_iterate_net(struct net *net, | 144 | void nf_ct_expect_iterate_net(struct net *net, |
| @@ -153,5 +161,8 @@ static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect, · 16 unmodified lines | |||
| 153 | return nf_ct_expect_related_report(expect, 0, 0, flags); | 161 | return nf_ct_expect_related_report(expect, 0, 0, flags); |
| 154 | } | 162 | } |
| 155 | 163 | ||
| 164 | struct nf_conn_help; | ||
| 165 | void nf_ct_expectation_gc(struct nf_conn_help *master_help); | ||
| 166 | |||
| 156 | #endif /*_NF_CONNTRACK_EXPECT_H*/ | 167 | #endif /*_NF_CONNTRACK_EXPECT_H*/ |
| 157 | 168 | ||
| @@ -114,6 +114,10 @@ int nf_conntrack_helpers_register(struct nf_conntrack_helper *, unsigned int, · 113 unmodified lines | |||
| 114 | void nf_conntrack_helpers_unregister(struct nf_conntrack_helper **, | 114 | void nf_conntrack_helpers_unregister(struct nf_conntrack_helper **, |
| 115 | unsigned int); | 115 | unsigned int); |
| 116 | 116 | ||
| 117 | #define nf_conntrack_helper_deprecated(name) \ | ||
| 118 | pr_warn("The %s conntrack helper is scheduled for removal.\n" \ | ||
| 119 | "Please contact the netfilter-devel mailing list if you still need this.\n", name) | ||
| 120 | |||
| 117 | struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); | 121 | struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); |
| 118 | 122 | ||
| 119 | int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, | 123 | int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, |
| @@ -18,6 +18,7 @@ struct nf_queue_entry { · 17 unmodified lines | |||
| 18 | unsigned int id; | 18 | unsigned int id; |
| 19 | unsigned int hook_index; /* index in hook_entries->hook[] */ | 19 | unsigned int hook_index; /* index in hook_entries->hook[] */ |
| 20 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 20 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
| 21 | struct net_device *bridge_dev; | ||
| 21 | struct net_device *physin; | 22 | struct net_device *physin; |
| 22 | struct net_device *physout; | 23 | struct net_device *physout; |
| 23 | #endif | 24 | #endif |
| @@ -40,6 +40,8 @@ void nft_meta_set_eval(const struct nft_expr *expr, · 39 unmodified lines | |||
| 40 | void nft_meta_set_destroy(const struct nft_ctx *ctx, | 40 | void nft_meta_set_destroy(const struct nft_ctx *ctx, |
| 41 | const struct nft_expr *expr); | 41 | const struct nft_expr *expr); |
| 42 | 42 | ||
| 43 | int nft_meta_get_validate(const struct nft_ctx *ctx, | ||
| 44 | const struct nft_expr *expr); | ||
| 43 | int nft_meta_set_validate(const struct nft_ctx *ctx, | 45 | int nft_meta_set_validate(const struct nft_ctx *ctx, |
| 44 | const struct nft_expr *expr); | 46 | const struct nft_expr *expr); |
| 45 | 47 | ||
| @@ -256,6 +256,8 @@ int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm, · 255 unmodified lines | |||
| 256 | int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer, | 256 | int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer, |
| 257 | struct netlink_ext_ack *exterr); | 257 | struct netlink_ext_ack *exterr); |
| 258 | struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid); | 258 | struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid); |
| 259 | bool rtnl_dev_link_net_capable(const struct net_device *dev, | ||
| 260 | const struct net *link_net); | ||
| 259 | 261 | ||
| 260 | #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) | 262 | #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) |
| 261 | 263 | ||
| @@ -111,7 +111,8 @@ int sctp_transport_lookup_process(sctp_callback_t cb, struct net *net, · 110 unmodified lines | |||
| 111 | const union sctp_addr *paddr, void *p, int dif); | 111 | const union sctp_addr *paddr, void *p, int dif); |
| 112 | int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done, | 112 | int sctp_transport_traverse_process(sctp_callback_t cb, sctp_callback_t cb_done, |
| 113 | struct net *net, int *pos, void *p); | 113 | struct net *net, int *pos, void *p); |
| 114 | int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), void *p); | 114 | int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), |
| 115 | struct net *net, int *pos, void *p); | ||
| 115 | int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, | 116 | int sctp_get_sctp_info(struct sock *sk, struct sctp_association *asoc, |
| 116 | struct sctp_info *info); | 117 | struct sctp_info *info); |
| 117 | 118 | ||
| @@ -953,6 +953,9 @@ static inline bool addr_match(const void *token1, const void *token2, · 952 unmodified lines | |||
| 953 | unsigned int pdw; | 953 | unsigned int pdw; |
| 954 | unsigned int pbi; | 954 | unsigned int pbi; |
| 955 | 955 | ||
| 956 | if (prefixlen > 128) | ||
| 957 | return false; | ||
| 958 | |||
| 956 | pdw = prefixlen >> 5; /* num of whole u32 in prefix */ | 959 | pdw = prefixlen >> 5; /* num of whole u32 in prefix */ |
| 957 | pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ | 960 | pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ |
| 958 | 961 | ||
| @@ -977,6 +980,10 @@ static inline bool addr4_match(__be32 a1, __be32 a2, u8 prefixlen) · 18 unmodified lines | |||
| 977 | /* C99 6.5.7 (3): u32 << 32 is undefined behaviour */ | 980 | /* C99 6.5.7 (3): u32 << 32 is undefined behaviour */ |
| 978 | if (sizeof(long) == 4 && prefixlen == 0) | 981 | if (sizeof(long) == 4 && prefixlen == 0) |
| 979 | return true; | 982 | return true; |
| 983 | |||
| 984 | if (prefixlen > 32) | ||
| 985 | return false; | ||
| 986 | |||
| 980 | return !((a1 ^ a2) & htonl(~0UL << (32 - prefixlen))); | 987 | return !((a1 ^ a2) & htonl(~0UL << (32 - prefixlen))); |
| 981 | } | 988 | } |
| 982 | 989 | ||
| @@ -1260,8 +1267,8 @@ int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb, · 277 unmodified lines | |||
| 1260 | static inline bool __xfrm_check_nopolicy(struct net *net, struct sk_buff *skb, | 1267 | static inline bool __xfrm_check_nopolicy(struct net *net, struct sk_buff *skb, |
| 1261 | int dir) | 1268 | int dir) |
| 1262 | { | 1269 | { |
| 1263 | if (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) | 1270 | if (!READ_ONCE(net->xfrm.policy_count[dir]) && !secpath_exists(skb)) |
| 1264 | return net->xfrm.policy_default[dir] == XFRM_USERPOLICY_ACCEPT; | 1271 | return READ_ONCE(net->xfrm.policy_default[dir]) == XFRM_USERPOLICY_ACCEPT; |
| 1265 | 1272 | ||
| 1266 | return false; | 1273 | return false; |
| 1267 | } | 1274 | } |
| @@ -1361,8 +1368,8 @@ static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) · 93 unmodified lines | |||
| 1361 | { | 1368 | { |
| 1362 | struct net *net = dev_net(skb->dev); | 1369 | struct net *net = dev_net(skb->dev); |
| 1363 | 1370 | ||
| 1364 | if (!net->xfrm.policy_count[XFRM_POLICY_OUT] && | 1371 | if (!READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT]) && |
| 1365 | net->xfrm.policy_default[XFRM_POLICY_OUT] == XFRM_USERPOLICY_ACCEPT) | 1372 | READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_OUT]) == XFRM_USERPOLICY_ACCEPT) |
| 1366 | return true; | 1373 | return true; |
| 1367 | 1374 | ||
| 1368 | return (skb_dst(skb)->flags & DST_NOXFRM) || | 1375 | return (skb_dst(skb)->flags & DST_NOXFRM) || |
| @@ -160,6 +160,7 @@ enum ip_conntrack_expect_events { · 159 unmodified lines | |||
| 160 | #define NF_CT_EXPECT_USERSPACE 0x4 | 160 | #define NF_CT_EXPECT_USERSPACE 0x4 |
| 161 | 161 | ||
| 162 | #ifdef __KERNEL__ | 162 | #ifdef __KERNEL__ |
| 163 | #define NF_CT_EXPECT_DEAD 0x8 | ||
| 163 | #define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \ | 164 | #define NF_CT_EXPECT_MASK (NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE | \ |
| 164 | NF_CT_EXPECT_USERSPACE) | 165 | NF_CT_EXPECT_USERSPACE) |
| 165 | #endif | 166 | #endif |
| @@ -77,9 +77,9 @@ static int vlan_group_prealloc_vid(struct vlan_group *vg, · 76 unmodified lines | |||
| 77 | return 0; | 77 | return 0; |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | static void vlan_stacked_transfer_operstate(const struct net_device *rootdev, | 80 | void vlan_stacked_transfer_operstate(const struct net_device *rootdev, |
| 81 | struct net_device *dev, | 81 | struct net_device *dev, |
| 82 | struct vlan_dev_priv *vlan) | 82 | struct vlan_dev_priv *vlan) |
| 83 | { | 83 | { |
| 84 | if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) | 84 | if (!(vlan->flags & VLAN_FLAG_BRIDGE_BINDING)) |
| 85 | netif_stacked_transfer_operstate(rootdev, dev); | 85 | netif_stacked_transfer_operstate(rootdev, dev); |
| @@ -316,29 +316,6 @@ out: · 230 unmodified lines | |||
| 316 | ether_addr_copy(vlan->real_dev_addr, dev->dev_addr); | 316 | ether_addr_copy(vlan->real_dev_addr, dev->dev_addr); |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | static void vlan_transfer_features(struct net_device *dev, | ||
| 320 | struct net_device *vlandev) | ||
| 321 | { | ||
| 322 | struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); | ||
| 323 | |||
| 324 | netif_inherit_tso_max(vlandev, dev); | ||
| 325 | |||
| 326 | if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto)) | ||
| 327 | vlandev->hard_header_len = dev->hard_header_len; | ||
| 328 | else | ||
| 329 | vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN; | ||
| 330 | |||
| 331 | #if IS_ENABLED(CONFIG_FCOE) | ||
| 332 | vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; | ||
| 333 | #endif | ||
| 334 | |||
| 335 | vlandev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
| 336 | vlandev->priv_flags |= (vlan->real_dev->priv_flags & IFF_XMIT_DST_RELEASE); | ||
| 337 | vlandev->hw_enc_features = vlan_tnl_features(vlan->real_dev); | ||
| 338 | |||
| 339 | netdev_update_features(vlandev); | ||
| 340 | } | ||
| 341 | |||
| 342 | static int __vlan_device_event(struct net_device *dev, unsigned long event) | 319 | static int __vlan_device_event(struct net_device *dev, unsigned long event) |
| 343 | { | 320 | { |
| 344 | int err = 0; | 321 | int err = 0; |
| @@ -391,13 +368,11 @@ static void vlan_vid0_del(struct net_device *dev) · 46 unmodified lines | |||
| 391 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, | 368 | static int vlan_device_event(struct notifier_block *unused, unsigned long event, |
| 392 | void *ptr) | 369 | void *ptr) |
| 393 | { | 370 | { |
| 394 | struct netlink_ext_ack *extack = netdev_notifier_info_to_extack(ptr); | ||
| 395 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); | 371 | struct net_device *dev = netdev_notifier_info_to_dev(ptr); |
| 396 | struct vlan_group *grp; | 372 | struct vlan_group *grp; |
| 397 | struct vlan_info *vlan_info; | 373 | struct vlan_info *vlan_info; |
| 398 | int i, flgs; | 374 | int i, flgs; |
| 399 | struct net_device *vlandev; | 375 | struct net_device *vlandev; |
| 400 | struct vlan_dev_priv *vlan; | ||
| 401 | bool last = false; | 376 | bool last = false; |
| 402 | LIST_HEAD(list); | 377 | LIST_HEAD(list); |
| 403 | int err; | 378 | int err; |
| @@ -447,54 +422,19 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, · 43 unmodified lines | |||
| 447 | if (vlandev->mtu <= dev->mtu) | 422 | if (vlandev->mtu <= dev->mtu) |
| 448 | continue; | 423 | continue; |
| 449 | 424 | ||
| 450 | dev_set_mtu(vlandev, dev->mtu); | 425 | netdev_work_sched(vlandev, VLAN_WORK_MTU); |
| 451 | } | 426 | } |
| 452 | break; | 427 | break; |
| 453 | 428 | ||
| 454 | case NETDEV_FEAT_CHANGE: | 429 | case NETDEV_FEAT_CHANGE: |
| 455 | /* Propagate device features to underlying device */ | ||
| 456 | vlan_group_for_each_dev(grp, i, vlandev) | 430 | vlan_group_for_each_dev(grp, i, vlandev) |
| 457 | vlan_transfer_features(dev, vlandev); | 431 | netdev_work_sched(vlandev, VLAN_WORK_FEATURES); |
| 458 | break; | 432 | break; |
| 459 | 433 | ||
| 460 | case NETDEV_DOWN: { | 434 | case NETDEV_DOWN: |
| 461 | struct net_device *tmp; | ||
| 462 | LIST_HEAD(close_list); | ||
| 463 | |||
| 464 | /* Put all VLANs for this dev in the down state too. */ | ||
| 465 | vlan_group_for_each_dev(grp, i, vlandev) { | ||
| 466 | flgs = vlandev->flags; | ||
| 467 | if (!(flgs & IFF_UP)) | ||
| 468 | continue; | ||
| 469 | |||
| 470 | vlan = vlan_dev_priv(vlandev); | ||
| 471 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | ||
| 472 | list_add(&vlandev->close_list, &close_list); | ||
| 473 | } | ||
| 474 | |||
| 475 | netif_close_many(&close_list, false); | ||
| 476 | |||
| 477 | list_for_each_entry_safe(vlandev, tmp, &close_list, close_list) { | ||
| 478 | vlan_stacked_transfer_operstate(dev, vlandev, | ||
| 479 | vlan_dev_priv(vlandev)); | ||
| 480 | list_del_init(&vlandev->close_list); | ||
| 481 | } | ||
| 482 | list_del(&close_list); | ||
| 483 | break; | ||
| 484 | } | ||
| 485 | case NETDEV_UP: | 435 | case NETDEV_UP: |
| 486 | /* Put all VLANs for this dev in the up state too. */ | 436 | vlan_group_for_each_dev(grp, i, vlandev) |
| 487 | vlan_group_for_each_dev(grp, i, vlandev) { | 437 | netdev_work_sched(vlandev, VLAN_WORK_LINK_STATE); |
| 488 | flgs = netif_get_flags(vlandev); | ||
| 489 | if (flgs & IFF_UP) | ||
| 490 | continue; | ||
| 491 | |||
| 492 | vlan = vlan_dev_priv(vlandev); | ||
| 493 | if (!(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | ||
| 494 | dev_change_flags(vlandev, flgs | IFF_UP, | ||
| 495 | extack); | ||
| 496 | vlan_stacked_transfer_operstate(dev, vlandev, vlan); | ||
| 497 | } | ||
| 498 | break; | 438 | break; |
| 499 | 439 | ||
| 500 | case NETDEV_UNREGISTER: | 440 | case NETDEV_UNREGISTER: |
| @@ -125,6 +125,17 @@ static inline netdev_features_t vlan_tnl_features(struct net_device *real_dev) · 124 unmodified lines | |||
| 125 | int vlan_filter_push_vids(struct vlan_info *vlan_info, __be16 proto); | 125 | int vlan_filter_push_vids(struct vlan_info *vlan_info, __be16 proto); |
| 126 | void vlan_filter_drop_vids(struct vlan_info *vlan_info, __be16 proto); | 126 | void vlan_filter_drop_vids(struct vlan_info *vlan_info, __be16 proto); |
| 127 | 127 | ||
| 128 | /* netdev_work events propagated from the real device, see vlan_dev_work(). */ | ||
| 129 | enum { | ||
| 130 | VLAN_WORK_LINK_STATE = BIT(0), /* sync up/down with real_dev */ | ||
| 131 | VLAN_WORK_MTU = BIT(1), /* clamp mtu to real_dev's */ | ||
| 132 | VLAN_WORK_FEATURES = BIT(2), /* re-inherit real_dev features */ | ||
| 133 | }; | ||
| 134 | |||
| 135 | void vlan_stacked_transfer_operstate(const struct net_device *rootdev, | ||
| 136 | struct net_device *dev, | ||
| 137 | struct vlan_dev_priv *vlan); | ||
| 138 | |||
| 128 | /* found in vlan_dev.c */ | 139 | /* found in vlan_dev.c */ |
| 129 | void vlan_dev_set_ingress_priority(const struct net_device *dev, | 140 | void vlan_dev_set_ingress_priority(const struct net_device *dev, |
| 130 | u32 skb_prio, u16 vlan_prio); | 141 | u32 skb_prio, u16 vlan_prio); |
| @@ -270,6 +270,9 @@ static int vlan_dev_open(struct net_device *dev) · 269 unmodified lines | |||
| 270 | !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) | 270 | !(vlan->flags & VLAN_FLAG_LOOSE_BINDING)) |
| 271 | return -ENETDOWN; | 271 | return -ENETDOWN; |
| 272 | 272 | ||
| 273 | /* The explicit open supersedes any deferred link-state sync */ | ||
| 274 | netdev_work_cancel(dev, VLAN_WORK_LINK_STATE); | ||
| 275 | |||
| 273 | if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) && | 276 | if (!ether_addr_equal(dev->dev_addr, real_dev->dev_addr) && |
| 274 | !vlan_dev_inherit_address(dev, real_dev)) { | 277 | !vlan_dev_inherit_address(dev, real_dev)) { |
| 275 | err = dev_uc_add(real_dev, dev->dev_addr); | 278 | err = dev_uc_add(real_dev, dev->dev_addr); |
| @@ -300,6 +303,9 @@ static int vlan_dev_stop(struct net_device *dev) · 24 unmodified lines | |||
| 300 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); | 303 | struct vlan_dev_priv *vlan = vlan_dev_priv(dev); |
| 301 | struct net_device *real_dev = vlan->real_dev; | 304 | struct net_device *real_dev = vlan->real_dev; |
| 302 | 305 | ||
| 306 | /* The explicit close supersedes any deferred link-state sync */ | ||
| 307 | netdev_work_cancel(dev, VLAN_WORK_LINK_STATE); | ||
| 308 | |||
| 303 | dev_mc_unsync(real_dev, dev); | 309 | dev_mc_unsync(real_dev, dev); |
| 304 | dev_uc_unsync(real_dev, dev); | 310 | dev_uc_unsync(real_dev, dev); |
| 305 | 311 | ||
| @@ -1016,6 +1022,59 @@ static const struct ethtool_ops vlan_ethtool_ops = { · 710 unmodified lines | |||
| 1016 | .get_ts_info = vlan_ethtool_get_ts_info, | 1022 | .get_ts_info = vlan_ethtool_get_ts_info, |
| 1017 | }; | 1023 | }; |
| 1018 | 1024 | ||
| 1025 | static void vlan_transfer_features(struct net_device *dev, | ||
| 1026 | struct net_device *vlandev) | ||
| 1027 | { | ||
| 1028 | struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); | ||
| 1029 | |||
| 1030 | netif_inherit_tso_max(vlandev, dev); | ||
| 1031 | |||
| 1032 | if (vlan_hw_offload_capable(dev->features, vlan->vlan_proto)) | ||
| 1033 | vlandev->hard_header_len = dev->hard_header_len; | ||
| 1034 | else | ||
| 1035 | vlandev->hard_header_len = dev->hard_header_len + VLAN_HLEN; | ||
| 1036 | |||
| 1037 | #if IS_ENABLED(CONFIG_FCOE) | ||
| 1038 | vlandev->fcoe_ddp_xid = dev->fcoe_ddp_xid; | ||
| 1039 | #endif | ||
| 1040 | |||
| 1041 | vlandev->priv_flags &= ~IFF_XMIT_DST_RELEASE; | ||
| 1042 | vlandev->priv_flags |= (vlan->real_dev->priv_flags & IFF_XMIT_DST_RELEASE); | ||
| 1043 | vlandev->hw_enc_features = vlan_tnl_features(vlan->real_dev); | ||
| 1044 | |||
| 1045 | netdev_update_features(vlandev); | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static void vlan_dev_work(struct net_device *vlandev, unsigned long events) | ||
| 1049 | { | ||
| 1050 | struct vlan_dev_priv *vlan = vlan_dev_priv(vlandev); | ||
| 1051 | struct net_device *real_dev = vlan->real_dev; | ||
| 1052 | bool loose = vlan->flags & VLAN_FLAG_LOOSE_BINDING; | ||
| 1053 | unsigned int flgs; | ||
| 1054 | |||
| 1055 | if (events & VLAN_WORK_LINK_STATE) { | ||
| 1056 | flgs = netif_get_flags(vlandev); | ||
| 1057 | if (real_dev->flags & IFF_UP) { | ||
| 1058 | if (!(flgs & IFF_UP)) { | ||
| 1059 | if (!loose) | ||
| 1060 | netif_change_flags(vlandev, | ||
| 1061 | flgs | IFF_UP, NULL); | ||
| 1062 | vlan_stacked_transfer_operstate(real_dev, | ||
| 1063 | vlandev, vlan); | ||
| 1064 | } | ||
| 1065 | } else if ((flgs & IFF_UP) && !loose) { | ||
| 1066 | netif_change_flags(vlandev, flgs & ~IFF_UP, NULL); | ||
| 1067 | vlan_stacked_transfer_operstate(real_dev, vlandev, vlan); | ||
| 1068 | } | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | if ((events & VLAN_WORK_MTU) && vlandev->mtu > real_dev->mtu) | ||
| 1072 | netif_set_mtu(vlandev, real_dev->mtu); | ||
| 1073 | |||
| 1074 | if (events & VLAN_WORK_FEATURES) | ||
| 1075 | vlan_transfer_features(real_dev, vlandev); | ||
| 1076 | } | ||
| 1077 | |||
| 1019 | static const struct net_device_ops vlan_netdev_ops = { | 1078 | static const struct net_device_ops vlan_netdev_ops = { |
| 1020 | .ndo_change_mtu = vlan_dev_change_mtu, | 1079 | .ndo_change_mtu = vlan_dev_change_mtu, |
| 1021 | .ndo_init = vlan_dev_init, | 1080 | .ndo_init = vlan_dev_init, |
| @@ -1027,6 +1086,7 @@ static const struct net_device_ops vlan_netdev_ops = { · 5 unmodified lines | |||
| 1027 | .ndo_set_mac_address = vlan_dev_set_mac_address, | 1086 | .ndo_set_mac_address = vlan_dev_set_mac_address, |
| 1028 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, | 1087 | .ndo_set_rx_mode = vlan_dev_set_rx_mode, |
| 1029 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, | 1088 | .ndo_change_rx_flags = vlan_dev_change_rx_flags, |
| 1089 | .ndo_work = vlan_dev_work, | ||
| 1030 | .ndo_eth_ioctl = vlan_dev_ioctl, | 1090 | .ndo_eth_ioctl = vlan_dev_ioctl, |
| 1031 | .ndo_neigh_setup = vlan_dev_neigh_setup, | 1091 | .ndo_neigh_setup = vlan_dev_neigh_setup, |
| 1032 | .ndo_get_stats64 = vlan_dev_get_stats64, | 1092 | .ndo_get_stats64 = vlan_dev_get_stats64, |
| @@ -316,14 +316,23 @@ batadv_iv_ogm_aggr_packet(int buff_pos, int packet_len, · 315 unmodified lines | |||
| 316 | const struct batadv_ogm_packet *ogm_packet) | 316 | const struct batadv_ogm_packet *ogm_packet) |
| 317 | { | 317 | { |
| 318 | int next_buff_pos = 0; | 318 | int next_buff_pos = 0; |
| 319 | u16 tvlv_len; | ||
| 319 | 320 | ||
| 320 | /* check if there is enough space for the header */ | 321 | /* check if there is enough space for the header */ |
| 321 | next_buff_pos += buff_pos + sizeof(*ogm_packet); | 322 | next_buff_pos += buff_pos + sizeof(*ogm_packet); |
| 322 | if (next_buff_pos > packet_len) | 323 | if (next_buff_pos > packet_len) |
| 323 | return false; | 324 | return false; |
| 324 | 325 | ||
| 326 | tvlv_len = ntohs(ogm_packet->tvlv_len); | ||
| 327 | |||
| 328 | /* the fields of an aggregated OGM are accessed assuming (at least) | ||
| 329 | * 2-byte alignment, so a following OGM must start at an even offset. | ||
| 330 | */ | ||
| 331 | if (tvlv_len & 1) | ||
| 332 | return false; | ||
| 333 | |||
| 325 | /* check if there is enough space for the optional TVLV */ | 334 | /* check if there is enough space for the optional TVLV */ |
| 326 | next_buff_pos += ntohs(ogm_packet->tvlv_len); | 335 | next_buff_pos += tvlv_len; |
| 327 | 336 | ||
| 328 | return next_buff_pos <= packet_len; | 337 | return next_buff_pos <= packet_len; |
| 329 | } | 338 | } |
| @@ -817,6 +817,7 @@ void batadv_v_hardif_init(struct batadv_hard_iface *hard_iface) · 816 unmodified lines | |||
| 817 | 817 | ||
| 818 | hard_iface->bat_v.aggr_len = 0; | 818 | hard_iface->bat_v.aggr_len = 0; |
| 819 | skb_queue_head_init(&hard_iface->bat_v.aggr_list); | 819 | skb_queue_head_init(&hard_iface->bat_v.aggr_list); |
| 820 | hard_iface->bat_v.aggr_list_enabled = false; | ||
| 820 | INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq, | 821 | INIT_DELAYED_WORK(&hard_iface->bat_v.aggr_wq, |
| 821 | batadv_v_ogm_aggr_work); | 822 | batadv_v_ogm_aggr_work); |
| 822 | /* make sure it doesn't run until interface gets enabled */ | 823 | /* make sure it doesn't run until interface gets enabled */ |
| @@ -254,11 +254,18 @@ static void batadv_v_ogm_queue_on_if(struct batadv_priv *bat_priv, · 253 unmodified lines | |||
| 254 | } | 254 | } |
| 255 | 255 | ||
| 256 | spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); | 256 | spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); |
| 257 | if (!hard_iface->bat_v.aggr_list_enabled) { | ||
| 258 | kfree_skb(skb); | ||
| 259 | goto unlock; | ||
| 260 | } | ||
| 261 | |||
| 257 | if (!batadv_v_ogm_queue_left(skb, hard_iface)) | 262 | if (!batadv_v_ogm_queue_left(skb, hard_iface)) |
| 258 | batadv_v_ogm_aggr_send(bat_priv, hard_iface); | 263 | batadv_v_ogm_aggr_send(bat_priv, hard_iface); |
| 259 | 264 | ||
| 260 | hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb); | 265 | hard_iface->bat_v.aggr_len += batadv_v_ogm_len(skb); |
| 261 | __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb); | 266 | __skb_queue_tail(&hard_iface->bat_v.aggr_list, skb); |
| 267 | |||
| 268 | unlock: | ||
| 262 | spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); | 269 | spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); |
| 263 | } | 270 | } |
| 264 | 271 | ||
| @@ -415,6 +422,10 @@ int batadv_v_ogm_iface_enable(struct batadv_hard_iface *hard_iface) · 150 unmodified lines | |||
| 415 | { | 422 | { |
| 416 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); | 423 | struct batadv_priv *bat_priv = netdev_priv(hard_iface->mesh_iface); |
| 417 | 424 | ||
| 425 | spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); | ||
| 426 | hard_iface->bat_v.aggr_list_enabled = true; | ||
| 427 | spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); | ||
| 428 | |||
| 418 | enable_delayed_work(&hard_iface->bat_v.aggr_wq); | 429 | enable_delayed_work(&hard_iface->bat_v.aggr_wq); |
| 419 | 430 | ||
| 420 | batadv_v_ogm_start_queue_timer(hard_iface); | 431 | batadv_v_ogm_start_queue_timer(hard_iface); |
| @@ -432,6 +443,7 @@ void batadv_v_ogm_iface_disable(struct batadv_hard_iface *hard_iface) · 11 unmodified lines | |||
| 432 | disable_delayed_work_sync(&hard_iface->bat_v.aggr_wq); | 443 | disable_delayed_work_sync(&hard_iface->bat_v.aggr_wq); |
| 433 | 444 | ||
| 434 | spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); | 445 | spin_lock_bh(&hard_iface->bat_v.aggr_list.lock); |
| 446 | hard_iface->bat_v.aggr_list_enabled = false; | ||
| 435 | batadv_v_ogm_aggr_list_free(hard_iface); | 447 | batadv_v_ogm_aggr_list_free(hard_iface); |
| 436 | spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); | 448 | spin_unlock_bh(&hard_iface->bat_v.aggr_list.lock); |
| 437 | } | 449 | } |
| @@ -837,14 +849,23 @@ batadv_v_ogm_aggr_packet(int buff_pos, int packet_len, · 399 unmodified lines | |||
| 837 | const struct batadv_ogm2_packet *ogm2_packet) | 849 | const struct batadv_ogm2_packet *ogm2_packet) |
| 838 | { | 850 | { |
| 839 | int next_buff_pos = 0; | 851 | int next_buff_pos = 0; |
| 852 | u16 tvlv_len; | ||
| 840 | 853 | ||
| 841 | /* check if there is enough space for the header */ | 854 | /* check if there is enough space for the header */ |
| 842 | next_buff_pos += buff_pos + sizeof(*ogm2_packet); | 855 | next_buff_pos += buff_pos + sizeof(*ogm2_packet); |
| 843 | if (next_buff_pos > packet_len) | 856 | if (next_buff_pos > packet_len) |
| 844 | return false; | 857 | return false; |
| 845 | 858 | ||
| 859 | tvlv_len = ntohs(ogm2_packet->tvlv_len); | ||
| 860 | |||
| 861 | /* the fields of an aggregated OGMv2 are accessed assuming (at least) | ||
| 862 | * 2-byte alignment, so a following OGMv2 must start at an even offset. | ||
| 863 | */ | ||
| 864 | if (tvlv_len & 1) | ||
| 865 | return false; | ||
| 866 | |||
| 846 | /* check if there is enough space for the optional TVLV */ | 867 | /* check if there is enough space for the optional TVLV */ |
| 847 | next_buff_pos += ntohs(ogm2_packet->tvlv_len); | 868 | next_buff_pos += tvlv_len; |
| 848 | 869 | ||
| 849 | return next_buff_pos <= packet_len; | 870 | return next_buff_pos <= packet_len; |
| 850 | } | 871 | } |
| @@ -215,10 +215,13 @@ static void batadv_dat_purge(struct work_struct *work) · 214 unmodified lines | |||
| 215 | */ | 215 | */ |
| 216 | static bool batadv_compare_dat(const struct hlist_node *node, const void *data2) | 216 | static bool batadv_compare_dat(const struct hlist_node *node, const void *data2) |
| 217 | { | 217 | { |
| 218 | const void *data1 = container_of(node, struct batadv_dat_entry, | 218 | const struct batadv_dat_entry *entry1; |
| 219 | hash_entry); | 219 | const struct batadv_dat_entry *entry2; |
| 220 | 220 | ||
| 221 | return memcmp(data1, data2, sizeof(__be32)) == 0; | 221 | entry1 = container_of(node, struct batadv_dat_entry, hash_entry); |
| 222 | entry2 = data2; | ||
| 223 | |||
| 224 | return entry1->ip == entry2->ip && entry1->vid == entry2->vid; | ||
| 222 | } | 225 | } |
| 223 | 226 | ||
| 224 | /** | 227 | /** |
| @@ -345,6 +348,9 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, · 120 unmodified lines | |||
| 345 | if (dat_entry->ip != ip) | 348 | if (dat_entry->ip != ip) |
| 346 | continue; | 349 | continue; |
| 347 | 350 | ||
| 351 | if (dat_entry->vid != vid) | ||
| 352 | continue; | ||
| 353 | |||
| 348 | if (!kref_get_unless_zero(&dat_entry->refcount)) | 354 | if (!kref_get_unless_zero(&dat_entry->refcount)) |
| 349 | continue; | 355 | continue; |
| 350 | 356 | ||
| @@ -386,6 +386,8 @@ out_err: · 385 unmodified lines | |||
| 386 | * @skb: skb to forward | 386 | * @skb: skb to forward |
| 387 | * @recv_if: interface that the skb is received on | 387 | * @recv_if: interface that the skb is received on |
| 388 | * @orig_node_src: originator that the skb is received from | 388 | * @orig_node_src: originator that the skb is received from |
| 389 | * @rx_result: set to NET_RX_SUCCESS when the fragment was forwarded and | ||
| 390 | * NET_RX_DROP when it was dropped; only valid when true is returned | ||
| 389 | * | 391 | * |
| 390 | * Look up the next-hop of the fragments payload and check if the merged packet | 392 | * Look up the next-hop of the fragments payload and check if the merged packet |
| 391 | * will exceed the MTU towards the next-hop. If so, the fragment is forwarded | 393 | * will exceed the MTU towards the next-hop. If so, the fragment is forwarded |
| @@ -395,7 +397,8 @@ out_err: · 3 unmodified lines | |||
| 395 | */ | 397 | */ |
| 396 | bool batadv_frag_skb_fwd(struct sk_buff *skb, | 398 | bool batadv_frag_skb_fwd(struct sk_buff *skb, |
| 397 | struct batadv_hard_iface *recv_if, | 399 | struct batadv_hard_iface *recv_if, |
| 398 | struct batadv_orig_node *orig_node_src) | 400 | struct batadv_orig_node *orig_node_src, |
| 401 | int *rx_result) | ||
| 399 | { | 402 | { |
| 400 | struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); | 403 | struct batadv_priv *bat_priv = netdev_priv(recv_if->mesh_iface); |
| 401 | struct batadv_neigh_node *neigh_node = NULL; | 404 | struct batadv_neigh_node *neigh_node = NULL; |
| @@ -414,12 +417,29 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, · 12 unmodified lines | |||
| 414 | */ | 417 | */ |
| 415 | total_size = ntohs(packet->total_size); | 418 | total_size = ntohs(packet->total_size); |
| 416 | if (total_size > neigh_node->if_incoming->net_dev->mtu) { | 419 | if (total_size > neigh_node->if_incoming->net_dev->mtu) { |
| 420 | if (packet->ttl < 2) { | ||
| 421 | kfree_skb(skb); | ||
| 422 | *rx_result = NET_RX_DROP; | ||
| 423 | ret = true; | ||
| 424 | goto out; | ||
| 425 | } | ||
| 426 | |||
| 427 | if (skb_cow(skb, ETH_HLEN) < 0) { | ||
| 428 | kfree_skb(skb); | ||
| 429 | *rx_result = NET_RX_DROP; | ||
| 430 | ret = true; | ||
| 431 | goto out; | ||
| 432 | } | ||
| 433 | |||
| 434 | packet = (struct batadv_frag_packet *)skb->data; | ||
| 435 | |||
| 417 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_FWD); | 436 | batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_FWD); |
| 418 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_FWD_BYTES, | 437 | batadv_add_counter(bat_priv, BATADV_CNT_FRAG_FWD_BYTES, |
| 419 | skb->len + ETH_HLEN); | 438 | skb->len + ETH_HLEN); |
| 420 | 439 | ||
| 421 | packet->ttl--; | 440 | packet->ttl--; |
| 422 | batadv_send_unicast_skb(skb, neigh_node); | 441 | batadv_send_unicast_skb(skb, neigh_node); |
| 442 | *rx_result = NET_RX_SUCCESS; | ||
| 423 | ret = true; | 443 | ret = true; |
| 424 | } | 444 | } |
| 425 | 445 | ||
| @@ -19,7 +19,8 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig, · 18 unmodified lines | |||
| 19 | bool (*check_cb)(struct batadv_frag_table_entry *)); | 19 | bool (*check_cb)(struct batadv_frag_table_entry *)); |
| 20 | bool batadv_frag_skb_fwd(struct sk_buff *skb, | 20 | bool batadv_frag_skb_fwd(struct sk_buff *skb, |
| 21 | struct batadv_hard_iface *recv_if, | 21 | struct batadv_hard_iface *recv_if, |
| 22 | struct batadv_orig_node *orig_node_src); | 22 | struct batadv_orig_node *orig_node_src, |
| 23 | int *rx_result); | ||
| 23 | bool batadv_frag_skb_buffer(struct sk_buff **skb, | 24 | bool batadv_frag_skb_buffer(struct sk_buff **skb, |
| 24 | struct batadv_orig_node *orig_node); | 25 | struct batadv_orig_node *orig_node); |
| 25 | int batadv_frag_send_packet(struct sk_buff *skb, | 26 | int batadv_frag_send_packet(struct sk_buff *skb, |
| @@ -814,30 +814,6 @@ err_dev: · 813 unmodified lines | |||
| 814 | return ret; | 814 | return ret; |
| 815 | } | 815 | } |
| 816 | 816 | ||
| 817 | /** | ||
| 818 | * batadv_hardif_cnt() - get number of interfaces enslaved to mesh interface | ||
| 819 | * @mesh_iface: mesh interface to check | ||
| 820 | * | ||
| 821 | * This function is only using RCU for locking - the result can therefore be | ||
| 822 | * off when another function is modifying the list at the same time. The | ||
| 823 | * caller can use the rtnl_lock to make sure that the count is accurate. | ||
| 824 | * | ||
| 825 | * Return: number of connected/enslaved hard interfaces | ||
| 826 | */ | ||
| 827 | static size_t batadv_hardif_cnt(struct net_device *mesh_iface) | ||
| 828 | { | ||
| 829 | struct batadv_hard_iface *hard_iface; | ||
| 830 | struct list_head *iter; | ||
| 831 | size_t count = 0; | ||
| 832 | |||
| 833 | rcu_read_lock(); | ||
| 834 | netdev_for_each_lower_private_rcu(mesh_iface, hard_iface, iter) | ||
| 835 | count++; | ||
| 836 | rcu_read_unlock(); | ||
| 837 | |||
| 838 | return count; | ||
| 839 | } | ||
| 840 | |||
| 841 | /** | 817 | /** |
| 842 | * batadv_hardif_disable_interface() - Remove hard interface from mesh interface | 818 | * batadv_hardif_disable_interface() - Remove hard interface from mesh interface |
| 843 | * @hard_iface: hard interface to be removed | 819 | * @hard_iface: hard interface to be removed |
| @@ -878,8 +854,8 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface) · 34 unmodified lines | |||
| 878 | netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface); | 854 | netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->mesh_iface); |
| 879 | batadv_hardif_recalc_extra_skbroom(hard_iface->mesh_iface); | 855 | batadv_hardif_recalc_extra_skbroom(hard_iface->mesh_iface); |
| 880 | 856 | ||
| 881 | /* nobody uses this interface anymore */ | 857 | /* nobody uses this mesh interface anymore */ |
| 882 | if (batadv_hardif_cnt(hard_iface->mesh_iface) <= 1) | 858 | if (list_empty(&hard_iface->mesh_iface->adj_list.lower)) |
| 883 | batadv_gw_check_client_stop(bat_priv); | 859 | batadv_gw_check_client_stop(bat_priv); |
| 884 | 860 | ||
| 885 | hard_iface->mesh_iface = NULL; | 861 | hard_iface->mesh_iface = NULL; |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | #include "main.h" | 8 | #include "main.h" |
| 9 | 9 | ||
| 10 | #include <linux/atomic.h> | 10 | #include <linux/atomic.h> |
| 11 | #include <linux/build_bug.h> | ||
| 11 | #include <linux/byteorder/generic.h> | 12 | #include <linux/byteorder/generic.h> |
| 12 | #include <linux/compiler.h> | 13 | #include <linux/compiler.h> |
| 13 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
| @@ -204,6 +205,59 @@ bool batadv_check_management_packet(struct sk_buff *skb, · 190 unmodified lines | |||
| 204 | return true; | 205 | return true; |
| 205 | } | 206 | } |
| 206 | 207 | ||
| 208 | /** | ||
| 209 | * batadv_skb_decrement_ttl() - decrement ttl in a batman-adv header, csum-safe | ||
| 210 | * @skb: the received packet with @skb->data pointing to the batman-adv header | ||
| 211 | * | ||
| 212 | * Supports the following packet types, all of which carry the TTL at offset 2: | ||
| 213 | * | ||
| 214 | * - batadv_ogm_packet | ||
| 215 | * - batadv_ogm2_packet | ||
| 216 | * - batadv_icmp_header | ||
| 217 | * - batadv_icmp_packet | ||
| 218 | * - batadv_icmp_tp_packet | ||
| 219 | * - batadv_icmp_packet_rr | ||
| 220 | * - batadv_unicast_packet | ||
| 221 | * - batadv_frag_packet | ||
| 222 | * - batadv_bcast_packet | ||
| 223 | * - batadv_mcast_packet | ||
| 224 | * - batadv_coded_packet | ||
| 225 | * - batadv_unicast_tvlv_packet | ||
| 226 | * | ||
| 227 | * Return: true if the packet may be forwarded (ttl decremented), | ||
| 228 | * false if it must be dropped (ttl would expire) | ||
| 229 | */ | ||
| 230 | static bool batadv_skb_decrement_ttl(struct sk_buff *skb) | ||
| 231 | { | ||
| 232 | static const size_t ttl_offset = 2; | ||
| 233 | u8 *ttl_pos; | ||
| 234 | |||
| 235 | BUILD_BUG_ON(offsetof(struct batadv_ogm_packet, ttl) != ttl_offset); | ||
| 236 | BUILD_BUG_ON(offsetof(struct batadv_ogm2_packet, ttl) != ttl_offset); | ||
| 237 | BUILD_BUG_ON(offsetof(struct batadv_icmp_header, ttl) != ttl_offset); | ||
| 238 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet, ttl) != ttl_offset); | ||
| 239 | BUILD_BUG_ON(offsetof(struct batadv_icmp_tp_packet, ttl) != ttl_offset); | ||
| 240 | BUILD_BUG_ON(offsetof(struct batadv_icmp_packet_rr, ttl) != ttl_offset); | ||
| 241 | BUILD_BUG_ON(offsetof(struct batadv_unicast_packet, ttl) != ttl_offset); | ||
| 242 | BUILD_BUG_ON(offsetof(struct batadv_frag_packet, ttl) != ttl_offset); | ||
| 243 | BUILD_BUG_ON(offsetof(struct batadv_bcast_packet, ttl) != ttl_offset); | ||
| 244 | BUILD_BUG_ON(offsetof(struct batadv_mcast_packet, ttl) != ttl_offset); | ||
| 245 | BUILD_BUG_ON(offsetof(struct batadv_coded_packet, ttl) != ttl_offset); | ||
| 246 | BUILD_BUG_ON(offsetof(struct batadv_unicast_tvlv_packet, ttl) != ttl_offset); | ||
| 247 | |||
| 248 | ttl_pos = skb->data + ttl_offset; | ||
| 249 | |||
| 250 | /* would expire on this hop -> drop, leave header + csum untouched */ | ||
| 251 | if (*ttl_pos < 2) | ||
| 252 | return false; | ||
| 253 | |||
| 254 | skb_postpull_rcsum(skb, ttl_pos, 1); | ||
| 255 | (*ttl_pos)--; | ||
| 256 | skb_postpush_rcsum(skb, ttl_pos, 1); | ||
| 257 | |||
| 258 | return true; | ||
| 259 | } | ||
| 260 | |||
| 207 | /** | 261 | /** |
| 208 | * batadv_recv_my_icmp_packet() - receive an icmp packet locally | 262 | * batadv_recv_my_icmp_packet() - receive an icmp packet locally |
| 209 | * @bat_priv: the bat priv with all the mesh interface information | 263 | * @bat_priv: the bat priv with all the mesh interface information |
| @@ -1114,10 +1168,9 @@ int batadv_recv_frag_packet(struct sk_buff *skb, · 904 unmodified lines | |||
| 1114 | 1168 | ||
| 1115 | /* Route the fragment if it is not for us and too big to be merged. */ | 1169 | /* Route the fragment if it is not for us and too big to be merged. */ |
| 1116 | if (!batadv_is_my_mac(bat_priv, frag_packet->dest) && | 1170 | if (!batadv_is_my_mac(bat_priv, frag_packet->dest) && |
| 1117 | batadv_frag_skb_fwd(skb, recv_if, orig_node_src)) { | 1171 | batadv_frag_skb_fwd(skb, recv_if, orig_node_src, &ret)) { |
| 1118 | /* skb was consumed */ | 1172 | /* skb was consumed */ |
| 1119 | skb = NULL; | 1173 | skb = NULL; |
| 1120 | ret = NET_RX_SUCCESS; | ||
| 1121 | goto put_orig_node; | 1174 | goto put_orig_node; |
| 1122 | } | 1175 | } |
| 1123 | 1176 | ||
| @@ -1191,7 +1244,13 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, · 67 unmodified lines | |||
| 1191 | if (batadv_is_my_mac(bat_priv, bcast_packet->orig)) | 1244 | if (batadv_is_my_mac(bat_priv, bcast_packet->orig)) |
| 1192 | goto free_skb; | 1245 | goto free_skb; |
| 1193 | 1246 | ||
| 1194 | if (bcast_packet->ttl-- < 2) | 1247 | /* create a copy of the skb, if needed, to modify it. */ |
| 1248 | if (skb_cow(skb, ETH_HLEN) < 0) | ||
| 1249 | goto free_skb; | ||
| 1250 | |||
| 1251 | bcast_packet = (struct batadv_bcast_packet *)skb->data; | ||
| 1252 | |||
| 1253 | if (!batadv_skb_decrement_ttl(skb)) | ||
| 1195 | goto free_skb; | 1254 | goto free_skb; |
| 1196 | 1255 | ||
| 1197 | orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig); | 1256 | orig_node = batadv_orig_hash_find(bat_priv, bcast_packet->orig); |
| @@ -1298,7 +1357,7 @@ int batadv_recv_mcast_packet(struct sk_buff *skb, · 100 unmodified lines | |||
| 1298 | goto free_skb; | 1357 | goto free_skb; |
| 1299 | 1358 | ||
| 1300 | mcast_packet = (struct batadv_mcast_packet *)skb->data; | 1359 | mcast_packet = (struct batadv_mcast_packet *)skb->data; |
| 1301 | if (mcast_packet->ttl-- < 2) | 1360 | if (!batadv_skb_decrement_ttl(skb)) |
| 1302 | goto free_skb; | 1361 | goto free_skb; |
| 1303 | 1362 | ||
| 1304 | tvlv_buff = (unsigned char *)(skb->data + hdr_size); | 1363 | tvlv_buff = (unsigned char *)(skb->data + hdr_size); |
| @@ -1307,6 +1366,12 @@ int batadv_recv_mcast_packet(struct sk_buff *skb, · 2 unmodified lines | |||
| 1307 | if (tvlv_buff_len > skb->len - hdr_size) | 1366 | if (tvlv_buff_len > skb->len - hdr_size) |
| 1308 | goto free_skb; | 1367 | goto free_skb; |
| 1309 | 1368 | ||
| 1369 | /* the fields of an multicast payload are accessed assuming (at least) | ||
| 1370 | * 2-byte alignment, so a following packet must start at an even offset. | ||
| 1371 | */ | ||
| 1372 | if (tvlv_buff_len & 1) | ||
| 1373 | goto free_skb; | ||
| 1374 | |||
| 1310 | ret = batadv_tvlv_containers_process(bat_priv, BATADV_MCAST, NULL, skb, | 1375 | ret = batadv_tvlv_containers_process(bat_priv, BATADV_MCAST, NULL, skb, |
| 1311 | tvlv_buff, tvlv_buff_len); | 1376 | tvlv_buff, tvlv_buff_len); |
| 1312 | if (ret >= 0) { | 1377 | if (ret >= 0) { |
| @@ -87,6 +87,11 @@ · 86 unmodified lines | |||
| 87 | #define BATADV_TP_PLEN (BATADV_TP_PACKET_LEN - ETH_HLEN - \ | 87 | #define BATADV_TP_PLEN (BATADV_TP_PACKET_LEN - ETH_HLEN - \ |
| 88 | sizeof(struct batadv_unicast_packet)) | 88 | sizeof(struct batadv_unicast_packet)) |
| 89 | 89 | ||
| 90 | /** | ||
| 91 | * BATADV_TP_MAX_UNACKED - maximum number of packets a receiver didn't yet ack | ||
| 92 | */ | ||
| 93 | #define BATADV_TP_MAX_UNACKED 100 | ||
| 94 | |||
| 90 | static u8 batadv_tp_prerandom[4096] __read_mostly; | 95 | static u8 batadv_tp_prerandom[4096] __read_mostly; |
| 91 | 96 | ||
| 92 | /** | 97 | /** |
| @@ -1285,7 +1290,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t) · 1192 unmodified lines | |||
| 1285 | bat_priv = tp_vars->common.bat_priv; | 1290 | bat_priv = tp_vars->common.bat_priv; |
| 1286 | 1291 | ||
| 1287 | /* if there is recent activity rearm the timer */ | 1292 | /* if there is recent activity rearm the timer */ |
| 1288 | if (!batadv_has_timed_out(tp_vars->last_recv_time, | 1293 | if (!batadv_has_timed_out(READ_ONCE(tp_vars->last_recv_time), |
| 1289 | BATADV_TP_RECV_TIMEOUT)) { | 1294 | BATADV_TP_RECV_TIMEOUT)) { |
| 1290 | /* reset the receiver shutdown timer */ | 1295 | /* reset the receiver shutdown timer */ |
| 1291 | batadv_tp_reset_receiver_timer(tp_vars); | 1296 | batadv_tp_reset_receiver_timer(tp_vars); |
| @@ -1303,6 +1308,7 @@ static void batadv_tp_receiver_shutdown(struct timer_list *t) · 11 unmodified lines | |||
| 1303 | list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { | 1308 | list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { |
| 1304 | list_del(&un->list); | 1309 | list_del(&un->list); |
| 1305 | kfree(un); | 1310 | kfree(un); |
| 1311 | tp_vars->common.unacked_count--; | ||
| 1306 | } | 1312 | } |
| 1307 | spin_unlock_bh(&tp_vars->common.unacked_lock); | 1313 | spin_unlock_bh(&tp_vars->common.unacked_lock); |
| 1308 | 1314 | ||
| @@ -1386,7 +1392,8 @@ out: · 77 unmodified lines | |||
| 1386 | /** | 1392 | /** |
| 1387 | * batadv_tp_handle_out_of_order() - store an out of order packet | 1393 | * batadv_tp_handle_out_of_order() - store an out of order packet |
| 1388 | * @tp_vars: the private data of the current TP meter session | 1394 | * @tp_vars: the private data of the current TP meter session |
| 1389 | * @skb: the buffer containing the received packet | 1395 | * @seqno: sequence number of new received packet |
| 1396 | * @payload_len: length of the received packet | ||
| 1390 | * | 1397 | * |
| 1391 | * Store the out of order packet in the unacked list for late processing. This | 1398 | * Store the out of order packet in the unacked list for late processing. This |
| 1392 | * packets are kept in this list so that they can be ACKed at once as soon as | 1399 | * packets are kept in this list so that they can be ACKed at once as soon as |
| @@ -1395,28 +1402,24 @@ out: · 2 unmodified lines | |||
| 1395 | * Return: true if the packed has been successfully processed, false otherwise | 1402 | * Return: true if the packed has been successfully processed, false otherwise |
| 1396 | */ | 1403 | */ |
| 1397 | static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars, | 1404 | static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars, |
| 1398 | const struct sk_buff *skb) | 1405 | u32 seqno, u32 payload_len) |
| 1406 | __must_hold(&tp_vars->common.unacked_lock) | ||
| 1399 | { | 1407 | { |
| 1400 | const struct batadv_icmp_tp_packet *icmp; | ||
| 1401 | struct batadv_tp_unacked *un, *new; | 1408 | struct batadv_tp_unacked *un, *new; |
| 1402 | u32 payload_len; | ||
| 1403 | bool added = false; | 1409 | bool added = false; |
| 1404 | 1410 | ||
| 1405 | new = kmalloc_obj(*new, GFP_ATOMIC); | 1411 | new = kmalloc_obj(*new, GFP_ATOMIC); |
| 1406 | if (unlikely(!new)) | 1412 | if (unlikely(!new)) |
| 1407 | return false; | 1413 | return false; |
| 1408 | 1414 | ||
| 1409 | icmp = (struct batadv_icmp_tp_packet *)skb->data; | 1415 | new->seqno = seqno; |
| 1410 | |||
| 1411 | new->seqno = ntohl(icmp->seqno); | ||
| 1412 | payload_len = skb->len - sizeof(struct batadv_unicast_packet); | ||
| 1413 | new->len = payload_len; | 1416 | new->len = payload_len; |
| 1414 | 1417 | ||
| 1415 | spin_lock_bh(&tp_vars->common.unacked_lock); | ||
| 1416 | /* if the list is empty immediately attach this new object */ | 1418 | /* if the list is empty immediately attach this new object */ |
| 1417 | if (list_empty(&tp_vars->common.unacked_list)) { | 1419 | if (list_empty(&tp_vars->common.unacked_list)) { |
| 1418 | list_add(&new->list, &tp_vars->common.unacked_list); | 1420 | list_add(&new->list, &tp_vars->common.unacked_list); |
| 1419 | goto out; | 1421 | tp_vars->common.unacked_count++; |
| 1422 | return true; | ||
| 1420 | } | 1423 | } |
| 1421 | 1424 | ||
| 1422 | /* otherwise loop over the list and either drop the packet because this | 1425 | /* otherwise loop over the list and either drop the packet because this |
| @@ -1446,15 +1449,24 @@ static bool batadv_tp_handle_out_of_order(struct batadv_tp_receiver *tp_vars, · 23 unmodified lines | |||
| 1446 | */ | 1449 | */ |
| 1447 | list_add(&new->list, &un->list); | 1450 | list_add(&new->list, &un->list); |
| 1448 | added = true; | 1451 | added = true; |
| 1452 | tp_vars->common.unacked_count++; | ||
| 1449 | break; | 1453 | break; |
| 1450 | } | 1454 | } |
| 1451 | 1455 | ||
| 1452 | /* received packet with smallest seqno out of order; add it to front */ | 1456 | /* received packet with smallest seqno out of order; add it to front */ |
| 1453 | if (!added) | 1457 | if (!added) { |
| 1454 | list_add(&new->list, &tp_vars->common.unacked_list); | 1458 | list_add(&new->list, &tp_vars->common.unacked_list); |
| 1459 | tp_vars->common.unacked_count++; | ||
| 1460 | } | ||
| 1455 | 1461 | ||
| 1456 | out: | 1462 | /* remove the last (biggest) unacked seqno when list is too large */ |
| 1457 | spin_unlock_bh(&tp_vars->common.unacked_lock); | 1463 | if (tp_vars->common.unacked_count > BATADV_TP_MAX_UNACKED) { |
| 1464 | un = list_last_entry(&tp_vars->common.unacked_list, | ||
| 1465 | struct batadv_tp_unacked, list); | ||
| 1466 | list_del(&un->list); | ||
| 1467 | kfree(un); | ||
| 1468 | tp_vars->common.unacked_count--; | ||
| 1469 | } | ||
| 1458 | 1470 | ||
| 1459 | return true; | 1471 | return true; |
| 1460 | } | 1472 | } |
| @@ -1465,6 +1477,7 @@ out: · 4 unmodified lines | |||
| 1465 | * @tp_vars: the private data of the current TP meter session | 1477 | * @tp_vars: the private data of the current TP meter session |
| 1466 | */ | 1478 | */ |
| 1467 | static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) | 1479 | static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) |
| 1480 | __must_hold(&tp_vars->common.unacked_lock) | ||
| 1468 | { | 1481 | { |
| 1469 | struct batadv_tp_unacked *un, *safe; | 1482 | struct batadv_tp_unacked *un, *safe; |
| 1470 | u32 to_ack; | 1483 | u32 to_ack; |
| @@ -1472,7 +1485,6 @@ static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) · 1 unmodified line | |||
| 1472 | /* go through the unacked packet list and possibly ACK them as | 1485 | /* go through the unacked packet list and possibly ACK them as |
| 1473 | * well | 1486 | * well |
| 1474 | */ | 1487 | */ |
| 1475 | spin_lock_bh(&tp_vars->common.unacked_lock); | ||
| 1476 | list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { | 1488 | list_for_each_entry_safe(un, safe, &tp_vars->common.unacked_list, list) { |
| 1477 | /* the list is ordered, therefore it is possible to stop as soon | 1489 | /* the list is ordered, therefore it is possible to stop as soon |
| 1478 | * there is a gap between the last acked seqno and the seqno of | 1490 | * there is a gap between the last acked seqno and the seqno of |
| @@ -1488,8 +1500,8 @@ static void batadv_tp_ack_unordered(struct batadv_tp_receiver *tp_vars) · 9 unmodified lines | |||
| 1488 | 1500 | ||
| 1489 | list_del(&un->list); | 1501 | list_del(&un->list); |
| 1490 | kfree(un); | 1502 | kfree(un); |
| 1503 | tp_vars->common.unacked_count--; | ||
| 1491 | } | 1504 | } |
| 1492 | spin_unlock_bh(&tp_vars->common.unacked_lock); | ||
| 1493 | } | 1505 | } |
| 1494 | 1506 | ||
| 1495 | /** | 1507 | /** |
| @@ -1512,7 +1524,7 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, · 16 unmodified lines | |||
| 1512 | tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig, | 1524 | tp_vars = batadv_tp_list_find_receiver_session(bat_priv, icmp->orig, |
| 1513 | icmp->session); | 1525 | icmp->session); |
| 1514 | if (tp_vars) { | 1526 | if (tp_vars) { |
| 1515 | tp_vars->last_recv_time = jiffies; | 1527 | WRITE_ONCE(tp_vars->last_recv_time, jiffies); |
| 1516 | goto out_unlock; | 1528 | goto out_unlock; |
| 1517 | } | 1529 | } |
| 1518 | 1530 | ||
| @@ -1537,11 +1549,12 @@ batadv_tp_init_recv(struct batadv_priv *bat_priv, · 18 unmodified lines | |||
| 1537 | 1549 | ||
| 1538 | spin_lock_init(&tp_vars->common.unacked_lock); | 1550 | spin_lock_init(&tp_vars->common.unacked_lock); |
| 1539 | INIT_LIST_HEAD(&tp_vars->common.unacked_list); | 1551 | INIT_LIST_HEAD(&tp_vars->common.unacked_list); |
| 1552 | tp_vars->common.unacked_count = 0; | ||
| 1540 | 1553 | ||
| 1541 | kref_get(&tp_vars->common.refcount); | 1554 | kref_get(&tp_vars->common.refcount); |
| 1542 | timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0); | 1555 | timer_setup(&tp_vars->common.timer, batadv_tp_receiver_shutdown, 0); |
| 1543 | 1556 | ||
| 1544 | tp_vars->last_recv_time = jiffies; | 1557 | WRITE_ONCE(tp_vars->last_recv_time, jiffies); |
| 1545 | 1558 | ||
| 1546 | kref_get(&tp_vars->common.refcount); | 1559 | kref_get(&tp_vars->common.refcount); |
| 1547 | hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list); | 1560 | hlist_add_head_rcu(&tp_vars->common.list, &bat_priv->tp_receiver_list); |
| @@ -1566,7 +1579,8 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, · 18 unmodified lines | |||
| 1566 | { | 1579 | { |
| 1567 | const struct batadv_icmp_tp_packet *icmp; | 1580 | const struct batadv_icmp_tp_packet *icmp; |
| 1568 | struct batadv_tp_receiver *tp_vars; | 1581 | struct batadv_tp_receiver *tp_vars; |
| 1569 | size_t packet_size; | 1582 | u32 payload_len; |
| 1583 | u32 to_ack; | ||
| 1570 | u32 seqno; | 1584 | u32 seqno; |
| 1571 | 1585 | ||
| 1572 | icmp = (struct batadv_icmp_tp_packet *)skb->data; | 1586 | icmp = (struct batadv_icmp_tp_packet *)skb->data; |
| @@ -1592,40 +1606,48 @@ static void batadv_tp_recv_msg(struct batadv_priv *bat_priv, · 19 unmodified lines | |||
| 1592 | goto out; | 1606 | goto out; |
| 1593 | } | 1607 | } |
| 1594 | 1608 | ||
| 1595 | tp_vars->last_recv_time = jiffies; | 1609 | WRITE_ONCE(tp_vars->last_recv_time, jiffies); |
| 1596 | } | 1610 | } |
| 1597 | 1611 | ||
| 1612 | spin_lock_bh(&tp_vars->common.unacked_lock); | ||
| 1613 | |||
| 1598 | /* if the packet is a duplicate, it may be the case that an ACK has been | 1614 | /* if the packet is a duplicate, it may be the case that an ACK has been |
| 1599 | * lost. Resend the ACK | 1615 | * lost. Resend the ACK |
| 1600 | */ | 1616 | */ |
| 1601 | if (batadv_seq_before(seqno, tp_vars->last_recv)) | 1617 | payload_len = skb->len - sizeof(struct batadv_unicast_packet); |
| 1618 | to_ack = seqno + payload_len; | ||
| 1619 | if (batadv_seq_before(to_ack, tp_vars->last_recv)) | ||
| 1602 | goto send_ack; | 1620 | goto send_ack; |
| 1603 | 1621 | ||
| 1604 | /* if the packet is out of order enqueue it */ | 1622 | /* if the packet is out of order enqueue it */ |
| 1605 | if (ntohl(icmp->seqno) != tp_vars->last_recv) { | 1623 | if (batadv_seq_before(tp_vars->last_recv, seqno)) { |
| 1606 | /* exit immediately (and do not send any ACK) if the packet has | 1624 | /* exit immediately (and do not send any ACK) if the packet has |
| 1607 | * not been enqueued correctly | 1625 | * not been enqueued correctly |
| 1608 | */ | 1626 | */ |
| 1609 | if (!batadv_tp_handle_out_of_order(tp_vars, skb)) | 1627 | if (!batadv_tp_handle_out_of_order(tp_vars, seqno, payload_len)) { |
| 1628 | spin_unlock_bh(&tp_vars->common.unacked_lock); | ||
| 1610 | goto out; | 1629 | goto out; |
| 1630 | } | ||
| 1611 | 1631 | ||
| 1612 | /* send a duplicate ACK */ | 1632 | /* send a duplicate ACK */ |
| 1613 | goto send_ack; | 1633 | goto send_ack; |
| 1614 | } | 1634 | } |
| 1615 | 1635 | ||
| 1616 | /* if everything was fine count the ACKed bytes */ | 1636 | /* if everything was fine count the ACKed bytes */ |
| 1617 | packet_size = skb->len - sizeof(struct batadv_unicast_packet); | 1637 | tp_vars->last_recv = to_ack; |
| 1618 | tp_vars->last_recv += packet_size; | ||
| 1619 | 1638 | ||
| 1620 | /* check if this ordered message filled a gap.... */ | 1639 | /* check if this ordered message filled a gap.... */ |
| 1621 | batadv_tp_ack_unordered(tp_vars); | 1640 | batadv_tp_ack_unordered(tp_vars); |
| 1622 | 1641 | ||
| 1623 | send_ack: | 1642 | send_ack: |
| 1643 | to_ack = tp_vars->last_recv; | ||
| 1644 | spin_unlock_bh(&tp_vars->common.unacked_lock); | ||
| 1645 | |||
| 1624 | /* send the ACK. If the received packet was out of order, the ACK that | 1646 | /* send the ACK. If the received packet was out of order, the ACK that |
| 1625 | * is going to be sent is a duplicate (the sender will count them and | 1647 | * is going to be sent is a duplicate (the sender will count them and |
| 1626 | * possibly enter Fast Retransmit as soon as it has reached 3) | 1648 | * possibly enter Fast Retransmit as soon as it has reached 3) |
| 1627 | */ | 1649 | */ |
| 1628 | batadv_tp_send_ack(bat_priv, icmp->orig, tp_vars->last_recv, | 1650 | batadv_tp_send_ack(bat_priv, icmp->orig, to_ack, |
| 1629 | icmp->timestamp, icmp->session, icmp->uid); | 1651 | icmp->timestamp, icmp->session, icmp->uid); |
| 1630 | out: | 1652 | out: |
| 1631 | batadv_tp_receiver_put(tp_vars); | 1653 | batadv_tp_receiver_put(tp_vars); |
| @@ -447,6 +447,9 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv, · 446 unmodified lines | |||
| 447 | if (!batadv_compare_eth(entry->change.addr, common->addr)) | 447 | if (!batadv_compare_eth(entry->change.addr, common->addr)) |
| 448 | continue; | 448 | continue; |
| 449 | 449 | ||
| 450 | if (entry->change.vid != tt_change_node->change.vid) | ||
| 451 | continue; | ||
| 452 | |||
| 450 | del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; | 453 | del_op_entry = entry->change.flags & BATADV_TT_CLIENT_DEL; |
| 451 | if (del_op_requested != del_op_entry) { | 454 | if (del_op_requested != del_op_entry) { |
| 452 | /* DEL+ADD in the same orig interval have no effect and | 455 | /* DEL+ADD in the same orig interval have no effect and |
| @@ -3447,6 +3450,7 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) · 2994 unmodified lines | |||
| 3447 | * batadv_tt_check_roam_count() - check if a client has roamed too frequently | 3450 | * batadv_tt_check_roam_count() - check if a client has roamed too frequently |
| 3448 | * @bat_priv: the bat priv with all the mesh interface information | 3451 | * @bat_priv: the bat priv with all the mesh interface information |
| 3449 | * @client: mac address of the roaming client | 3452 | * @client: mac address of the roaming client |
| 3453 | * @vid: VLAN identifier | ||
| 3450 | * | 3454 | * |
| 3451 | * This function checks whether the client already reached the | 3455 | * This function checks whether the client already reached the |
| 3452 | * maximum number of possible roaming phases. In this case the ROAMING_ADV | 3456 | * maximum number of possible roaming phases. In this case the ROAMING_ADV |
| @@ -3454,7 +3458,7 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) · 1 unmodified line | |||
| 3454 | * | 3458 | * |
| 3455 | * Return: true if the ROAMING_ADV can be sent, false otherwise | 3459 | * Return: true if the ROAMING_ADV can be sent, false otherwise |
| 3456 | */ | 3460 | */ |
| 3457 | static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) | 3461 | static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client, u16 vid) |
| 3458 | { | 3462 | { |
| 3459 | struct batadv_tt_roam_node *tt_roam_node; | 3463 | struct batadv_tt_roam_node *tt_roam_node; |
| 3460 | bool ret = false; | 3464 | bool ret = false; |
| @@ -3467,6 +3471,9 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) · 6 unmodified lines | |||
| 3467 | if (!batadv_compare_eth(tt_roam_node->addr, client)) | 3471 | if (!batadv_compare_eth(tt_roam_node->addr, client)) |
| 3468 | continue; | 3472 | continue; |
| 3469 | 3473 | ||
| 3474 | if (tt_roam_node->vid != vid) | ||
| 3475 | continue; | ||
| 3476 | |||
| 3470 | if (batadv_has_timed_out(tt_roam_node->first_time, | 3477 | if (batadv_has_timed_out(tt_roam_node->first_time, |
| 3471 | BATADV_ROAMING_MAX_TIME)) | 3478 | BATADV_ROAMING_MAX_TIME)) |
| 3472 | continue; | 3479 | continue; |
| @@ -3488,6 +3495,7 @@ static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) · 15 unmodified lines | |||
| 3488 | atomic_set(&tt_roam_node->counter, | 3495 | atomic_set(&tt_roam_node->counter, |
| 3489 | BATADV_ROAMING_MAX_COUNT - 1); | 3496 | BATADV_ROAMING_MAX_COUNT - 1); |
| 3490 | ether_addr_copy(tt_roam_node->addr, client); | 3497 | ether_addr_copy(tt_roam_node->addr, client); |
| 3498 | tt_roam_node->vid = vid; | ||
| 3491 | 3499 | ||
| 3492 | list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); | 3500 | list_add(&tt_roam_node->list, &bat_priv->tt.roam_list); |
| 3493 | ret = true; | 3501 | ret = true; |
| @@ -3524,7 +3532,7 @@ static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, · 30 unmodified lines | |||
| 3524 | /* before going on we have to check whether the client has | 3532 | /* before going on we have to check whether the client has |
| 3525 | * already roamed to us too many times | 3533 | * already roamed to us too many times |
| 3526 | */ | 3534 | */ |
| 3527 | if (!batadv_tt_check_roam_count(bat_priv, client)) | 3535 | if (!batadv_tt_check_roam_count(bat_priv, client, vid)) |
| 3528 | goto out; | 3536 | goto out; |
| 3529 | 3537 | ||
| 3530 | batadv_dbg(BATADV_DBG_TT, bat_priv, | 3538 | batadv_dbg(BATADV_DBG_TT, bat_priv, |
| @@ -411,7 +411,6 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, · 410 unmodified lines | |||
| 411 | tvlv_handler->ogm_handler(bat_priv, orig_node, | 411 | tvlv_handler->ogm_handler(bat_priv, orig_node, |
| 412 | BATADV_NO_FLAGS, | 412 | BATADV_NO_FLAGS, |
| 413 | tvlv_value, tvlv_value_len); | 413 | tvlv_value, tvlv_value_len); |
| 414 | tvlv_handler->flags |= BATADV_TVLV_HANDLER_OGM_CALLED; | ||
| 415 | break; | 414 | break; |
| 416 | case BATADV_UNICAST_TVLV: | 415 | case BATADV_UNICAST_TVLV: |
| 417 | if (!skb) | 416 | if (!skb) |
| @@ -443,6 +442,48 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, · 25 unmodified lines | |||
| 443 | return NET_RX_SUCCESS; | 442 | return NET_RX_SUCCESS; |
| 444 | } | 443 | } |
| 445 | 444 | ||
| 445 | /** | ||
| 446 | * batadv_tvlv_containers_contain() - check if a tvlv buffer holds a container | ||
| 447 | * @tvlv_value: tvlv content | ||
| 448 | * @tvlv_value_len: tvlv content length | ||
| 449 | * @type: tvlv container type to look for | ||
| 450 | * @version: tvlv container version to look for | ||
| 451 | * | ||
| 452 | * Return: true if a container of the given type and version is present in the | ||
| 453 | * tvlv buffer, false otherwise. | ||
| 454 | */ | ||
| 455 | static bool batadv_tvlv_containers_contain(void *tvlv_value, | ||
| 456 | u16 tvlv_value_len, u8 type, | ||
| 457 | u8 version) | ||
| 458 | { | ||
| 459 | struct batadv_tvlv_hdr *tvlv_hdr; | ||
| 460 | u16 tvlv_value_cont_len; | ||
| 461 | |||
| 462 | while (tvlv_value_len >= sizeof(*tvlv_hdr)) { | ||
| 463 | tvlv_hdr = tvlv_value; | ||
| 464 | tvlv_value_cont_len = ntohs(tvlv_hdr->len); | ||
| 465 | tvlv_value = tvlv_hdr + 1; | ||
| 466 | tvlv_value_len -= sizeof(*tvlv_hdr); | ||
| 467 | |||
| 468 | if (tvlv_value_cont_len > tvlv_value_len) | ||
| 469 | break; | ||
| 470 | |||
| 471 | /* the next tvlv header is accessed assuming (at least) 2-byte | ||
| 472 | * alignment, so it must start at an even offset. | ||
| 473 | */ | ||
| 474 | if (tvlv_value_cont_len & 1) | ||
| 475 | break; | ||
| 476 | |||
| 477 | if (tvlv_hdr->type == type && tvlv_hdr->version == version) | ||
| 478 | return true; | ||
| 479 | |||
| 480 | tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len; | ||
| 481 | tvlv_value_len -= tvlv_value_cont_len; | ||
| 482 | } | ||
| 483 | |||
| 484 | return false; | ||
| 485 | } | ||
| 486 | |||
| 446 | /** | 487 | /** |
| 447 | * batadv_tvlv_containers_process() - parse the given tvlv buffer to call the | 488 | * batadv_tvlv_containers_process() - parse the given tvlv buffer to call the |
| 448 | * appropriate handlers | 489 | * appropriate handlers |
| @@ -462,7 +503,9 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, · 13 unmodified lines | |||
| 462 | struct sk_buff *skb, void *tvlv_value, | 503 | struct sk_buff *skb, void *tvlv_value, |
| 463 | u16 tvlv_value_len) | 504 | u16 tvlv_value_len) |
| 464 | { | 505 | { |
| 506 | u16 tvlv_value_start_len = tvlv_value_len; | ||
| 465 | struct batadv_tvlv_handler *tvlv_handler; | 507 | struct batadv_tvlv_handler *tvlv_handler; |
| 508 | void *tvlv_value_start = tvlv_value; | ||
| 466 | struct batadv_tvlv_hdr *tvlv_hdr; | 509 | struct batadv_tvlv_hdr *tvlv_hdr; |
| 467 | u16 tvlv_value_cont_len; | 510 | u16 tvlv_value_cont_len; |
| 468 | u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; | 511 | u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; |
| @@ -477,6 +520,12 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, · 8 unmodified lines | |||
| 477 | if (tvlv_value_cont_len > tvlv_value_len) | 520 | if (tvlv_value_cont_len > tvlv_value_len) |
| 478 | break; | 521 | break; |
| 479 | 522 | ||
| 523 | /* the next tvlv header is accessed assuming (at least) 2-byte | ||
| 524 | * alignment, so it must start at an even offset. | ||
| 525 | */ | ||
| 526 | if (tvlv_value_cont_len & 1) | ||
| 527 | break; | ||
| 528 | |||
| 480 | tvlv_handler = batadv_tvlv_handler_get(bat_priv, | 529 | tvlv_handler = batadv_tvlv_handler_get(bat_priv, |
| 481 | tvlv_hdr->type, | 530 | tvlv_hdr->type, |
| 482 | tvlv_hdr->version); | 531 | tvlv_hdr->version); |
| @@ -500,12 +549,20 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, · 17 unmodified lines | |||
| 500 | if (!tvlv_handler->ogm_handler) | 549 | if (!tvlv_handler->ogm_handler) |
| 501 | continue; | 550 | continue; |
| 502 | 551 | ||
| 503 | if ((tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) && | 552 | if (!(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND)) |
| 504 | !(tvlv_handler->flags & BATADV_TVLV_HANDLER_OGM_CALLED)) | 553 | continue; |
| 505 | tvlv_handler->ogm_handler(bat_priv, orig_node, | 554 | |
| 506 | cifnotfound, NULL, 0); | 555 | /* if the corresponding container was present then the handler |
| 556 | * was already called from the loop above | ||
| 557 | */ | ||
| 558 | if (batadv_tvlv_containers_contain(tvlv_value_start, | ||
| 559 | tvlv_value_start_len, | ||
| 560 | tvlv_handler->type, | ||
| 561 | tvlv_handler->version)) | ||
| 562 | continue; | ||
| 507 | 563 | ||
| 508 | tvlv_handler->flags &= ~BATADV_TVLV_HANDLER_OGM_CALLED; | 564 | tvlv_handler->ogm_handler(bat_priv, orig_node, |
| 565 | cifnotfound, NULL, 0); | ||
| 509 | } | 566 | } |
| 510 | rcu_read_unlock(); | 567 | rcu_read_unlock(); |
| 511 | 568 | ||
| @@ -145,6 +145,12 @@ struct batadv_hard_iface_bat_v { · 144 unmodified lines | |||
| 145 | /** @aggr_list: queue for to be aggregated OGM packets */ | 145 | /** @aggr_list: queue for to be aggregated OGM packets */ |
| 146 | struct sk_buff_head aggr_list; | 146 | struct sk_buff_head aggr_list; |
| 147 | 147 | ||
| 148 | /** | ||
| 149 | * @aggr_list_enabled: aggr_list is active and new skbs can be | ||
| 150 | * enqueued. Protected by aggr_list.lock after initialization | ||
| 151 | */ | ||
| 152 | bool aggr_list_enabled:1; | ||
| 153 | |||
| 148 | /** @aggr_len: size of the OGM aggregate (excluding ethernet header) */ | 154 | /** @aggr_len: size of the OGM aggregate (excluding ethernet header) */ |
| 149 | unsigned int aggr_len; | 155 | unsigned int aggr_len; |
| 150 | 156 | ||
| @@ -1357,9 +1363,12 @@ struct batadv_tp_vars_common { · 1206 unmodified lines | |||
| 1357 | /** @unacked_list: list of unacked packets (meta-info only) */ | 1363 | /** @unacked_list: list of unacked packets (meta-info only) */ |
| 1358 | struct list_head unacked_list; | 1364 | struct list_head unacked_list; |
| 1359 | 1365 | ||
| 1360 | /** @unacked_lock: protect unacked_list */ | 1366 | /** @unacked_lock: protect unacked_list + &batadv_tp_receiver.last_recv */ |
| 1361 | spinlock_t unacked_lock; | 1367 | spinlock_t unacked_lock; |
| 1362 | 1368 | ||
| 1369 | /** @unacked_count: number of unacked entries */ | ||
| 1370 | size_t unacked_count; | ||
| 1371 | |||
| 1363 | /** @refcount: number of context where the object is used */ | 1372 | /** @refcount: number of context where the object is used */ |
| 1364 | struct kref refcount; | 1373 | struct kref refcount; |
| 1365 | 1374 | ||
| @@ -1952,6 +1961,9 @@ struct batadv_tt_roam_node { · 586 unmodified lines | |||
| 1952 | /** @addr: mac address of the client in the roaming phase */ | 1961 | /** @addr: mac address of the client in the roaming phase */ |
| 1953 | u8 addr[ETH_ALEN]; | 1962 | u8 addr[ETH_ALEN]; |
| 1954 | 1963 | ||
| 1964 | /** @vid: VLAN identifier */ | ||
| 1965 | u16 vid; | ||
| 1966 | |||
| 1955 | /** | 1967 | /** |
| 1956 | * @counter: number of allowed roaming events per client within a single | 1968 | * @counter: number of allowed roaming events per client within a single |
| 1957 | * OGM interval (changes are committed with each OGM) | 1969 | * OGM interval (changes are committed with each OGM) |
| @@ -2282,13 +2294,6 @@ enum batadv_tvlv_handler_flags { · 324 unmodified lines | |||
| 2282 | * will call this handler even if its type was not found (with no data) | 2294 | * will call this handler even if its type was not found (with no data) |
| 2283 | */ | 2295 | */ |
| 2284 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), | 2296 | BATADV_TVLV_HANDLER_OGM_CIFNOTFND = BIT(1), |
| 2285 | |||
| 2286 | /** | ||
| 2287 | * @BATADV_TVLV_HANDLER_OGM_CALLED: interval tvlv handling flag - the | ||
| 2288 | * API marks a handler as being called, so it won't be called if the | ||
| 2289 | * BATADV_TVLV_HANDLER_OGM_CIFNOTFND flag was set | ||
| 2290 | */ | ||
| 2291 | BATADV_TVLV_HANDLER_OGM_CALLED = BIT(2), | ||
| 2292 | }; | 2297 | }; |
| 2293 | 2298 | ||
| 2294 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ | 2299 | #endif /* _NET_BATMAN_ADV_TYPES_H_ */ |
| @@ -44,7 +44,9 @@ static void nft_meta_bridge_get_eval(const struct nft_expr *expr, · 43 unmodified lines | |||
| 44 | if (!br_dev || !br_vlan_enabled(br_dev)) | 44 | if (!br_dev || !br_vlan_enabled(br_dev)) |
| 45 | goto err; | 45 | goto err; |
| 46 | 46 | ||
| 47 | br_vlan_get_pvid_rcu(in, &p_pvid); | 47 | if (br_vlan_get_pvid_rcu(in, &p_pvid)) |
| 48 | goto err; | ||
| 49 | |||
| 48 | nft_reg_store16(dest, p_pvid); | 50 | nft_reg_store16(dest, p_pvid); |
| 49 | return; | 51 | return; |
| 50 | } | 52 | } |
| @@ -107,12 +109,30 @@ static int nft_meta_bridge_get_init(const struct nft_ctx *ctx, · 56 unmodified lines | |||
| 107 | NULL, NFT_DATA_VALUE, len); | 109 | NULL, NFT_DATA_VALUE, len); |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 112 | static int nft_meta_bridge_get_validate(const struct nft_ctx *ctx, | ||
| 113 | const struct nft_expr *expr) | ||
| 114 | { | ||
| 115 | struct nft_meta *priv = nft_expr_priv(expr); | ||
| 116 | unsigned int hooks; | ||
| 117 | |||
| 118 | switch (priv->key) { | ||
| 119 | case NFT_META_BRI_IIFHWADDR: | ||
| 120 | hooks = 1 << NF_BR_PRE_ROUTING; | ||
| 121 | break; | ||
| 122 | default: | ||
| 123 | return nft_meta_get_validate(ctx, expr); | ||
| 124 | } | ||
| 125 | |||
| 126 | return nft_chain_validate_hooks(ctx->chain, hooks); | ||
| 127 | } | ||
| 128 | |||
| 110 | static struct nft_expr_type nft_meta_bridge_type; | 129 | static struct nft_expr_type nft_meta_bridge_type; |
| 111 | static const struct nft_expr_ops nft_meta_bridge_get_ops = { | 130 | static const struct nft_expr_ops nft_meta_bridge_get_ops = { |
| 112 | .type = &nft_meta_bridge_type, | 131 | .type = &nft_meta_bridge_type, |
| 113 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), | 132 | .size = NFT_EXPR_SIZE(sizeof(struct nft_meta)), |
| 114 | .eval = nft_meta_bridge_get_eval, | 133 | .eval = nft_meta_bridge_get_eval, |
| 115 | .init = nft_meta_bridge_get_init, | 134 | .init = nft_meta_bridge_get_init, |
| 135 | .validate = nft_meta_bridge_get_validate, | ||
| 116 | .dump = nft_meta_get_dump, | 136 | .dump = nft_meta_get_dump, |
| 117 | }; | 137 | }; |
| 118 | 138 | ||
| @@ -168,7 +188,6 @@ static int nft_meta_bridge_set_validate(const struct nft_ctx *ctx, · 49 unmodified lines | |||
| 168 | 188 | ||
| 169 | switch (priv->key) { | 189 | switch (priv->key) { |
| 170 | case NFT_META_BRI_BROUTE: | 190 | case NFT_META_BRI_BROUTE: |
| 171 | case NFT_META_BRI_IIFHWADDR: | ||
| 172 | hooks = 1 << NF_BR_PRE_ROUTING; | 191 | hooks = 1 << NF_BR_PRE_ROUTING; |
| 173 | break; | 192 | break; |
| 174 | default: | 193 | default: |
| @@ -13,7 +13,7 @@ obj-y += dev.o dev_api.o dev_addr_lists.o dst.o netevent.o \ · 12 unmodified lines | |||
| 13 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ | 13 | neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ |
| 14 | sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ | 14 | sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \ |
| 15 | fib_notifier.o xdp.o flow_offload.o gro.o \ | 15 | fib_notifier.o xdp.o flow_offload.o gro.o \ |
| 16 | netdev-genl.o netdev-genl-gen.o gso.o | 16 | netdev-genl.o netdev-genl-gen.o netdev_work.o gso.o |
| 17 | 17 | ||
| 18 | obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o | 18 | obj-$(CONFIG_NETDEV_ADDR_LIST_TEST) += dev_addr_lists_test.o |
| 19 | 19 | ||
| @@ -9822,6 +9822,7 @@ int netif_change_flags(struct net_device *dev, unsigned int flags, · 9821 unmodified lines | |||
| 9822 | __dev_notify_flags(dev, old_flags, changes, 0, NULL); | 9822 | __dev_notify_flags(dev, old_flags, changes, 0, NULL); |
| 9823 | return ret; | 9823 | return ret; |
| 9824 | } | 9824 | } |
| 9825 | EXPORT_SYMBOL(netif_change_flags); | ||
| 9825 | 9826 | ||
| 9826 | int __netif_set_mtu(struct net_device *dev, int new_mtu) | 9827 | int __netif_set_mtu(struct net_device *dev, int new_mtu) |
| 9827 | { | 9828 | { |
| @@ -12093,6 +12094,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, · 2265 unmodified lines | |||
| 12093 | INIT_LIST_HEAD(&dev->ptype_all); | 12094 | INIT_LIST_HEAD(&dev->ptype_all); |
| 12094 | INIT_LIST_HEAD(&dev->ptype_specific); | 12095 | INIT_LIST_HEAD(&dev->ptype_specific); |
| 12095 | INIT_LIST_HEAD(&dev->net_notifier_list); | 12096 | INIT_LIST_HEAD(&dev->net_notifier_list); |
| 12097 | INIT_LIST_HEAD(&dev->work_node); | ||
| 12096 | #ifdef CONFIG_NET_SCHED | 12098 | #ifdef CONFIG_NET_SCHED |
| 12097 | hash_init(dev->qdisc_hash); | 12099 | hash_init(dev->qdisc_hash); |
| 12098 | #endif | 12100 | #endif |
| @@ -167,10 +167,19 @@ int dev_change_carrier(struct net_device *dev, bool new_carrier); · 166 unmodified lines | |||
| 167 | void __dev_set_rx_mode(struct net_device *dev); | 167 | void __dev_set_rx_mode(struct net_device *dev); |
| 168 | int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify); | 168 | int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify); |
| 169 | void netif_rx_mode_init(struct net_device *dev); | 169 | void netif_rx_mode_init(struct net_device *dev); |
| 170 | bool netif_rx_mode_clean(struct net_device *dev); | 170 | void netif_rx_mode_run(struct net_device *dev); |
| 171 | void netif_rx_mode_sync(struct net_device *dev); | 171 | void netif_rx_mode_sync(struct net_device *dev); |
| 172 | void netif_rx_mode_cancel_retry(struct net_device *dev); | 172 | void netif_rx_mode_cancel_retry(struct net_device *dev); |
| 173 | 173 | ||
| 174 | /* Events for the async netdev work, tracked in netdev->work_core_pending. */ | ||
| 175 | enum netdev_work_core { | ||
| 176 | NETDEV_WORK_RX_MODE = BIT(0), /* run the rx_mode update */ | ||
| 177 | }; | ||
| 178 | |||
| 179 | void __netdev_work_core_sched(struct net_device *dev, unsigned long event); | ||
| 180 | unsigned long | ||
| 181 | __netdev_work_core_cancel(struct net_device *dev, unsigned long mask); | ||
| 182 | |||
| 174 | void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, | 183 | void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, |
| 175 | unsigned int gchanges, u32 portid, | 184 | unsigned int gchanges, u32 portid, |
| 176 | const struct nlmsghdr *nlh); | 185 | const struct nlmsghdr *nlh); |
| @@ -12,17 +12,10 @@ · 11 unmodified lines | |||
| 12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
| 13 | #include <linux/list.h> | 13 | #include <linux/list.h> |
| 14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 15 | #include <linux/workqueue.h> | ||
| 16 | #include <kunit/visibility.h> | 15 | #include <kunit/visibility.h> |
| 17 | 16 | ||
| 18 | #include "dev.h" | 17 | #include "dev.h" |
| 19 | 18 | ||
| 20 | static void netdev_rx_mode_work(struct work_struct *work); | ||
| 21 | |||
| 22 | static LIST_HEAD(rx_mode_list); | ||
| 23 | static DEFINE_SPINLOCK(rx_mode_lock); | ||
| 24 | static DECLARE_WORK(rx_mode_work, netdev_rx_mode_work); | ||
| 25 | |||
| 26 | /* | 19 | /* |
| 27 | * General list handling functions | 20 | * General list handling functions |
| 28 | */ | 21 | */ |
| @@ -1281,7 +1274,7 @@ void netif_rx_mode_cancel_retry(struct net_device *dev) · 1252 unmodified lines | |||
| 1281 | dev->rx_mode_retry_count = 0; | 1274 | dev->rx_mode_retry_count = 0; |
| 1282 | } | 1275 | } |
| 1283 | 1276 | ||
| 1284 | static void netif_rx_mode_run(struct net_device *dev) | 1277 | void netif_rx_mode_run(struct net_device *dev) |
| 1285 | { | 1278 | { |
| 1286 | struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref; | 1279 | struct netdev_hw_addr_list uc_snap, mc_snap, uc_ref, mc_ref; |
| 1287 | const struct net_device_ops *ops = dev->netdev_ops; | 1280 | const struct net_device_ops *ops = dev->netdev_ops; |
| @@ -1339,49 +1332,9 @@ static void netif_rx_mode_run(struct net_device *dev) · 51 unmodified lines | |||
| 1339 | } | 1332 | } |
| 1340 | } | 1333 | } |
| 1341 | 1334 | ||
| 1342 | static void netdev_rx_mode_work(struct work_struct *work) | ||
| 1343 | { | ||
| 1344 | struct net_device *dev; | ||
| 1345 | |||
| 1346 | rtnl_lock(); | ||
| 1347 | |||
| 1348 | while (true) { | ||
| 1349 | spin_lock_bh(&rx_mode_lock); | ||
| 1350 | if (list_empty(&rx_mode_list)) { | ||
| 1351 | spin_unlock_bh(&rx_mode_lock); | ||
| 1352 | break; | ||
| 1353 | } | ||
| 1354 | dev = list_first_entry(&rx_mode_list, struct net_device, | ||
| 1355 | rx_mode_node); | ||
| 1356 | list_del_init(&dev->rx_mode_node); | ||
| 1357 | /* We must free netdev tracker under | ||
| 1358 | * the spinlock protection. | ||
| 1359 | */ | ||
| 1360 | netdev_tracker_free(dev, &dev->rx_mode_tracker); | ||
| 1361 | spin_unlock_bh(&rx_mode_lock); | ||
| 1362 | |||
| 1363 | netdev_lock_ops(dev); | ||
| 1364 | netif_rx_mode_run(dev); | ||
| 1365 | netdev_unlock_ops(dev); | ||
| 1366 | /* Use __dev_put() because netdev_tracker_free() was already | ||
| 1367 | * called above. Must be after netdev_unlock_ops() to prevent | ||
| 1368 | * netdev_run_todo() from freeing the device while still in use. | ||
| 1369 | */ | ||
| 1370 | __dev_put(dev); | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | rtnl_unlock(); | ||
| 1374 | } | ||
| 1375 | |||
| 1376 | static void netif_rx_mode_queue(struct net_device *dev) | 1335 | static void netif_rx_mode_queue(struct net_device *dev) |
| 1377 | { | 1336 | { |
| 1378 | spin_lock_bh(&rx_mode_lock); | 1337 | __netdev_work_core_sched(dev, NETDEV_WORK_RX_MODE); |
| 1379 | if (list_empty(&dev->rx_mode_node)) { | ||
| 1380 | list_add_tail(&dev->rx_mode_node, &rx_mode_list); | ||
| 1381 | netdev_hold(dev, &dev->rx_mode_tracker, GFP_ATOMIC); | ||
| 1382 | } | ||
| 1383 | spin_unlock_bh(&rx_mode_lock); | ||
| 1384 | schedule_work(&rx_mode_work); | ||
| 1385 | } | 1338 | } |
| 1386 | 1339 | ||
| 1387 | static void netif_rx_mode_retry(struct timer_list *t) | 1340 | static void netif_rx_mode_retry(struct timer_list *t) |
| @@ -1394,7 +1347,6 @@ static void netif_rx_mode_retry(struct timer_list *t) · 6 unmodified lines | |||
| 1394 | 1347 | ||
| 1395 | void netif_rx_mode_init(struct net_device *dev) | 1348 | void netif_rx_mode_init(struct net_device *dev) |
| 1396 | { | 1349 | { |
| 1397 | INIT_LIST_HEAD(&dev->rx_mode_node); | ||
| 1398 | __hw_addr_init(&dev->rx_mode_addr_cache); | 1350 | __hw_addr_init(&dev->rx_mode_addr_cache); |
| 1399 | timer_setup(&dev->rx_mode_retry_timer, netif_rx_mode_retry, 0); | 1351 | timer_setup(&dev->rx_mode_retry_timer, netif_rx_mode_retry, 0); |
| 1400 | } | 1352 | } |
| @@ -1442,24 +1394,6 @@ void dev_set_rx_mode(struct net_device *dev) · 41 unmodified lines | |||
| 1442 | netif_addr_unlock_bh(dev); | 1394 | netif_addr_unlock_bh(dev); |
| 1443 | } | 1395 | } |
| 1444 | 1396 | ||
| 1445 | bool netif_rx_mode_clean(struct net_device *dev) | ||
| 1446 | { | ||
| 1447 | bool clean = false; | ||
| 1448 | |||
| 1449 | spin_lock_bh(&rx_mode_lock); | ||
| 1450 | if (!list_empty(&dev->rx_mode_node)) { | ||
| 1451 | list_del_init(&dev->rx_mode_node); | ||
| 1452 | clean = true; | ||
| 1453 | /* We must release netdev tracker under | ||
| 1454 | * the spinlock protection. | ||
| 1455 | */ | ||
| 1456 | netdev_tracker_free(dev, &dev->rx_mode_tracker); | ||
| 1457 | } | ||
| 1458 | spin_unlock_bh(&rx_mode_lock); | ||
| 1459 | |||
| 1460 | return clean; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | /** | 1397 | /** |
| 1464 | * netif_rx_mode_sync() - sync rx mode inline | 1398 | * netif_rx_mode_sync() - sync rx mode inline |
| 1465 | * @dev: network device | 1399 | * @dev: network device |
| @@ -1473,11 +1407,6 @@ bool netif_rx_mode_clean(struct net_device *dev) · 7 unmodified lines | |||
| 1473 | */ | 1407 | */ |
| 1474 | void netif_rx_mode_sync(struct net_device *dev) | 1408 | void netif_rx_mode_sync(struct net_device *dev) |
| 1475 | { | 1409 | { |
| 1476 | if (netif_rx_mode_clean(dev)) { | 1410 | if (__netdev_work_core_cancel(dev, NETDEV_WORK_RX_MODE)) |
| 1477 | netif_rx_mode_run(dev); | 1411 | netif_rx_mode_run(dev); |
| 1478 | /* Use __dev_put() because netdev_tracker_free() was already | ||
| 1479 | * called inside netif_rx_mode_clean(). | ||
| 1480 | */ | ||
| 1481 | __dev_put(dev); | ||
| 1482 | } | ||
| 1483 | } | 1412 | } |
| @@ -4472,7 +4472,7 @@ u32 xdp_master_redirect(struct xdp_buff *xdp) · 4471 unmodified lines | |||
| 4472 | struct net_device *master, *slave; | 4472 | struct net_device *master, *slave; |
| 4473 | 4473 | ||
| 4474 | master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); | 4474 | master = netdev_master_upper_dev_get_rcu(xdp->rxq->dev); |
| 4475 | if (unlikely(!(master->flags & IFF_UP))) | 4475 | if (unlikely(!master || !(master->flags & IFF_UP))) |
| 4476 | return XDP_ABORTED; | 4476 | return XDP_ABORTED; |
| 4477 | slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); | 4477 | slave = master->netdev_ops->ndo_xdp_get_xmit_slave(master, xdp); |
| 4478 | if (slave && slave != xdp->rxq->dev) { | 4478 | if (slave && slave != xdp->rxq->dev) { |
| @@ -1173,13 +1173,21 @@ bool __skb_flow_dissect(const struct net *net, · 1172 unmodified lines | |||
| 1173 | 1173 | ||
| 1174 | if (dissector_uses_key(flow_dissector, | 1174 | if (dissector_uses_key(flow_dissector, |
| 1175 | FLOW_DISSECTOR_KEY_ETH_ADDRS)) { | 1175 | FLOW_DISSECTOR_KEY_ETH_ADDRS)) { |
| 1176 | struct ethhdr *eth = eth_hdr(skb); | ||
| 1177 | struct flow_dissector_key_eth_addrs *key_eth_addrs; | 1176 | struct flow_dissector_key_eth_addrs *key_eth_addrs; |
| 1178 | 1177 | ||
| 1179 | key_eth_addrs = skb_flow_dissector_target(flow_dissector, | 1178 | key_eth_addrs = skb_flow_dissector_target(flow_dissector, |
| 1180 | FLOW_DISSECTOR_KEY_ETH_ADDRS, | 1179 | FLOW_DISSECTOR_KEY_ETH_ADDRS, |
| 1181 | target_container); | 1180 | target_container); |
| 1182 | memcpy(key_eth_addrs, eth, sizeof(*key_eth_addrs)); | 1181 | /* TC filter blocks can be shared across devices with |
| 1182 | * different link types, so we cannot validate this | ||
| 1183 | * when the filter is installed -- check at dissect time. | ||
| 1184 | */ | ||
| 1185 | if (skb && skb->dev && | ||
| 1186 | skb->dev->type == ARPHRD_ETHER && | ||
| 1187 | skb_mac_header_was_set(skb)) | ||
| 1188 | memcpy(key_eth_addrs, eth_hdr(skb), sizeof(*key_eth_addrs)); | ||
| 1189 | else | ||
| 1190 | memset(key_eth_addrs, 0, sizeof(*key_eth_addrs)); | ||
| 1183 | } | 1191 | } |
| 1184 | 1192 | ||
| 1185 | if (dissector_uses_key(flow_dissector, | 1193 | if (dissector_uses_key(flow_dissector, |
| @@ -350,6 +350,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) · 349 unmodified lines | |||
| 350 | rcu_read_lock(); | 350 | rcu_read_lock(); |
| 351 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); | 351 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); |
| 352 | if (likely(ops && ops->output)) { | 352 | if (likely(ops && ops->output)) { |
| 353 | /* Encap pushes outer headers over the metadata; drop it. */ | ||
| 354 | skb_metadata_clear(skb); | ||
| 353 | dev_xmit_recursion_inc(); | 355 | dev_xmit_recursion_inc(); |
| 354 | ret = ops->output(net, sk, skb); | 356 | ret = ops->output(net, sk, skb); |
| 355 | dev_xmit_recursion_dec(); | 357 | dev_xmit_recursion_dec(); |
| @@ -404,6 +406,8 @@ int lwtunnel_xmit(struct sk_buff *skb) · 48 unmodified lines | |||
| 404 | rcu_read_lock(); | 406 | rcu_read_lock(); |
| 405 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); | 407 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); |
| 406 | if (likely(ops && ops->xmit)) { | 408 | if (likely(ops && ops->xmit)) { |
| 409 | /* Encap pushes outer headers over the metadata; drop it. */ | ||
| 410 | skb_metadata_clear(skb); | ||
| 407 | dev_xmit_recursion_inc(); | 411 | dev_xmit_recursion_inc(); |
| 408 | ret = ops->xmit(skb); | 412 | ret = ops->xmit(skb); |
| 409 | dev_xmit_recursion_dec(); | 413 | dev_xmit_recursion_dec(); |
| @@ -455,6 +459,8 @@ int lwtunnel_input(struct sk_buff *skb) · 45 unmodified lines | |||
| 455 | rcu_read_lock(); | 459 | rcu_read_lock(); |
| 456 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); | 460 | ops = rcu_dereference(lwtun_encaps[lwtstate->type]); |
| 457 | if (likely(ops && ops->input)) { | 461 | if (likely(ops && ops->input)) { |
| 462 | /* Encap pushes outer headers over the metadata; drop it. */ | ||
| 463 | skb_metadata_clear(skb); | ||
| 458 | dev_xmit_recursion_inc(); | 464 | dev_xmit_recursion_inc(); |
| 459 | ret = ops->input(skb); | 465 | ret = ops->input(skb); |
| 460 | dev_xmit_recursion_dec(); | 466 | dev_xmit_recursion_dec(); |
| @@ -2,6 +2,7 @@ · 1 unmodified line | |||
| 2 | 2 | ||
| 3 | #include <linux/netdevice.h> | 3 | #include <linux/netdevice.h> |
| 4 | #include <linux/notifier.h> | 4 | #include <linux/notifier.h> |
| 5 | #include <linux/pid_namespace.h> | ||
| 5 | #include <linux/rtnetlink.h> | 6 | #include <linux/rtnetlink.h> |
| 6 | #include <net/busy_poll.h> | 7 | #include <net/busy_poll.h> |
| 7 | #include <net/net_namespace.h> | 8 | #include <net/net_namespace.h> |
| @@ -189,7 +190,8 @@ netdev_nl_napi_fill_one(struct sk_buff *rsp, struct napi_struct *napi, · 181 unmodified lines | |||
| 189 | goto nla_put_failure; | 190 | goto nla_put_failure; |
| 190 | 191 | ||
| 191 | if (napi->thread) { | 192 | if (napi->thread) { |
| 192 | pid = task_pid_nr(napi->thread); | 193 | pid = task_pid_nr_ns(napi->thread, |
| 194 | task_active_pid_ns(current)); | ||
| 193 | if (nla_put_u32(rsp, NETDEV_A_NAPI_PID, pid)) | 195 | if (nla_put_u32(rsp, NETDEV_A_NAPI_PID, pid)) |
| 194 | goto nla_put_failure; | 196 | goto nla_put_failure; |
| 195 | } | 197 | } |
| @@ -0,0 +1,162 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | |||
| 3 | #include <linux/export.h> | ||
| 4 | #include <linux/list.h> | ||
| 5 | #include <linux/netdevice.h> | ||
| 6 | #include <linux/rtnetlink.h> | ||
| 7 | #include <linux/spinlock.h> | ||
| 8 | #include <linux/workqueue.h> | ||
| 9 | #include <net/netdev_lock.h> | ||
| 10 | |||
| 11 | #include "dev.h" | ||
| 12 | |||
| 13 | static void netdev_work_proc(struct work_struct *work); | ||
| 14 | |||
| 15 | /* @netdev_work_lock protects: | ||
| 16 | * - @netdev_work_list | ||
| 17 | * - within the list entries (struct net_device fields): | ||
| 18 | * - work_node | ||
| 19 | * - work_tracker | ||
| 20 | * - work_pending | ||
| 21 | * - work_core_pending | ||
| 22 | */ | ||
| 23 | static LIST_HEAD(netdev_work_list); | ||
| 24 | static DEFINE_SPINLOCK(netdev_work_lock); | ||
| 25 | static DECLARE_WORK(netdev_work, netdev_work_proc); | ||
| 26 | |||
| 27 | static void netdev_work_enqueue(struct net_device *dev, unsigned long events, | ||
| 28 | unsigned long core) | ||
| 29 | { | ||
| 30 | if (!events && !core) | ||
| 31 | return; | ||
| 32 | |||
| 33 | spin_lock_bh(&netdev_work_lock); | ||
| 34 | if (list_empty(&dev->work_node)) { | ||
| 35 | list_add_tail(&dev->work_node, &netdev_work_list); | ||
| 36 | netdev_hold(dev, &dev->work_tracker, GFP_ATOMIC); | ||
| 37 | } | ||
| 38 | dev->work_pending |= events; | ||
| 39 | dev->work_core_pending |= core; | ||
| 40 | spin_unlock_bh(&netdev_work_lock); | ||
| 41 | |||
| 42 | schedule_work(&netdev_work); | ||
| 43 | } | ||
| 44 | |||
| 45 | static unsigned long | ||
| 46 | netdev_work_dequeue(struct net_device *dev, unsigned long *pending, | ||
| 47 | unsigned long mask) | ||
| 48 | { | ||
| 49 | unsigned long events; | ||
| 50 | |||
| 51 | spin_lock_bh(&netdev_work_lock); | ||
| 52 | events = *pending & mask; | ||
| 53 | *pending &= ~events; | ||
| 54 | if (!list_empty(&dev->work_node) && | ||
| 55 | !dev->work_pending && !dev->work_core_pending) { | ||
| 56 | list_del_init(&dev->work_node); | ||
| 57 | netdev_put(dev, &dev->work_tracker); | ||
| 58 | } | ||
| 59 | spin_unlock_bh(&netdev_work_lock); | ||
| 60 | |||
| 61 | return events; | ||
| 62 | } | ||
| 63 | |||
| 64 | void netdev_work_sched(struct net_device *dev, unsigned long events) | ||
| 65 | { | ||
| 66 | netdev_work_enqueue(dev, events, 0); | ||
| 67 | } | ||
| 68 | EXPORT_SYMBOL(netdev_work_sched); | ||
| 69 | |||
| 70 | /** | ||
| 71 | * netdev_work_cancel() - cancel selected work for a netdev | ||
| 72 | * @dev: net_device | ||
| 73 | * @mask: events to cancel | ||
| 74 | * | ||
| 75 | * Clear @mask from the device's work pending mask. If no work is left pending | ||
| 76 | * the device is dequeued and its ndo_work won't be called. | ||
| 77 | * | ||
| 78 | * No expectations on locking, but also no guarantees provided. If the caller | ||
| 79 | * wants to touch @dev afterwards (e.g. call the work that got canceled) | ||
| 80 | * they have to ensure @dev does not get freed. | ||
| 81 | * | ||
| 82 | * Returns: the subset of @mask that was actually pending, so the caller can run | ||
| 83 | * those events inline. | ||
| 84 | */ | ||
| 85 | unsigned long netdev_work_cancel(struct net_device *dev, unsigned long mask) | ||
| 86 | { | ||
| 87 | return netdev_work_dequeue(dev, &dev->work_pending, mask); | ||
| 88 | } | ||
| 89 | EXPORT_SYMBOL(netdev_work_cancel); | ||
| 90 | |||
| 91 | void __netdev_work_core_sched(struct net_device *dev, unsigned long events) | ||
| 92 | { | ||
| 93 | netdev_work_enqueue(dev, 0, events); | ||
| 94 | } | ||
| 95 | |||
| 96 | unsigned long | ||
| 97 | __netdev_work_core_cancel(struct net_device *dev, unsigned long mask) | ||
| 98 | { | ||
| 99 | return netdev_work_dequeue(dev, &dev->work_core_pending, mask); | ||
| 100 | } | ||
| 101 | |||
| 102 | static void netdev_work_run(struct net_device *dev, unsigned long events, | ||
| 103 | unsigned long core) | ||
| 104 | { | ||
| 105 | if (!netif_device_present(dev)) | ||
| 106 | return; | ||
| 107 | |||
| 108 | if (core & NETDEV_WORK_RX_MODE) | ||
| 109 | netif_rx_mode_run(dev); | ||
| 110 | if (events && dev->netdev_ops->ndo_work) | ||
| 111 | dev->netdev_ops->ndo_work(dev, events); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void netdev_work_proc(struct work_struct *work) | ||
| 115 | { | ||
| 116 | rtnl_lock(); | ||
| 117 | |||
| 118 | while (true) { | ||
| 119 | unsigned long events = 0, core = 0; | ||
| 120 | netdevice_tracker tracker; | ||
| 121 | struct net_device *dev; | ||
| 122 | |||
| 123 | spin_lock_bh(&netdev_work_lock); | ||
| 124 | if (list_empty(&netdev_work_list)) { | ||
| 125 | spin_unlock_bh(&netdev_work_lock); | ||
| 126 | break; | ||
| 127 | } | ||
| 128 | dev = list_first_entry(&netdev_work_list, struct net_device, | ||
| 129 | work_node); | ||
| 130 | /* Take a temporary reference so @dev can't be freed while we | ||
| 131 | * drop the lock to grab its ops lock; the work reference is | ||
| 132 | * only released once we claim the work below. | ||
| 133 | * The re-locking dance is to ensure that ops lock is enough | ||
| 134 | * to ensure canceling work is not racy with dequeue. | ||
| 135 | */ | ||
| 136 | netdev_hold(dev, &tracker, GFP_ATOMIC); | ||
| 137 | spin_unlock_bh(&netdev_work_lock); | ||
| 138 | |||
| 139 | netdev_lock_ops(dev); | ||
| 140 | spin_lock_bh(&netdev_work_lock); | ||
| 141 | if (!list_empty(&dev->work_node)) { | ||
| 142 | list_del_init(&dev->work_node); | ||
| 143 | core = dev->work_core_pending; | ||
| 144 | dev->work_core_pending = 0; | ||
| 145 | events = dev->work_pending; | ||
| 146 | dev->work_pending = 0; | ||
| 147 | /* We took another ref above */ | ||
| 148 | netdev_put(dev, &dev->work_tracker); | ||
| 149 | |||
| 150 | if (!dev_isalive(dev)) | ||
| 151 | core = events = 0; | ||
| 152 | } | ||
| 153 | spin_unlock_bh(&netdev_work_lock); | ||
| 154 | |||
| 155 | netdev_work_run(dev, events, core); | ||
| 156 | netdev_unlock_ops(dev); | ||
| 157 | |||
| 158 | netdev_put(dev, &tracker); | ||
| 159 | } | ||
| 160 | |||
| 161 | rtnl_unlock(); | ||
| 162 | } | ||
| @@ -2438,6 +2438,14 @@ struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid) · 2437 unmodified lines | |||
| 2438 | } | 2438 | } |
| 2439 | EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); | 2439 | EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable); |
| 2440 | 2440 | ||
| 2441 | bool rtnl_dev_link_net_capable(const struct net_device *dev, | ||
| 2442 | const struct net *link_net) | ||
| 2443 | { | ||
| 2444 | return net_eq(link_net, dev_net(dev)) || | ||
| 2445 | ns_capable(link_net->user_ns, CAP_NET_ADMIN); | ||
| 2446 | } | ||
| 2447 | EXPORT_SYMBOL_GPL(rtnl_dev_link_net_capable); | ||
| 2448 | |||
| 2441 | static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, | 2449 | static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh, |
| 2442 | bool strict_check, struct nlattr **tb, | 2450 | bool strict_check, struct nlattr **tb, |
| 2443 | struct netlink_ext_ack *extack) | 2451 | struct netlink_ext_ack *extack) |
| @@ -486,16 +486,19 @@ static int devlink_nl_rate_set(struct devlink_rate *devlink_rate, · 485 unmodified lines | |||
| 486 | devlink_rate->tx_weight = weight; | 486 | devlink_rate->tx_weight = weight; |
| 487 | } | 487 | } |
| 488 | 488 | ||
| 489 | nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]; | 489 | if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) { |
| 490 | if (nla_parent) { | 490 | err = devlink_nl_rate_tc_bw_set(devlink_rate, info); |
| 491 | err = devlink_nl_rate_parent_node_set(devlink_rate, info, | ||
| 492 | nla_parent); | ||
| 493 | if (err) | 491 | if (err) |
| 494 | return err; | 492 | return err; |
| 495 | } | 493 | } |
| 496 | 494 | ||
| 497 | if (attrs[DEVLINK_ATTR_RATE_TC_BWS]) { | 495 | /* Keep parent setting last because it takes a reference. This function |
| 498 | err = devlink_nl_rate_tc_bw_set(devlink_rate, info); | 496 | * has no rollback, so failing after taking the ref would leak it. |
| 497 | */ | ||
| 498 | nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]; | ||
| 499 | if (nla_parent) { | ||
| 500 | err = devlink_nl_rate_parent_node_set(devlink_rate, info, | ||
| 501 | nla_parent); | ||
| 499 | if (err) | 502 | if (err) |
| 500 | return err; | 503 | return err; |
| 501 | } | 504 | } |
| @@ -725,11 +728,6 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, · 223 unmodified lines | |||
| 725 | if (!rate_node) | 728 | if (!rate_node) |
| 726 | return ERR_PTR(-ENOMEM); | 729 | return ERR_PTR(-ENOMEM); |
| 727 | 730 | ||
| 728 | if (parent) { | ||
| 729 | rate_node->parent = parent; | ||
| 730 | refcount_inc(&rate_node->parent->refcnt); | ||
| 731 | } | ||
| 732 | |||
| 733 | rate_node->type = DEVLINK_RATE_TYPE_NODE; | 731 | rate_node->type = DEVLINK_RATE_TYPE_NODE; |
| 734 | rate_node->devlink = devlink; | 732 | rate_node->devlink = devlink; |
| 735 | rate_node->priv = priv; | 733 | rate_node->priv = priv; |
| @@ -740,6 +738,11 @@ devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name, · 4 unmodified lines | |||
| 740 | return ERR_PTR(-ENOMEM); | 738 | return ERR_PTR(-ENOMEM); |
| 741 | } | 739 | } |
| 742 | 740 | ||
| 741 | if (parent) { | ||
| 742 | rate_node->parent = parent; | ||
| 743 | refcount_inc(&rate_node->parent->refcnt); | ||
| 744 | } | ||
| 745 | |||
| 743 | refcount_set(&rate_node->refcnt, 1); | 746 | refcount_set(&rate_node->refcnt, 1); |
| 744 | list_add(&rate_node->list, &devlink->rate_list); | 747 | list_add(&rate_node->list, &devlink->rate_list); |
| 745 | devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); | 748 | devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW); |
| @@ -113,6 +113,8 @@ ethtool_nl_msg_needs_rtnl(const struct net_device *dev, u8 cmd) · 112 unmodified lines | |||
| 113 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM; | 113 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_SPAUSEPARAM; |
| 114 | case ETHTOOL_MSG_RSS_SET: | 114 | case ETHTOOL_MSG_RSS_SET: |
| 115 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_RSS; | 115 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_RSS; |
| 116 | case ETHTOOL_MSG_LINKSTATE_GET: | ||
| 117 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_GLINK; | ||
| 116 | case ETHTOOL_MSG_TSCONFIG_GET: | 118 | case ETHTOOL_MSG_TSCONFIG_GET: |
| 117 | case ETHTOOL_MSG_TSCONFIG_SET: | 119 | case ETHTOOL_MSG_TSCONFIG_SET: |
| 118 | /* tsconfig calls ndos (ndo_hwtstamp_set/get), not ethtool ops. | 120 | /* tsconfig calls ndos (ndo_hwtstamp_set/get), not ethtool ops. |
| @@ -159,6 +161,8 @@ ethtool_ioctl_needs_rtnl(const struct net_device *dev, u32 ethcmd) · 40 unmodified lines | |||
| 159 | case ETHTOOL_SRXFH: | 161 | case ETHTOOL_SRXFH: |
| 160 | case ETHTOOL_SRXFHINDIR: | 162 | case ETHTOOL_SRXFHINDIR: |
| 161 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_RSS; | 163 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_RSS; |
| 164 | case ETHTOOL_GLINK: | ||
| 165 | return ops->op_needs_rtnl & ETHTOOL_OP_NEEDS_RTNL_GLINK; | ||
| 162 | } | 166 | } |
| 163 | return false; | 167 | return false; |
| 164 | } | 168 | } |
| @@ -228,36 +228,43 @@ int cfg802154_switch_netns(struct cfg802154_registered_device *rdev, · 227 unmodified lines | |||
| 228 | continue; | 228 | continue; |
| 229 | wpan_dev->netdev->netns_immutable = false; | 229 | wpan_dev->netdev->netns_immutable = false; |
| 230 | err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d"); | 230 | err = dev_change_net_namespace(wpan_dev->netdev, net, "wpan%d"); |
| 231 | if (err) | 231 | if (err) { |
| 232 | WARN_ON(err && err != -ENOMEM); | ||
| 232 | break; | 233 | break; |
| 234 | } | ||
| 233 | wpan_dev->netdev->netns_immutable = true; | 235 | wpan_dev->netdev->netns_immutable = true; |
| 234 | } | 236 | } |
| 235 | 237 | ||
| 236 | if (err) { | 238 | if (err) |
| 237 | /* failed -- clean up to old netns */ | 239 | goto errout; |
| 238 | net = wpan_phy_net(&rdev->wpan_phy); | ||
| 239 | |||
| 240 | list_for_each_entry_continue_reverse(wpan_dev, | ||
| 241 | &rdev->wpan_dev_list, | ||
| 242 | list) { | ||
| 243 | if (!wpan_dev->netdev) | ||
| 244 | continue; | ||
| 245 | wpan_dev->netdev->netns_immutable = false; | ||
| 246 | err = dev_change_net_namespace(wpan_dev->netdev, net, | ||
| 247 | "wpan%d"); | ||
| 248 | WARN_ON(err); | ||
| 249 | wpan_dev->netdev->netns_immutable = true; | ||
| 250 | } | ||
| 251 | 240 | ||
| 252 | return err; | 241 | err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev)); |
| 253 | } | 242 | WARN_ON(err && err != -ENOMEM); |
| 254 | 243 | ||
| 255 | wpan_phy_net_set(&rdev->wpan_phy, net); | 244 | if (err) |
| 245 | goto errout; | ||
| 256 | 246 | ||
| 257 | err = device_rename(&rdev->wpan_phy.dev, dev_name(&rdev->wpan_phy.dev)); | 247 | wpan_phy_net_set(&rdev->wpan_phy, net); |
| 258 | WARN_ON(err); | ||
| 259 | 248 | ||
| 260 | return 0; | 249 | return 0; |
| 250 | |||
| 251 | errout: | ||
| 252 | /* failed -- clean up to old netns */ | ||
| 253 | net = wpan_phy_net(&rdev->wpan_phy); | ||
| 254 | |||
| 255 | list_for_each_entry_continue_reverse(wpan_dev, | ||
| 256 | &rdev->wpan_dev_list, | ||
| 257 | list) { | ||
| 258 | if (!wpan_dev->netdev) | ||
| 259 | continue; | ||
| 260 | wpan_dev->netdev->netns_immutable = false; | ||
| 261 | err = dev_change_net_namespace(wpan_dev->netdev, net, | ||
| 262 | "wpan%d"); | ||
| 263 | WARN_ON(err && err != -ENOMEM); | ||
| 264 | wpan_dev->netdev->netns_immutable = true; | ||
| 265 | } | ||
| 266 | |||
| 267 | return err; | ||
| 261 | } | 268 | } |
| 262 | 269 | ||
| 263 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev) | 270 | void cfg802154_dev_free(struct cfg802154_registered_device *rdev) |
| @@ -351,7 +358,7 @@ static void __net_exit cfg802154_pernet_exit(struct net *net) · 87 unmodified lines | |||
| 351 | rtnl_lock(); | 358 | rtnl_lock(); |
| 352 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { | 359 | list_for_each_entry(rdev, &cfg802154_rdev_list, list) { |
| 353 | if (net_eq(wpan_phy_net(&rdev->wpan_phy), net)) | 360 | if (net_eq(wpan_phy_net(&rdev->wpan_phy), net)) |
| 354 | WARN_ON(cfg802154_switch_netns(rdev, &init_net)); | 361 | cfg802154_switch_netns(rdev, &init_net); |
| 355 | } | 362 | } |
| 356 | rtnl_unlock(); | 363 | rtnl_unlock(); |
| 357 | } | 364 | } |
| @@ -173,10 +173,13 @@ ieee802154_hdr_get_addr(const u8 *buf, int mode, bool omit_pan, · 172 unmodified lines | |||
| 173 | { | 173 | { |
| 174 | int pos = 0; | 174 | int pos = 0; |
| 175 | 175 | ||
| 176 | addr->mode = mode; | 176 | if (mode == IEEE802154_ADDR_NONE) { |
| 177 | 177 | memset(addr, 0, sizeof(*addr)); | |
| 178 | if (mode == IEEE802154_ADDR_NONE) | 178 | addr->mode = IEEE802154_ADDR_NONE; |
| 179 | return 0; | 179 | return 0; |
| 180 | } | ||
| 181 | |||
| 182 | addr->mode = mode; | ||
| 180 | 183 | ||
| 181 | if (!omit_pan) { | 184 | if (!omit_pan) { |
| 182 | memcpy(&addr->pan_id, buf + pos, 2); | 185 | memcpy(&addr->pan_id, buf + pos, 2); |
| @@ -16,6 +16,15 @@ void ieee802154_nl_exit(void); · 15 unmodified lines | |||
| 16 | .flags = GENL_ADMIN_PERM, \ | 16 | .flags = GENL_ADMIN_PERM, \ |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | #define IEEE802154_OP_RELAXED(_cmd, _func) \ | ||
| 20 | { \ | ||
| 21 | .cmd = _cmd, \ | ||
| 22 | .doit = _func, \ | ||
| 23 | .dumpit = NULL, \ | ||
| 24 | .flags = GENL_ADMIN_PERM, \ | ||
| 25 | .validate = GENL_DONT_VALIDATE_STRICT,\ | ||
| 26 | } | ||
| 27 | |||
| 19 | #define IEEE802154_DUMP(_cmd, _func, _dump) \ | 28 | #define IEEE802154_DUMP(_cmd, _func, _dump) \ |
| 20 | { \ | 29 | { \ |
| 21 | .cmd = _cmd, \ | 30 | .cmd = _cmd, \ |
| @@ -23,6 +32,14 @@ void ieee802154_nl_exit(void); · 1 unmodified line | |||
| 23 | .dumpit = _dump, \ | 32 | .dumpit = _dump, \ |
| 24 | } | 33 | } |
| 25 | 34 | ||
| 35 | #define IEEE802154_DUMP_PRIV(_cmd, _func, _dump) \ | ||
| 36 | { \ | ||
| 37 | .cmd = _cmd, \ | ||
| 38 | .doit = _func, \ | ||
| 39 | .dumpit = _dump, \ | ||
| 40 | .flags = GENL_ADMIN_PERM, \ | ||
| 41 | } | ||
| 42 | |||
| 26 | struct genl_info; | 43 | struct genl_info; |
| 27 | 44 | ||
| 28 | struct sk_buff *ieee802154_nl_create(int flags, u8 req); | 45 | struct sk_buff *ieee802154_nl_create(int flags, u8 req); |
| @@ -98,24 +98,24 @@ static const struct genl_small_ops ieee802154_ops[] = { · 97 unmodified lines | |||
| 98 | IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams), | 98 | IEEE802154_OP(IEEE802154_SET_MACPARAMS, ieee802154_set_macparams), |
| 99 | IEEE802154_OP(IEEE802154_LLSEC_GETPARAMS, ieee802154_llsec_getparams), | 99 | IEEE802154_OP(IEEE802154_LLSEC_GETPARAMS, ieee802154_llsec_getparams), |
| 100 | IEEE802154_OP(IEEE802154_LLSEC_SETPARAMS, ieee802154_llsec_setparams), | 100 | IEEE802154_OP(IEEE802154_LLSEC_SETPARAMS, ieee802154_llsec_setparams), |
| 101 | IEEE802154_DUMP(IEEE802154_LLSEC_LIST_KEY, NULL, | 101 | IEEE802154_DUMP_PRIV(IEEE802154_LLSEC_LIST_KEY, NULL, |
| 102 | ieee802154_llsec_dump_keys), | 102 | ieee802154_llsec_dump_keys), |
| 103 | IEEE802154_OP(IEEE802154_LLSEC_ADD_KEY, ieee802154_llsec_add_key), | 103 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_ADD_KEY, ieee802154_llsec_add_key), |
| 104 | IEEE802154_OP(IEEE802154_LLSEC_DEL_KEY, ieee802154_llsec_del_key), | 104 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_DEL_KEY, ieee802154_llsec_del_key), |
| 105 | IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEV, NULL, | 105 | IEEE802154_DUMP_PRIV(IEEE802154_LLSEC_LIST_DEV, NULL, |
| 106 | ieee802154_llsec_dump_devs), | 106 | ieee802154_llsec_dump_devs), |
| 107 | IEEE802154_OP(IEEE802154_LLSEC_ADD_DEV, ieee802154_llsec_add_dev), | 107 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_ADD_DEV, ieee802154_llsec_add_dev), |
| 108 | IEEE802154_OP(IEEE802154_LLSEC_DEL_DEV, ieee802154_llsec_del_dev), | 108 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_DEL_DEV, ieee802154_llsec_del_dev), |
| 109 | IEEE802154_DUMP(IEEE802154_LLSEC_LIST_DEVKEY, NULL, | 109 | IEEE802154_DUMP_PRIV(IEEE802154_LLSEC_LIST_DEVKEY, NULL, |
| 110 | ieee802154_llsec_dump_devkeys), | 110 | ieee802154_llsec_dump_devkeys), |
| 111 | IEEE802154_OP(IEEE802154_LLSEC_ADD_DEVKEY, ieee802154_llsec_add_devkey), | 111 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_ADD_DEVKEY, ieee802154_llsec_add_devkey), |
| 112 | IEEE802154_OP(IEEE802154_LLSEC_DEL_DEVKEY, ieee802154_llsec_del_devkey), | 112 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_DEL_DEVKEY, ieee802154_llsec_del_devkey), |
| 113 | IEEE802154_DUMP(IEEE802154_LLSEC_LIST_SECLEVEL, NULL, | 113 | IEEE802154_DUMP_PRIV(IEEE802154_LLSEC_LIST_SECLEVEL, NULL, |
| 114 | ieee802154_llsec_dump_seclevels), | 114 | ieee802154_llsec_dump_seclevels), |
| 115 | IEEE802154_OP(IEEE802154_LLSEC_ADD_SECLEVEL, | 115 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_ADD_SECLEVEL, |
| 116 | ieee802154_llsec_add_seclevel), | 116 | ieee802154_llsec_add_seclevel), |
| 117 | IEEE802154_OP(IEEE802154_LLSEC_DEL_SECLEVEL, | 117 | IEEE802154_OP_RELAXED(IEEE802154_LLSEC_DEL_SECLEVEL, |
| 118 | ieee802154_llsec_del_seclevel), | 118 | ieee802154_llsec_del_seclevel), |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | static const struct genl_multicast_group ieee802154_mcgrps[] = { | 121 | static const struct genl_multicast_group ieee802154_mcgrps[] = { |
| @@ -1457,6 +1457,9 @@ static int ipgre_changelink(struct net_device *dev, struct nlattr *tb[], · 1456 unmodified lines | |||
| 1457 | __u32 fwmark = t->fwmark; | 1457 | __u32 fwmark = t->fwmark; |
| 1458 | int err; | 1458 | int err; |
| 1459 | 1459 | ||
| 1460 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 1461 | return -EPERM; | ||
| 1462 | |||
| 1460 | err = ipgre_newlink_encap_setup(dev, data); | 1463 | err = ipgre_newlink_encap_setup(dev, data); |
| 1461 | if (err) | 1464 | if (err) |
| 1462 | return err; | 1465 | return err; |
| @@ -1486,6 +1489,9 @@ static int erspan_changelink(struct net_device *dev, struct nlattr *tb[], · 23 unmodified lines | |||
| 1486 | __u32 fwmark = t->fwmark; | 1489 | __u32 fwmark = t->fwmark; |
| 1487 | int err; | 1490 | int err; |
| 1488 | 1491 | ||
| 1492 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 1493 | return -EPERM; | ||
| 1494 | |||
| 1489 | err = ipgre_newlink_encap_setup(dev, data); | 1495 | err = ipgre_newlink_encap_setup(dev, data); |
| 1490 | if (err) | 1496 | if (err) |
| 1491 | return err; | 1497 | return err; |
| @@ -1116,8 +1116,8 @@ alloc_new_skb: · 1115 unmodified lines | |||
| 1116 | !(rt->dst.dev->features & NETIF_F_SG))) | 1116 | !(rt->dst.dev->features & NETIF_F_SG))) |
| 1117 | alloclen = fraglen; | 1117 | alloclen = fraglen; |
| 1118 | else { | 1118 | else { |
| 1119 | alloclen = fragheaderlen + transhdrlen; | 1119 | alloclen = fragheaderlen + transhdrlen + fraggap; |
| 1120 | pagedlen = datalen - transhdrlen; | 1120 | pagedlen = datalen - transhdrlen - fraggap; |
| 1121 | } | 1121 | } |
| 1122 | 1122 | ||
| 1123 | alloclen += alloc_extra; | 1123 | alloclen += alloc_extra; |
| @@ -1164,9 +1164,6 @@ alloc_new_skb: · 40 unmodified lines | |||
| 1164 | } | 1164 | } |
| 1165 | 1165 | ||
| 1166 | copy = datalen - transhdrlen - fraggap - pagedlen; | 1166 | copy = datalen - transhdrlen - fraggap - pagedlen; |
| 1167 | /* [!] NOTE: copy will be negative if pagedlen>0 | ||
| 1168 | * because then the equation reduces to -fraggap. | ||
| 1169 | */ | ||
| 1170 | if (copy > 0 && | 1167 | if (copy > 0 && |
| 1171 | INDIRECT_CALL_1(getfrag, ip_generic_getfrag, | 1168 | INDIRECT_CALL_1(getfrag, ip_generic_getfrag, |
| 1172 | from, data + transhdrlen, offset, | 1169 | from, data + transhdrlen, offset, |
| @@ -596,6 +596,9 @@ static int vti_changelink(struct net_device *dev, struct nlattr *tb[], · 595 unmodified lines | |||
| 596 | struct ip_tunnel_parm_kern p; | 596 | struct ip_tunnel_parm_kern p; |
| 597 | __u32 fwmark = t->fwmark; | 597 | __u32 fwmark = t->fwmark; |
| 598 | 598 | ||
| 599 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 600 | return -EPERM; | ||
| 601 | |||
| 599 | vti_netlink_parms(data, &p, &fwmark); | 602 | vti_netlink_parms(data, &p, &fwmark); |
| 600 | return ip_tunnel_changelink(dev, tb, &p, fwmark); | 603 | return ip_tunnel_changelink(dev, tb, &p, fwmark); |
| 601 | } | 604 | } |
| @@ -494,6 +494,9 @@ static int ipip_changelink(struct net_device *dev, struct nlattr *tb[], · 493 unmodified lines | |||
| 494 | bool collect_md; | 494 | bool collect_md; |
| 495 | __u32 fwmark = t->fwmark; | 495 | __u32 fwmark = t->fwmark; |
| 496 | 496 | ||
| 497 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 498 | return -EPERM; | ||
| 499 | |||
| 497 | if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { | 500 | if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { |
| 498 | int err = ip_tunnel_encap_setup(t, &ipencap); | 501 | int err = ip_tunnel_encap_setup(t, &ipencap); |
| 499 | 502 | ||
| @@ -89,7 +89,7 @@ static bool nf_skb_is_icmp_unreach(const struct sk_buff *skb) · 88 unmodified lines | |||
| 89 | if (iph->protocol != IPPROTO_ICMP) | 89 | if (iph->protocol != IPPROTO_ICMP) |
| 90 | return false; | 90 | return false; |
| 91 | 91 | ||
| 92 | thoff = skb_network_offset(skb) + sizeof(*iph); | 92 | thoff = skb_network_offset(skb) + ip_hdrlen(skb); |
| 93 | 93 | ||
| 94 | tp = skb_header_pointer(skb, | 94 | tp = skb_header_pointer(skb, |
| 95 | thoff + offsetof(struct icmphdr, type), | 95 | thoff + offsetof(struct icmphdr, type), |
| @@ -1058,7 +1058,9 @@ static struct ctl_table ipv4_net_table[] = { · 1057 unmodified lines | |||
| 1058 | .data = &init_net.ipv4.sysctl_tcp_reordering, | 1058 | .data = &init_net.ipv4.sysctl_tcp_reordering, |
| 1059 | .maxlen = sizeof(int), | 1059 | .maxlen = sizeof(int), |
| 1060 | .mode = 0644, | 1060 | .mode = 0644, |
| 1061 | .proc_handler = proc_dointvec | 1061 | .proc_handler = proc_dointvec_minmax, |
| 1062 | .extra1 = SYSCTL_ONE, | ||
| 1063 | .extra2 = &init_net.ipv4.sysctl_tcp_max_reordering, | ||
| 1062 | }, | 1064 | }, |
| 1063 | { | 1065 | { |
| 1064 | .procname = "tcp_retries1", | 1066 | .procname = "tcp_retries1", |
| @@ -1293,7 +1295,8 @@ static struct ctl_table ipv4_net_table[] = { · 228 unmodified lines | |||
| 1293 | .data = &init_net.ipv4.sysctl_tcp_max_reordering, | 1295 | .data = &init_net.ipv4.sysctl_tcp_max_reordering, |
| 1294 | .maxlen = sizeof(int), | 1296 | .maxlen = sizeof(int), |
| 1295 | .mode = 0644, | 1297 | .mode = 0644, |
| 1296 | .proc_handler = proc_dointvec | 1298 | .proc_handler = proc_dointvec_minmax, |
| 1299 | .extra1 = SYSCTL_ONE, | ||
| 1297 | }, | 1300 | }, |
| 1298 | { | 1301 | { |
| 1299 | .procname = "tcp_dsack", | 1302 | .procname = "tcp_dsack", |
| @@ -1676,6 +1679,9 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) · 376 unmodified lines | |||
| 1676 | */ | 1679 | */ |
| 1677 | table[i].mode &= ~0222; | 1680 | table[i].mode &= ~0222; |
| 1678 | } | 1681 | } |
| 1682 | if (table[i].extra2 >= (void *)&init_net.ipv4 && | ||
| 1683 | table[i].extra2 < (void *)(&init_net.ipv4 + 1)) | ||
| 1684 | table[i].extra2 += (void *)net - (void *)&init_net; | ||
| 1679 | } | 1685 | } |
| 1680 | } | 1686 | } |
| 1681 | 1687 | ||
| @@ -1747,6 +1747,10 @@ static int tcp_ao_delete_key(struct sock *sk, struct tcp_ao_info *ao_info, · 1746 unmodified lines | |||
| 1747 | * them and we can just free all resources in RCU fashion. | 1747 | * them and we can just free all resources in RCU fashion. |
| 1748 | */ | 1748 | */ |
| 1749 | if (del_async) { | 1749 | if (del_async) { |
| 1750 | if (ao_info->current_key == key) | ||
| 1751 | WRITE_ONCE(ao_info->current_key, NULL); | ||
| 1752 | if (ao_info->rnext_key == key) | ||
| 1753 | WRITE_ONCE(ao_info->rnext_key, NULL); | ||
| 1750 | atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc); | 1754 | atomic_sub(tcp_ao_sizeof_key(key), &sk->sk_omem_alloc); |
| 1751 | call_rcu(&key->rcu, tcp_ao_key_free_rcu); | 1755 | call_rcu(&key->rcu, tcp_ao_key_free_rcu); |
| 1752 | return 0; | 1756 | return 0; |
| @@ -2688,7 +2688,7 @@ static int tcp_mtu_probe(struct sock *sk) · 2687 unmodified lines | |||
| 2688 | struct sk_buff *skb, *nskb, *next; | 2688 | struct sk_buff *skb, *nskb, *next; |
| 2689 | struct net *net = sock_net(sk); | 2689 | struct net *net = sock_net(sk); |
| 2690 | int probe_size; | 2690 | int probe_size; |
| 2691 | int size_needed; | 2691 | u64 size_needed; |
| 2692 | int copy, len; | 2692 | int copy, len; |
| 2693 | int mss_now; | 2693 | int mss_now; |
| 2694 | int interval; | 2694 | int interval; |
| @@ -2712,7 +2712,7 @@ static int tcp_mtu_probe(struct sock *sk) · 17 unmodified lines | |||
| 2712 | mss_now = tcp_current_mss(sk); | 2712 | mss_now = tcp_current_mss(sk); |
| 2713 | probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high + | 2713 | probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high + |
| 2714 | icsk->icsk_mtup.search_low) >> 1); | 2714 | icsk->icsk_mtup.search_low) >> 1); |
| 2715 | size_needed = probe_size + (tp->reordering + 1) * tp->mss_cache; | 2715 | size_needed = probe_size + (tp->reordering + 1) * (u64)tp->mss_cache; |
| 2716 | interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low; | 2716 | interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low; |
| 2717 | /* When misfortune happens, we are reprobing actively, | 2717 | /* When misfortune happens, we are reprobing actively, |
| 2718 | * and then reprobe timer has expired. We stick with current | 2718 | * and then reprobe timer has expired. We stick with current |
| @@ -301,7 +301,7 @@ __udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn) · 300 unmodified lines | |||
| 301 | static void | 301 | static void |
| 302 | udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn) | 302 | udp_tunnel_nic_device_sync(struct net_device *dev, struct udp_tunnel_nic *utn) |
| 303 | { | 303 | { |
| 304 | if (!utn->need_sync) | 304 | if (!utn->need_sync || utn->work_pending) |
| 305 | return; | 305 | return; |
| 306 | 306 | ||
| 307 | queue_work(udp_tunnel_nic_workqueue, &utn->work); | 307 | queue_work(udp_tunnel_nic_workqueue, &utn->work); |
| @@ -76,8 +76,6 @@ int xfrm4_transport_finish(struct sk_buff *skb, int async) · 75 unmodified lines | |||
| 76 | NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, | 76 | NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, |
| 77 | dev_net(dev), NULL, skb, dev, NULL, | 77 | dev_net(dev), NULL, skb, dev, NULL, |
| 78 | xfrm4_rcv_encap_finish); | 78 | xfrm4_rcv_encap_finish); |
| 79 | if (async) | ||
| 80 | dev_put(dev); | ||
| 81 | return 0; | 79 | return 0; |
| 82 | } | 80 | } |
| 83 | 81 | ||
| @@ -913,7 +913,7 @@ static int addrconf_fixup_forwarding(const struct ctl_table *table, int *p, int · 912 unmodified lines | |||
| 913 | 913 | ||
| 914 | if (newf) | 914 | if (newf) |
| 915 | rt6_purge_dflt_routers(net); | 915 | rt6_purge_dflt_routers(net); |
| 916 | return 1; | 916 | return 0; |
| 917 | } | 917 | } |
| 918 | 918 | ||
| 919 | static void addrconf_linkdown_change(struct net *net, __s32 newf) | 919 | static void addrconf_linkdown_change(struct net *net, __s32 newf) |
| @@ -955,11 +955,7 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne · 35 unmodified lines | |||
| 955 | NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, | 955 | NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, |
| 956 | NETCONFA_IFINDEX_DEFAULT, | 956 | NETCONFA_IFINDEX_DEFAULT, |
| 957 | net->ipv6.devconf_dflt); | 957 | net->ipv6.devconf_dflt); |
| 958 | rtnl_net_unlock(net); | 958 | } else if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) { |
| 959 | return 0; | ||
| 960 | } | ||
| 961 | |||
| 962 | if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) { | ||
| 963 | WRITE_ONCE(net->ipv6.devconf_dflt->ignore_routes_with_linkdown, newf); | 959 | WRITE_ONCE(net->ipv6.devconf_dflt->ignore_routes_with_linkdown, newf); |
| 964 | addrconf_linkdown_change(net, newf); | 960 | addrconf_linkdown_change(net, newf); |
| 965 | if ((!newf) ^ (!old)) | 961 | if ((!newf) ^ (!old)) |
| @@ -968,11 +964,21 @@ static int addrconf_fixup_linkdown(const struct ctl_table *table, int *p, int ne · 2 unmodified lines | |||
| 968 | NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, | 964 | NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, |
| 969 | NETCONFA_IFINDEX_ALL, | 965 | NETCONFA_IFINDEX_ALL, |
| 970 | net->ipv6.devconf_all); | 966 | net->ipv6.devconf_all); |
| 967 | } else { | ||
| 968 | if (!newf ^ !old) { | ||
| 969 | struct inet6_dev *idev = table->extra1; | ||
| 970 | |||
| 971 | inet6_netconf_notify_devconf(net, | ||
| 972 | RTM_NEWNETCONF, | ||
| 973 | NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, | ||
| 974 | idev->dev->ifindex, | ||
| 975 | &idev->cnf); | ||
| 976 | } | ||
| 971 | } | 977 | } |
| 972 | 978 | ||
| 973 | rtnl_net_unlock(net); | 979 | rtnl_net_unlock(net); |
| 974 | 980 | ||
| 975 | return 1; | 981 | return 0; |
| 976 | } | 982 | } |
| 977 | 983 | ||
| 978 | #endif | 984 | #endif |
| @@ -6370,6 +6376,8 @@ static int addrconf_sysctl_forward(const struct ctl_table *ctl, int write, · 5391 unmodified lines | |||
| 6370 | lctl.data = &val; | 6376 | lctl.data = &val; |
| 6371 | 6377 | ||
| 6372 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | 6378 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); |
| 6379 | if (ret) | ||
| 6380 | return ret; | ||
| 6373 | 6381 | ||
| 6374 | if (write) | 6382 | if (write) |
| 6375 | ret = addrconf_fixup_forwarding(ctl, valp, val); | 6383 | ret = addrconf_fixup_forwarding(ctl, valp, val); |
| @@ -6467,6 +6475,8 @@ static int addrconf_sysctl_disable(const struct ctl_table *ctl, int write, · 91 unmodified lines | |||
| 6467 | lctl.data = &val; | 6475 | lctl.data = &val; |
| 6468 | 6476 | ||
| 6469 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | 6477 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); |
| 6478 | if (ret) | ||
| 6479 | return ret; | ||
| 6470 | 6480 | ||
| 6471 | if (write) | 6481 | if (write) |
| 6472 | ret = addrconf_disable_ipv6(ctl, valp, val); | 6482 | ret = addrconf_disable_ipv6(ctl, valp, val); |
| @@ -6478,20 +6488,19 @@ static int addrconf_sysctl_disable(const struct ctl_table *ctl, int write, · 5 unmodified lines | |||
| 6478 | static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write, | 6488 | static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write, |
| 6479 | void *buffer, size_t *lenp, loff_t *ppos) | 6489 | void *buffer, size_t *lenp, loff_t *ppos) |
| 6480 | { | 6490 | { |
| 6491 | struct net *net = ctl->extra2; | ||
| 6481 | int *valp = ctl->data; | 6492 | int *valp = ctl->data; |
| 6482 | int ret; | ||
| 6483 | int old, new; | 6493 | int old, new; |
| 6494 | int ret; | ||
| 6495 | |||
| 6496 | if (write && !rtnl_net_trylock(net)) | ||
| 6497 | return restart_syscall(); | ||
| 6484 | 6498 | ||
| 6485 | old = *valp; | 6499 | old = *valp; |
| 6486 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); | 6500 | ret = proc_dointvec(ctl, write, buffer, lenp, ppos); |
| 6487 | new = *valp; | 6501 | new = *valp; |
| 6488 | 6502 | ||
| 6489 | if (write && old != new) { | 6503 | if (write && old != new) { |
| 6490 | struct net *net = ctl->extra2; | ||
| 6491 | |||
| 6492 | if (!rtnl_net_trylock(net)) | ||
| 6493 | return restart_syscall(); | ||
| 6494 | |||
| 6495 | if (valp == &net->ipv6.devconf_dflt->proxy_ndp) { | 6504 | if (valp == &net->ipv6.devconf_dflt->proxy_ndp) { |
| 6496 | inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, | 6505 | inet6_netconf_notify_devconf(net, RTM_NEWNETCONF, |
| 6497 | NETCONFA_PROXY_NEIGH, | 6506 | NETCONFA_PROXY_NEIGH, |
| @@ -6510,8 +6519,9 @@ static int addrconf_sysctl_proxy_ndp(const struct ctl_table *ctl, int write, · 12 unmodified lines | |||
| 6510 | idev->dev->ifindex, | 6519 | idev->dev->ifindex, |
| 6511 | &idev->cnf); | 6520 | &idev->cnf); |
| 6512 | } | 6521 | } |
| 6513 | rtnl_net_unlock(net); | ||
| 6514 | } | 6522 | } |
| 6523 | if (write) | ||
| 6524 | rtnl_net_unlock(net); | ||
| 6515 | 6525 | ||
| 6516 | return ret; | 6526 | return ret; |
| 6517 | } | 6527 | } |
| @@ -6669,6 +6679,8 @@ int addrconf_sysctl_ignore_routes_with_linkdown(const struct ctl_table *ctl, · 151 unmodified lines | |||
| 6669 | lctl.data = &val; | 6679 | lctl.data = &val; |
| 6670 | 6680 | ||
| 6671 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | 6681 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); |
| 6682 | if (ret) | ||
| 6683 | return ret; | ||
| 6672 | 6684 | ||
| 6673 | if (write) | 6685 | if (write) |
| 6674 | ret = addrconf_fixup_linkdown(ctl, valp, val); | 6686 | ret = addrconf_fixup_linkdown(ctl, valp, val); |
| @@ -6763,6 +6775,8 @@ static int addrconf_sysctl_disable_policy(const struct ctl_table *ctl, int write · 88 unmodified lines | |||
| 6763 | lctl = *ctl; | 6775 | lctl = *ctl; |
| 6764 | lctl.data = &val; | 6776 | lctl.data = &val; |
| 6765 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); | 6777 | ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); |
| 6778 | if (ret) | ||
| 6779 | return ret; | ||
| 6766 | 6780 | ||
| 6767 | if (write && (*valp != val)) | 6781 | if (write && (*valp != val)) |
| 6768 | ret = addrconf_disable_policy(ctl, valp, val); | 6782 | ret = addrconf_disable_policy(ctl, valp, val); |
| @@ -35,7 +35,7 @@ struct ioam6_lwt_freq { · 34 unmodified lines | |||
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | struct ioam6_lwt { | 37 | struct ioam6_lwt { |
| 38 | struct dst_entry null_dst; | 38 | struct rt6_info null_rt; |
| 39 | struct dst_cache cache; | 39 | struct dst_cache cache; |
| 40 | struct ioam6_lwt_freq freq; | 40 | struct ioam6_lwt_freq freq; |
| 41 | atomic_t pkt_cnt; | 41 | atomic_t pkt_cnt; |
| @@ -176,7 +176,7 @@ static int ioam6_build_state(struct net *net, struct nlattr *nla, · 134 unmodified lines | |||
| 176 | * it is stored in the cache. Then, +1/-1 each time we read the cache | 176 | * it is stored in the cache. Then, +1/-1 each time we read the cache |
| 177 | * and release it. Long story short, we're fine. | 177 | * and release it. Long story short, we're fine. |
| 178 | */ | 178 | */ |
| 179 | dst_init(&ilwt->null_dst, NULL, NULL, DST_OBSOLETE_NONE, DST_NOCOUNT); | 179 | dst_init(&ilwt->null_rt.dst, NULL, NULL, DST_OBSOLETE_NONE, DST_NOCOUNT); |
| 180 | 180 | ||
| 181 | atomic_set(&ilwt->pkt_cnt, 0); | 181 | atomic_set(&ilwt->pkt_cnt, 0); |
| 182 | ilwt->freq.k = freq_k; | 182 | ilwt->freq.k = freq_k; |
| @@ -360,7 +360,7 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb) · 177 unmodified lines | |||
| 360 | /* This is how we notify that the destination does not change after | 360 | /* This is how we notify that the destination does not change after |
| 361 | * transformation and that we need to use orig_dst instead of the cache | 361 | * transformation and that we need to use orig_dst instead of the cache |
| 362 | */ | 362 | */ |
| 363 | if (dst == &ilwt->null_dst) { | 363 | if (dst == &ilwt->null_rt.dst) { |
| 364 | dst_release(dst); | 364 | dst_release(dst); |
| 365 | 365 | ||
| 366 | dst = orig_dst; | 366 | dst = orig_dst; |
| @@ -429,7 +429,7 @@ do_encap: · 62 unmodified lines | |||
| 429 | local_bh_disable(); | 429 | local_bh_disable(); |
| 430 | if (orig_dst->lwtstate == dst->lwtstate) | 430 | if (orig_dst->lwtstate == dst->lwtstate) |
| 431 | dst_cache_set_ip6(&ilwt->cache, | 431 | dst_cache_set_ip6(&ilwt->cache, |
| 432 | &ilwt->null_dst, &fl6.saddr); | 432 | &ilwt->null_rt.dst, &fl6.saddr); |
| 433 | else | 433 | else |
| 434 | dst_cache_set_ip6(&ilwt->cache, dst, &fl6.saddr); | 434 | dst_cache_set_ip6(&ilwt->cache, dst, &fl6.saddr); |
| 435 | local_bh_enable(); | 435 | local_bh_enable(); |
| @@ -2047,6 +2047,9 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], · 2046 unmodified lines | |||
| 2047 | struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); | 2047 | struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); |
| 2048 | struct __ip6_tnl_parm p; | 2048 | struct __ip6_tnl_parm p; |
| 2049 | 2049 | ||
| 2050 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 2051 | return -EPERM; | ||
| 2052 | |||
| 2050 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); | 2053 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); |
| 2051 | if (IS_ERR(t)) | 2054 | if (IS_ERR(t)) |
| 2052 | return PTR_ERR(t); | 2055 | return PTR_ERR(t); |
| @@ -2266,6 +2269,9 @@ static int ip6erspan_changelink(struct net_device *dev, struct nlattr *tb[], · 213 unmodified lines | |||
| 2266 | struct __ip6_tnl_parm p; | 2269 | struct __ip6_tnl_parm p; |
| 2267 | struct ip6gre_net *ign; | 2270 | struct ip6gre_net *ign; |
| 2268 | 2271 | ||
| 2272 | if (!rtnl_dev_link_net_capable(dev, t->net)) | ||
| 2273 | return -EPERM; | ||
| 2274 | |||
| 2269 | ign = net_generic(t->net, ip6gre_net_id); | 2275 | ign = net_generic(t->net, ip6gre_net_id); |
| 2270 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); | 2276 | t = ip6gre_changelink_common(dev, tb, data, &p, extack); |
| 2271 | if (IS_ERR(t)) | 2277 | if (IS_ERR(t)) |
| @@ -1667,8 +1667,8 @@ alloc_new_skb: · 1666 unmodified lines | |||
| 1667 | !(rt->dst.dev->features & NETIF_F_SG))) | 1667 | !(rt->dst.dev->features & NETIF_F_SG))) |
| 1668 | alloclen = fraglen; | 1668 | alloclen = fraglen; |
| 1669 | else { | 1669 | else { |
| 1670 | alloclen = fragheaderlen + transhdrlen; | 1670 | alloclen = fragheaderlen + transhdrlen + fraggap; |
| 1671 | pagedlen = datalen - transhdrlen; | 1671 | pagedlen = datalen - transhdrlen - fraggap; |
| 1672 | } | 1672 | } |
| 1673 | alloclen += alloc_extra; | 1673 | alloclen += alloc_extra; |
| 1674 | 1674 | ||
| @@ -1683,10 +1683,7 @@ alloc_new_skb: · 8 unmodified lines | |||
| 1683 | fraglen = datalen + fragheaderlen; | 1683 | fraglen = datalen + fragheaderlen; |
| 1684 | 1684 | ||
| 1685 | copy = datalen - transhdrlen - fraggap - pagedlen; | 1685 | copy = datalen - transhdrlen - fraggap - pagedlen; |
| 1686 | /* [!] NOTE: copy may be negative if pagedlen>0 | 1686 | if (copy < 0) { |
| 1687 | * because then the equation may reduces to -fraggap. | ||
| 1688 | */ | ||
| 1689 | if (copy < 0 && !(flags & MSG_SPLICE_PAGES)) { | ||
| 1690 | err = -EINVAL; | 1687 | err = -EINVAL; |
| 1691 | goto error; | 1688 | goto error; |
| 1692 | } | 1689 | } |
| @@ -1851,6 +1851,13 @@ static int ip6_tnl_fill_forward_path(struct net_device_path_ctx *ctx, · 1850 unmodified lines | |||
| 1851 | struct dst_entry *dst; | 1851 | struct dst_entry *dst; |
| 1852 | int err; | 1852 | int err; |
| 1853 | 1853 | ||
| 1854 | if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) { | ||
| 1855 | /* encaplimit option is currently not supported is | ||
| 1856 | * sw-acceleration path. | ||
| 1857 | */ | ||
| 1858 | return -EOPNOTSUPP; | ||
| 1859 | } | ||
| 1860 | |||
| 1854 | dst = ip6_route_output(dev_net(ctx->dev), NULL, &fl6); | 1861 | dst = ip6_route_output(dev_net(ctx->dev), NULL, &fl6); |
| 1855 | if (!dst->error) { | 1862 | if (!dst->error) { |
| 1856 | path->type = DEV_PATH_TUN; | 1863 | path->type = DEV_PATH_TUN; |
| @@ -2103,6 +2110,9 @@ static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], · 246 unmodified lines | |||
| 2103 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); | 2110 | struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); |
| 2104 | struct ip_tunnel_encap ipencap; | 2111 | struct ip_tunnel_encap ipencap; |
| 2105 | 2112 | ||
| 2113 | if (!rtnl_dev_link_net_capable(dev, net)) | ||
| 2114 | return -EPERM; | ||
| 2115 | |||
| 2106 | if (dev == ip6n->fb_tnl_dev) { | 2116 | if (dev == ip6n->fb_tnl_dev) { |
| 2107 | if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { | 2117 | if (ip_tunnel_netlink_encap_parms(data, &ipencap)) { |
| 2108 | /* iproute2 always sets TUNNEL_ENCAP_FLAG_CSUM6, so | 2118 | /* iproute2 always sets TUNNEL_ENCAP_FLAG_CSUM6, so |
| @@ -1046,6 +1046,9 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[], · 1045 unmodified lines | |||
| 1046 | struct __ip6_tnl_parm p; | 1046 | struct __ip6_tnl_parm p; |
| 1047 | struct vti6_net *ip6n; | 1047 | struct vti6_net *ip6n; |
| 1048 | 1048 | ||
| 1049 | if (!rtnl_dev_link_net_capable(dev, net)) | ||
| 1050 | return -EPERM; | ||
| 1051 | |||
| 1049 | ip6n = net_generic(net, vti6_net_id); | 1052 | ip6n = net_generic(net, vti6_net_id); |
| 1050 | if (dev == ip6n->fb_tnl_dev) | 1053 | if (dev == ip6n->fb_tnl_dev) |
| 1051 | return -EINVAL; | 1054 | return -EINVAL; |
| @@ -967,10 +967,8 @@ out: · 966 unmodified lines | |||
| 967 | return reason; | 967 | return reason; |
| 968 | } | 968 | } |
| 969 | 969 | ||
| 970 | static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr) | 970 | static int accept_untracked_na(struct inet6_dev *idev, struct in6_addr *saddr) |
| 971 | { | 971 | { |
| 972 | struct inet6_dev *idev = __in6_dev_get(dev); | ||
| 973 | |||
| 974 | switch (READ_ONCE(idev->cnf.accept_untracked_na)) { | 972 | switch (READ_ONCE(idev->cnf.accept_untracked_na)) { |
| 975 | case 0: /* Don't accept untracked na (absent in neighbor cache) */ | 973 | case 0: /* Don't accept untracked na (absent in neighbor cache) */ |
| 976 | return 0; | 974 | return 0; |
| @@ -980,7 +978,7 @@ static int accept_untracked_na(struct net_device *dev, struct in6_addr *saddr) · 3 unmodified lines | |||
| 980 | * same subnet as an address configured on the interface that | 978 | * same subnet as an address configured on the interface that |
| 981 | * received the na | 979 | * received the na |
| 982 | */ | 980 | */ |
| 983 | return !!ipv6_chk_prefix(saddr, dev); | 981 | return !!ipv6_chk_prefix(saddr, idev->dev); |
| 984 | default: | 982 | default: |
| 985 | return 0; | 983 | return 0; |
| 986 | } | 984 | } |
| @@ -1078,7 +1076,7 @@ static enum skb_drop_reason ndisc_recv_na(struct sk_buff *skb) · 91 unmodified lines | |||
| 1078 | */ | 1076 | */ |
| 1079 | new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE; | 1077 | new_state = msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE; |
| 1080 | if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) { | 1078 | if (!neigh && lladdr && idev && READ_ONCE(idev->cnf.forwarding)) { |
| 1081 | if (accept_untracked_na(dev, saddr)) { | 1079 | if (accept_untracked_na(idev, saddr)) { |
| 1082 | neigh = neigh_create(&nd_tbl, &msg->target, dev); | 1080 | neigh = neigh_create(&nd_tbl, &msg->target, dev); |
| 1083 | new_state = NUD_STALE; | 1081 | new_state = NUD_STALE; |
| 1084 | } | 1082 | } |
| @@ -5055,6 +5055,9 @@ static int fib6_nh_mtu_change(struct fib6_nh *nh, void *_arg) · 5054 unmodified lines | |||
| 5055 | struct inet6_dev *idev = __in6_dev_get(arg->dev); | 5055 | struct inet6_dev *idev = __in6_dev_get(arg->dev); |
| 5056 | u32 mtu = f6i->fib6_pmtu; | 5056 | u32 mtu = f6i->fib6_pmtu; |
| 5057 | 5057 | ||
| 5058 | if (!idev) | ||
| 5059 | return 0; | ||
| 5060 | |||
| 5058 | if (mtu >= arg->mtu || | 5061 | if (mtu >= arg->mtu || |
| 5059 | (mtu < arg->mtu && mtu == idev->cnf.mtu6)) | 5062 | (mtu < arg->mtu && mtu == idev->cnf.mtu6)) |
| 5060 | fib6_metric_set(f6i, RTAX_MTU, arg->mtu); | 5063 | fib6_metric_set(f6i, RTAX_MTU, arg->mtu); |
| @@ -1613,6 +1613,9 @@ static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], · 1612 unmodified lines | |||
| 1613 | __u32 fwmark = t->fwmark; | 1613 | __u32 fwmark = t->fwmark; |
| 1614 | int err; | 1614 | int err; |
| 1615 | 1615 | ||
| 1616 | if (!rtnl_dev_link_net_capable(dev, net)) | ||
| 1617 | return -EPERM; | ||
| 1618 | |||
| 1616 | if (dev == sitn->fb_tunnel_dev) | 1619 | if (dev == sitn->fb_tunnel_dev) |
| 1617 | return -EINVAL; | 1620 | return -EINVAL; |
| 1618 | 1621 | ||
| @@ -71,8 +71,6 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async) · 70 unmodified lines | |||
| 71 | NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, | 71 | NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, |
| 72 | dev_net(dev), NULL, skb, dev, NULL, | 72 | dev_net(dev), NULL, skb, dev, NULL, |
| 73 | xfrm6_transport_finish2); | 73 | xfrm6_transport_finish2); |
| 74 | if (async) | ||
| 75 | dev_put(dev); | ||
| 76 | return 0; | 74 | return 0; |
| 77 | } | 75 | } |
| 78 | 76 | ||
| @@ -1218,6 +1218,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, · 1217 unmodified lines | |||
| 1218 | goto out; | 1218 | goto out; |
| 1219 | } | 1219 | } |
| 1220 | strcpy(x->calg->alg_name, a->name); | 1220 | strcpy(x->calg->alg_name, a->name); |
| 1221 | x->calg->alg_key_len = 0; | ||
| 1221 | x->props.calgo = sa->sadb_sa_encrypt; | 1222 | x->props.calgo = sa->sadb_sa_encrypt; |
| 1222 | } else { | 1223 | } else { |
| 1223 | int keysize = 0; | 1224 | int keysize = 0; |
| @@ -47,7 +47,7 @@ static struct ctl_table_header *llc_station_header; · 46 unmodified lines | |||
| 47 | 47 | ||
| 48 | int __init llc_sysctl_init(void) | 48 | int __init llc_sysctl_init(void) |
| 49 | { | 49 | { |
| 50 | struct ctl_table empty[1] = {}; | 50 | static struct ctl_table empty[1] = {}; |
| 51 | llc2_timeout_header = register_net_sysctl(&init_net, "net/llc/llc2/timeout", llc2_timeout_table); | 51 | llc2_timeout_header = register_net_sysctl(&init_net, "net/llc/llc2/timeout", llc2_timeout_table); |
| 52 | llc_station_header = register_net_sysctl_sz(&init_net, "net/llc/station", empty, 0); | 52 | llc_station_header = register_net_sysctl_sz(&init_net, "net/llc/station", empty, 0); |
| 53 | 53 | ||
| @@ -710,6 +710,7 @@ int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb) · 709 unmodified lines | |||
| 710 | { | 710 | { |
| 711 | struct ieee802154_hdr hdr; | 711 | struct ieee802154_hdr hdr; |
| 712 | int rc, authlen, hlen; | 712 | int rc, authlen, hlen; |
| 713 | struct sk_buff *trailer; | ||
| 713 | struct mac802154_llsec_key *key; | 714 | struct mac802154_llsec_key *key; |
| 714 | u32 frame_ctr; | 715 | u32 frame_ctr; |
| 715 | 716 | ||
| @@ -769,6 +770,12 @@ int mac802154_llsec_encrypt(struct mac802154_llsec *sec, struct sk_buff *skb) · 53 unmodified lines | |||
| 769 | skb->mac_len = ieee802154_hdr_push(skb, &hdr); | 770 | skb->mac_len = ieee802154_hdr_push(skb, &hdr); |
| 770 | skb_reset_mac_header(skb); | 771 | skb_reset_mac_header(skb); |
| 771 | 772 | ||
| 773 | rc = skb_cow_data(skb, 0, &trailer); | ||
| 774 | if (rc < 0) { | ||
| 775 | llsec_key_put(key); | ||
| 776 | return rc; | ||
| 777 | } | ||
| 778 | |||
| 772 | rc = llsec_do_encrypt(skb, sec, &hdr, key); | 779 | rc = llsec_do_encrypt(skb, sec, &hdr, key); |
| 773 | llsec_key_put(key); | 780 | llsec_key_put(key); |
| 774 | 781 | ||
| @@ -908,6 +915,13 @@ llsec_do_decrypt(struct sk_buff *skb, const struct mac802154_llsec *sec, · 133 unmodified lines | |||
| 908 | const struct ieee802154_hdr *hdr, | 915 | const struct ieee802154_hdr *hdr, |
| 909 | struct mac802154_llsec_key *key, __le64 dev_addr) | 916 | struct mac802154_llsec_key *key, __le64 dev_addr) |
| 910 | { | 917 | { |
| 918 | struct sk_buff *trailer; | ||
| 919 | int err; | ||
| 920 | |||
| 921 | err = skb_cow_data(skb, 0, &trailer); | ||
| 922 | if (err < 0) | ||
| 923 | return err; | ||
| 924 | |||
| 911 | if (hdr->sec.level == IEEE802154_SCF_SECLEVEL_ENC) | 925 | if (hdr->sec.level == IEEE802154_SCF_SECLEVEL_ENC) |
| 912 | return llsec_do_decrypt_unauth(skb, sec, hdr, key, dev_addr); | 926 | return llsec_do_decrypt_unauth(skb, sec, hdr, key, dev_addr); |
| 913 | else | 927 | else |
| @@ -594,6 +594,7 @@ int mac802154_perform_association(struct ieee802154_sub_if_data *sdata, · 593 unmodified lines | |||
| 594 | "Negative ASSOC RESP received from %8phC: %s\n", &ceaddr, | 594 | "Negative ASSOC RESP received from %8phC: %s\n", &ceaddr, |
| 595 | local->assoc_status == IEEE802154_PAN_AT_CAPACITY ? | 595 | local->assoc_status == IEEE802154_PAN_AT_CAPACITY ? |
| 596 | "PAN at capacity" : "access denied"); | 596 | "PAN at capacity" : "access denied"); |
| 597 | goto clear_assoc; | ||
| 597 | } | 598 | } |
| 598 | 599 | ||
| 599 | ret = 0; | 600 | ret = 0; |
| @@ -256,8 +256,7 @@ config NF_CONNTRACK_H323 · 255 unmodified lines | |||
| 256 | To compile it as a module, choose M here. If unsure, say N. | 256 | To compile it as a module, choose M here. If unsure, say N. |
| 257 | 257 | ||
| 258 | config NF_CONNTRACK_IRC | 258 | config NF_CONNTRACK_IRC |
| 259 | tristate "IRC protocol support" | 259 | tristate "IRC DCC protocol support (obsolete)" |
| 260 | default m if NETFILTER_ADVANCED=n | ||
| 261 | help | 260 | help |
| 262 | There is a commonly-used extension to IRC called | 261 | There is a commonly-used extension to IRC called |
| 263 | Direct Client-to-Client Protocol (DCC). This enables users to send | 262 | Direct Client-to-Client Protocol (DCC). This enables users to send |
| @@ -267,6 +266,8 @@ config NF_CONNTRACK_IRC · 3 unmodified lines | |||
| 267 | using NAT, this extension will enable you to send files and initiate | 266 | using NAT, this extension will enable you to send files and initiate |
| 268 | chats. Note that you do NOT need this extension to get files or | 267 | chats. Note that you do NOT need this extension to get files or |
| 269 | have others initiate chats, or everything else in IRC. | 268 | have others initiate chats, or everything else in IRC. |
| 269 | DCC tracking behind NAT requires plaintext (unencrypted) IRC, so | ||
| 270 | this helper is of limited use these days. | ||
| 270 | 271 | ||
| 271 | To compile it as a module, choose M here. If unsure, say N. | 272 | To compile it as a module, choose M here. If unsure, say N. |
| 272 | 273 | ||
| @@ -308,17 +309,17 @@ config NF_CONNTRACK_SNMP · 35 unmodified lines | |||
| 308 | To compile it as a module, choose M here. If unsure, say N. | 309 | To compile it as a module, choose M here. If unsure, say N. |
| 309 | 310 | ||
| 310 | config NF_CONNTRACK_PPTP | 311 | config NF_CONNTRACK_PPTP |
| 311 | tristate "PPtP protocol support" | 312 | tristate "PPtP protocol support (deprecated)" |
| 312 | depends on NETFILTER_ADVANCED | 313 | depends on NETFILTER_ADVANCED |
| 313 | select NF_CT_PROTO_GRE | 314 | select NF_CT_PROTO_GRE |
| 314 | help | 315 | help |
| 315 | This module adds support for PPTP (Point to Point Tunnelling | 316 | This module adds support for PPTP (Point to Point Tunnelling |
| 316 | Protocol, RFC2637) connection tracking and NAT. | 317 | Protocol, RFC2637) connection tracking and NAT. |
| 317 | 318 | ||
| 318 | If you are running PPTP sessions over a stateful firewall or NAT | 319 | If you are still running PPTP sessions over a stateful firewall or NAT |
| 319 | box, you may want to enable this feature. | 320 | box, you may want to enable this feature. |
| 320 | 321 | ||
| 321 | Please note that not all PPTP modes of operation are supported yet. | 322 | Please note that not all PPTP modes of operation are supported. |
| 322 | Specifically these limitations exist: | 323 | Specifically these limitations exist: |
| 323 | - Blindly assumes that control connections are always established | 324 | - Blindly assumes that control connections are always established |
| 324 | in PNS->PAC direction. This is a violation of RFC2637. | 325 | in PNS->PAC direction. This is a violation of RFC2637. |
| @@ -165,6 +165,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext, · 164 unmodified lines | |||
| 165 | ip_set_init_skbinfo(ext_skbinfo(x, set), ext); | 165 | ip_set_init_skbinfo(ext_skbinfo(x, set), ext); |
| 166 | 166 | ||
| 167 | /* Activate element */ | 167 | /* Activate element */ |
| 168 | smp_mb__before_atomic(); | ||
| 168 | set_bit(e->id, map->members); | 169 | set_bit(e->id, map->members); |
| 169 | set->elements++; | 170 | set->elements++; |
| 170 | 171 | ||
| @@ -219,7 +220,7 @@ mtype_list(const struct ip_set *set, · 48 unmodified lines | |||
| 219 | cond_resched_rcu(); | 220 | cond_resched_rcu(); |
| 220 | id = cb->args[IPSET_CB_ARG0]; | 221 | id = cb->args[IPSET_CB_ARG0]; |
| 221 | x = get_ext(set, map, id); | 222 | x = get_ext(set, map, id); |
| 222 | if (!test_bit(id, map->members) || | 223 | if (!test_bit_acquire(id, map->members) || |
| 223 | (SET_WITH_TIMEOUT(set) && | 224 | (SET_WITH_TIMEOUT(set) && |
| 224 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT | 225 | #ifdef IP_SET_BITMAP_STORED_TIMEOUT |
| 225 | mtype_is_filled(x) && | 226 | mtype_is_filled(x) && |
| @@ -278,6 +279,7 @@ mtype_gc(struct timer_list *t) · 52 unmodified lines | |||
| 278 | x = get_ext(set, map, id); | 279 | x = get_ext(set, map, id); |
| 279 | if (ip_set_timeout_expired(ext_timeout(x, set))) { | 280 | if (ip_set_timeout_expired(ext_timeout(x, set))) { |
| 280 | clear_bit(id, map->members); | 281 | clear_bit(id, map->members); |
| 282 | smp_mb__after_atomic(); | ||
| 281 | ip_set_ext_destroy(set, x); | 283 | ip_set_ext_destroy(set, x); |
| 282 | set->elements--; | 284 | set->elements--; |
| 283 | } | 285 | } |
| @@ -67,7 +67,7 @@ static int · 66 unmodified lines | |||
| 67 | bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, | 67 | bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, |
| 68 | struct bitmap_ip *map, size_t dsize) | 68 | struct bitmap_ip *map, size_t dsize) |
| 69 | { | 69 | { |
| 70 | return !!test_bit(e->id, map->members); | 70 | return !!test_bit_acquire(e->id, map->members); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | static int | 73 | static int |
| @@ -86,7 +86,7 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, · 85 unmodified lines | |||
| 86 | { | 86 | { |
| 87 | const struct bitmap_ipmac_elem *elem; | 87 | const struct bitmap_ipmac_elem *elem; |
| 88 | 88 | ||
| 89 | if (!test_bit(e->id, map->members)) | 89 | if (!test_bit_acquire(e->id, map->members)) |
| 90 | return 0; | 90 | return 0; |
| 91 | elem = get_const_elem(map->extensions, e->id, dsize); | 91 | elem = get_const_elem(map->extensions, e->id, dsize); |
| 92 | if (e->add_mac && elem->filled == MAC_FILLED) | 92 | if (e->add_mac && elem->filled == MAC_FILLED) |
| @@ -58,7 +58,7 @@ static int · 57 unmodified lines | |||
| 58 | bitmap_port_do_test(const struct bitmap_port_adt_elem *e, | 58 | bitmap_port_do_test(const struct bitmap_port_adt_elem *e, |
| 59 | const struct bitmap_port *map, size_t dsize) | 59 | const struct bitmap_port *map, size_t dsize) |
| 60 | { | 60 | { |
| 61 | return !!test_bit(e->id, map->members); | 61 | return !!test_bit_acquire(e->id, map->members); |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static int | 64 | static int |
| @@ -351,8 +351,8 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment, · 350 unmodified lines | |||
| 351 | 351 | ||
| 352 | if (unlikely(c)) { | 352 | if (unlikely(c)) { |
| 353 | set->ext_size -= sizeof(*c) + strlen(c->str) + 1; | 353 | set->ext_size -= sizeof(*c) + strlen(c->str) + 1; |
| 354 | kfree_rcu(c, rcu); | ||
| 355 | rcu_assign_pointer(comment->c, NULL); | 354 | rcu_assign_pointer(comment->c, NULL); |
| 355 | kfree_rcu(c, rcu); | ||
| 356 | } | 356 | } |
| 357 | if (!len) | 357 | if (!len) |
| 358 | return; | 358 | return; |
| @@ -393,8 +393,8 @@ ip_set_comment_free(struct ip_set *set, void *ptr) · 34 unmodified lines | |||
| 393 | if (unlikely(!c)) | 393 | if (unlikely(!c)) |
| 394 | return; | 394 | return; |
| 395 | set->ext_size -= sizeof(*c) + strlen(c->str) + 1; | 395 | set->ext_size -= sizeof(*c) + strlen(c->str) + 1; |
| 396 | kfree_rcu(c, rcu); | ||
| 397 | rcu_assign_pointer(comment->c, NULL); | 396 | rcu_assign_pointer(comment->c, NULL); |
| 397 | kfree_rcu(c, rcu); | ||
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | typedef void (*destroyer)(struct ip_set *, void *); | 400 | typedef void (*destroyer)(struct ip_set *, void *); |
| @@ -606,7 +606,7 @@ mtype_cancel_gc(struct ip_set *set) · 605 unmodified lines | |||
| 606 | struct htype *h = set->data; | 606 | struct htype *h = set->data; |
| 607 | 607 | ||
| 608 | if (SET_WITH_TIMEOUT(set)) | 608 | if (SET_WITH_TIMEOUT(set)) |
| 609 | cancel_delayed_work_sync(&h->gc.dwork); | 609 | disable_delayed_work_sync(&h->gc.dwork); |
| 610 | } | 610 | } |
| 611 | 611 | ||
| 612 | static int | 612 | static int |
| @@ -689,7 +689,7 @@ retry: · 76 unmodified lines | |||
| 689 | continue; | 689 | continue; |
| 690 | pos = smp_load_acquire(&n->pos); | 690 | pos = smp_load_acquire(&n->pos); |
| 691 | for (j = 0; j < pos; j++) { | 691 | for (j = 0; j < pos; j++) { |
| 692 | if (!test_bit(j, n->used)) | 692 | if (!test_bit_acquire(j, n->used)) |
| 693 | continue; | 693 | continue; |
| 694 | data = ahash_data(n, j, dsize); | 694 | data = ahash_data(n, j, dsize); |
| 695 | if (SET_ELEM_EXPIRED(set, data)) | 695 | if (SET_ELEM_EXPIRED(set, data)) |
| @@ -826,7 +826,7 @@ mtype_ext_size(struct ip_set *set, u32 *elements, size_t *ext_size) · 130 unmodified lines | |||
| 826 | continue; | 826 | continue; |
| 827 | pos = smp_load_acquire(&n->pos); | 827 | pos = smp_load_acquire(&n->pos); |
| 828 | for (j = 0; j < pos; j++) { | 828 | for (j = 0; j < pos; j++) { |
| 829 | if (!test_bit(j, n->used)) | 829 | if (!test_bit_acquire(j, n->used)) |
| 830 | continue; | 830 | continue; |
| 831 | data = ahash_data(n, j, set->dsize); | 831 | data = ahash_data(n, j, set->dsize); |
| 832 | if (!SET_ELEM_EXPIRED(set, data)) | 832 | if (!SET_ELEM_EXPIRED(set, data)) |
| @@ -1201,7 +1201,7 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d, · 368 unmodified lines | |||
| 1201 | continue; | 1201 | continue; |
| 1202 | pos = smp_load_acquire(&n->pos); | 1202 | pos = smp_load_acquire(&n->pos); |
| 1203 | for (i = 0; i < pos; i++) { | 1203 | for (i = 0; i < pos; i++) { |
| 1204 | if (!test_bit(i, n->used)) | 1204 | if (!test_bit_acquire(i, n->used)) |
| 1205 | continue; | 1205 | continue; |
| 1206 | data = ahash_data(n, i, set->dsize); | 1206 | data = ahash_data(n, i, set->dsize); |
| 1207 | if (!mtype_data_equal(data, d, &multi)) | 1207 | if (!mtype_data_equal(data, d, &multi)) |
| @@ -1259,7 +1259,7 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext, · 51 unmodified lines | |||
| 1259 | } | 1259 | } |
| 1260 | pos = smp_load_acquire(&n->pos); | 1260 | pos = smp_load_acquire(&n->pos); |
| 1261 | for (i = 0; i < pos; i++) { | 1261 | for (i = 0; i < pos; i++) { |
| 1262 | if (!test_bit(i, n->used)) | 1262 | if (!test_bit_acquire(i, n->used)) |
| 1263 | continue; | 1263 | continue; |
| 1264 | data = ahash_data(n, i, set->dsize); | 1264 | data = ahash_data(n, i, set->dsize); |
| 1265 | if (!mtype_data_equal(data, d, &multi)) | 1265 | if (!mtype_data_equal(data, d, &multi)) |
| @@ -1396,7 +1396,7 @@ mtype_list(const struct ip_set *set, · 130 unmodified lines | |||
| 1396 | continue; | 1396 | continue; |
| 1397 | pos = smp_load_acquire(&n->pos); | 1397 | pos = smp_load_acquire(&n->pos); |
| 1398 | for (i = 0; i < pos; i++) { | 1398 | for (i = 0; i < pos; i++) { |
| 1399 | if (!test_bit(i, n->used)) | 1399 | if (!test_bit_acquire(i, n->used)) |
| 1400 | continue; | 1400 | continue; |
| 1401 | e = ahash_data(n, i, set->dsize); | 1401 | e = ahash_data(n, i, set->dsize); |
| 1402 | if (SET_ELEM_EXPIRED(set, e)) | 1402 | if (SET_ELEM_EXPIRED(set, e)) |
| @@ -183,17 +183,16 @@ static int __nf_conncount_add(struct net *net, · 182 unmodified lines | |||
| 183 | return -ENOENT; | 183 | return -ENOENT; |
| 184 | 184 | ||
| 185 | if (ct && nf_ct_is_confirmed(ct)) { | 185 | if (ct && nf_ct_is_confirmed(ct)) { |
| 186 | /* local connections are confirmed in postrouting so confirmation | 186 | /* Connection is confirmed but might still be in the setup phase. |
| 187 | * might have happened before hitting connlimit | 187 | * Only skip the tracking if it is fully assured. This guarantees |
| 188 | * that setup packets or retransmissions are properly counted and | ||
| 189 | * deduplicated. | ||
| 188 | */ | 190 | */ |
| 189 | if (skb->skb_iif != LOOPBACK_IFINDEX) { | 191 | if (test_bit(IPS_ASSURED_BIT, &ct->status)) { |
| 190 | err = -EEXIST; | 192 | err = -EEXIST; |
| 191 | goto out_put; | 193 | goto out_put; |
| 192 | } | 194 | } |
| 193 | 195 | ||
| 194 | /* this is likely a local connection, skip optimization to avoid | ||
| 195 | * adding duplicates from a 'packet train' | ||
| 196 | */ | ||
| 197 | goto check_connections; | 196 | goto check_connections; |
| 198 | } | 197 | } |
| 199 | 198 | ||
| @@ -62,6 +62,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, · 61 unmodified lines | |||
| 62 | if (exp == NULL) | 62 | if (exp == NULL) |
| 63 | goto out; | 63 | goto out; |
| 64 | 64 | ||
| 65 | exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
| 65 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | 66 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; |
| 66 | 67 | ||
| 67 | helper = rcu_dereference(help->helper); | 68 | helper = rcu_dereference(help->helper); |
| @@ -1471,6 +1471,31 @@ static bool gc_worker_can_early_drop(const struct nf_conn *ct) · 1470 unmodified lines | |||
| 1471 | return false; | 1471 | return false; |
| 1472 | } | 1472 | } |
| 1473 | 1473 | ||
| 1474 | static void nf_ct_help_gc(struct nf_conn *ct) | ||
| 1475 | { | ||
| 1476 | struct nf_conn_help *help; | ||
| 1477 | |||
| 1478 | if (!refcount_inc_not_zero(&ct->ct_general.use)) | ||
| 1479 | return; | ||
| 1480 | |||
| 1481 | /* load ->status after refcount increase */ | ||
| 1482 | smp_acquire__after_ctrl_dep(); | ||
| 1483 | |||
| 1484 | if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct)) { | ||
| 1485 | nf_ct_put(ct); | ||
| 1486 | return; | ||
| 1487 | } | ||
| 1488 | |||
| 1489 | /* re-check helper due to SLAB_TYPESAFE_BY_RCU */ | ||
| 1490 | if (test_bit(IPS_HELPER_BIT, &ct->status)) { | ||
| 1491 | help = nfct_help(ct); | ||
| 1492 | if (help) | ||
| 1493 | nf_ct_expectation_gc(help); | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | nf_ct_put(ct); | ||
| 1497 | } | ||
| 1498 | |||
| 1474 | static void gc_worker(struct work_struct *work) | 1499 | static void gc_worker(struct work_struct *work) |
| 1475 | { | 1500 | { |
| 1476 | unsigned int i, hashsz, nf_conntrack_max95 = 0; | 1501 | unsigned int i, hashsz, nf_conntrack_max95 = 0; |
| @@ -1543,7 +1568,13 @@ static void gc_worker(struct work_struct *work) · 66 unmodified lines | |||
| 1543 | expires = (expires - (long)next_run) / ++count; | 1568 | expires = (expires - (long)next_run) / ++count; |
| 1544 | next_run += expires; | 1569 | next_run += expires; |
| 1545 | 1570 | ||
| 1546 | if (nf_conntrack_max95 == 0 || gc_worker_skip_ct(tmp)) | 1571 | if (gc_worker_skip_ct(tmp)) |
| 1572 | continue; | ||
| 1573 | |||
| 1574 | if (test_bit(IPS_HELPER_BIT, &tmp->status)) | ||
| 1575 | nf_ct_help_gc(tmp); | ||
| 1576 | |||
| 1577 | if (nf_conntrack_max95 == 0) | ||
| 1547 | continue; | 1578 | continue; |
| 1548 | 1579 | ||
| 1549 | net = nf_ct_net(tmp); | 1580 | net = nf_ct_net(tmp); |
| @@ -43,6 +43,24 @@ unsigned int nf_ct_expect_max __read_mostly; · 42 unmodified lines | |||
| 43 | static struct kmem_cache *nf_ct_expect_cachep __read_mostly; | 43 | static struct kmem_cache *nf_ct_expect_cachep __read_mostly; |
| 44 | static siphash_aligned_key_t nf_ct_expect_hashrnd; | 44 | static siphash_aligned_key_t nf_ct_expect_hashrnd; |
| 45 | 45 | ||
| 46 | void nf_ct_expectation_gc(struct nf_conn_help *master_help) | ||
| 47 | { | ||
| 48 | struct nf_conntrack_expect *exp; | ||
| 49 | struct hlist_node *next; | ||
| 50 | |||
| 51 | if (hlist_empty(&master_help->expectations)) | ||
| 52 | return; | ||
| 53 | |||
| 54 | spin_lock_bh(&nf_conntrack_expect_lock); | ||
| 55 | hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) { | ||
| 56 | if (!nf_ct_exp_is_expired(exp)) | ||
| 57 | continue; | ||
| 58 | |||
| 59 | nf_ct_unlink_expect(exp); | ||
| 60 | } | ||
| 61 | spin_unlock_bh(&nf_conntrack_expect_lock); | ||
| 62 | } | ||
| 63 | |||
| 46 | /* nf_conntrack_expect helper functions */ | 64 | /* nf_conntrack_expect helper functions */ |
| 47 | void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, | 65 | void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, |
| 48 | u32 portid, int report) | 66 | u32 portid, int report) |
| @@ -52,7 +70,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, · 3 unmodified lines | |||
| 52 | struct nf_conntrack_net *cnet; | 70 | struct nf_conntrack_net *cnet; |
| 53 | 71 | ||
| 54 | lockdep_nfct_expect_lock_held(); | 72 | lockdep_nfct_expect_lock_held(); |
| 55 | WARN_ON_ONCE(timer_pending(&exp->timeout)); | ||
| 56 | 73 | ||
| 57 | hlist_del_rcu(&exp->hnode); | 74 | hlist_del_rcu(&exp->hnode); |
| 58 | 75 | ||
| @@ -70,16 +87,6 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, · 11 unmodified lines | |||
| 70 | } | 87 | } |
| 71 | EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report); | 88 | EXPORT_SYMBOL_GPL(nf_ct_unlink_expect_report); |
| 72 | 89 | ||
| 73 | static void nf_ct_expectation_timed_out(struct timer_list *t) | ||
| 74 | { | ||
| 75 | struct nf_conntrack_expect *exp = timer_container_of(exp, t, timeout); | ||
| 76 | |||
| 77 | spin_lock_bh(&nf_conntrack_expect_lock); | ||
| 78 | nf_ct_unlink_expect(exp); | ||
| 79 | spin_unlock_bh(&nf_conntrack_expect_lock); | ||
| 80 | nf_ct_expect_put(exp); | ||
| 81 | } | ||
| 82 | |||
| 83 | static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struct nf_conntrack_tuple *tuple) | 90 | static unsigned int nf_ct_expect_dst_hash(const struct net *n, const struct nf_conntrack_tuple *tuple) |
| 84 | { | 91 | { |
| 85 | struct { | 92 | struct { |
| @@ -117,19 +124,6 @@ nf_ct_exp_equal(const struct nf_conntrack_tuple *tuple, · 31 unmodified lines | |||
| 117 | nf_ct_exp_zone_equal_any(i, zone); | 124 | nf_ct_exp_zone_equal_any(i, zone); |
| 118 | } | 125 | } |
| 119 | 126 | ||
| 120 | bool nf_ct_remove_expect(struct nf_conntrack_expect *exp) | ||
| 121 | { | ||
| 122 | lockdep_nfct_expect_lock_held(); | ||
| 123 | |||
| 124 | if (timer_delete(&exp->timeout)) { | ||
| 125 | nf_ct_unlink_expect(exp); | ||
| 126 | nf_ct_expect_put(exp); | ||
| 127 | return true; | ||
| 128 | } | ||
| 129 | return false; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL_GPL(nf_ct_remove_expect); | ||
| 132 | |||
| 133 | struct nf_conntrack_expect * | 127 | struct nf_conntrack_expect * |
| 134 | __nf_ct_expect_find(struct net *net, | 128 | __nf_ct_expect_find(struct net *net, |
| 135 | const struct nf_conntrack_zone *zone, | 129 | const struct nf_conntrack_zone *zone, |
| @@ -144,6 +138,8 @@ __nf_ct_expect_find(struct net *net, · 8 unmodified lines | |||
| 144 | 138 | ||
| 145 | h = nf_ct_expect_dst_hash(net, tuple); | 139 | h = nf_ct_expect_dst_hash(net, tuple); |
| 146 | hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { | 140 | hlist_for_each_entry_rcu(i, &nf_ct_expect_hash[h], hnode) { |
| 141 | if (nf_ct_exp_is_expired(i)) | ||
| 142 | continue; | ||
| 147 | if (nf_ct_exp_equal(tuple, i, zone, net)) | 143 | if (nf_ct_exp_equal(tuple, i, zone, net)) |
| 148 | return i; | 144 | return i; |
| 149 | } | 145 | } |
| @@ -178,6 +174,7 @@ nf_ct_find_expectation(struct net *net, · 28 unmodified lines | |||
| 178 | { | 174 | { |
| 179 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); | 175 | struct nf_conntrack_net *cnet = nf_ct_pernet(net); |
| 180 | struct nf_conntrack_expect *i, *exp = NULL; | 176 | struct nf_conntrack_expect *i, *exp = NULL; |
| 177 | struct hlist_node *next; | ||
| 181 | unsigned int h; | 178 | unsigned int h; |
| 182 | 179 | ||
| 183 | lockdep_nfct_expect_lock_held(); | 180 | lockdep_nfct_expect_lock_held(); |
| @@ -186,7 +183,11 @@ nf_ct_find_expectation(struct net *net, · 2 unmodified lines | |||
| 186 | return NULL; | 183 | return NULL; |
| 187 | 184 | ||
| 188 | h = nf_ct_expect_dst_hash(net, tuple); | 185 | h = nf_ct_expect_dst_hash(net, tuple); |
| 189 | hlist_for_each_entry(i, &nf_ct_expect_hash[h], hnode) { | 186 | hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { |
| 187 | if (nf_ct_exp_is_expired(i)) { | ||
| 188 | nf_ct_unlink_expect(i); | ||
| 189 | continue; | ||
| 190 | } | ||
| 190 | if (!(i->flags & NF_CT_EXPECT_INACTIVE) && | 191 | if (!(i->flags & NF_CT_EXPECT_INACTIVE) && |
| 191 | nf_ct_exp_equal(tuple, i, zone, net)) { | 192 | nf_ct_exp_equal(tuple, i, zone, net)) { |
| 192 | exp = i; | 193 | exp = i; |
| @@ -196,13 +197,16 @@ nf_ct_find_expectation(struct net *net, · 3 unmodified lines | |||
| 196 | if (!exp) | 197 | if (!exp) |
| 197 | return NULL; | 198 | return NULL; |
| 198 | 199 | ||
| 200 | if (!refcount_inc_not_zero(&exp->use)) | ||
| 201 | return NULL; | ||
| 202 | |||
| 199 | /* If master is not in hash table yet (ie. packet hasn't left | 203 | /* If master is not in hash table yet (ie. packet hasn't left |
| 200 | this machine yet), how can other end know about expected? | 204 | this machine yet), how can other end know about expected? |
| 201 | Hence these are not the droids you are looking for (if | 205 | Hence these are not the droids you are looking for (if |
| 202 | master ct never got confirmed, we'd hold a reference to it | 206 | master ct never got confirmed, we'd hold a reference to it |
| 203 | and weird things would happen to future packets). */ | 207 | and weird things would happen to future packets). */ |
| 204 | if (!nf_ct_is_confirmed(exp->master)) | 208 | if (!nf_ct_is_confirmed(exp->master)) |
| 205 | return NULL; | 209 | goto err_release_exp; |
| 206 | 210 | ||
| 207 | /* Avoid race with other CPUs, that for exp->master ct, is | 211 | /* Avoid race with other CPUs, that for exp->master ct, is |
| 208 | * about to invoke ->destroy(), or nf_ct_delete() via timeout | 212 | * about to invoke ->destroy(), or nf_ct_delete() via timeout |
| @@ -214,18 +218,17 @@ nf_ct_find_expectation(struct net *net, · 5 unmodified lines | |||
| 214 | */ | 218 | */ |
| 215 | if (unlikely(nf_ct_is_dying(exp->master) || | 219 | if (unlikely(nf_ct_is_dying(exp->master) || |
| 216 | !refcount_inc_not_zero(&exp->master->ct_general.use))) | 220 | !refcount_inc_not_zero(&exp->master->ct_general.use))) |
| 217 | return NULL; | 221 | goto err_release_exp; |
| 218 | 222 | ||
| 219 | if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) { | 223 | if (exp->flags & NF_CT_EXPECT_PERMANENT || !unlink) |
| 220 | refcount_inc(&exp->use); | ||
| 221 | return exp; | 224 | return exp; |
| 222 | } else if (timer_delete(&exp->timeout)) { | ||
| 223 | nf_ct_unlink_expect(exp); | ||
| 224 | return exp; | ||
| 225 | } | ||
| 226 | /* Undo exp->master refcnt increase, if timer_delete() failed */ | ||
| 227 | nf_ct_put(exp->master); | ||
| 228 | 225 | ||
| 226 | nf_ct_unlink_expect(exp); | ||
| 227 | |||
| 228 | return exp; | ||
| 229 | |||
| 230 | err_release_exp: | ||
| 231 | nf_ct_expect_put(exp); | ||
| 229 | return NULL; | 232 | return NULL; |
| 230 | } | 233 | } |
| 231 | 234 | ||
| @@ -241,9 +244,8 @@ void nf_ct_remove_expectations(struct nf_conn *ct) · 9 unmodified lines | |||
| 241 | return; | 244 | return; |
| 242 | 245 | ||
| 243 | spin_lock_bh(&nf_conntrack_expect_lock); | 246 | spin_lock_bh(&nf_conntrack_expect_lock); |
| 244 | hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { | 247 | hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) |
| 245 | nf_ct_remove_expect(exp); | 248 | nf_ct_unlink_expect(exp); |
| 246 | } | ||
| 247 | spin_unlock_bh(&nf_conntrack_expect_lock); | 249 | spin_unlock_bh(&nf_conntrack_expect_lock); |
| 248 | } | 250 | } |
| 249 | EXPORT_SYMBOL_GPL(nf_ct_remove_expectations); | 251 | EXPORT_SYMBOL_GPL(nf_ct_remove_expectations); |
| @@ -292,7 +294,7 @@ static bool master_matches(const struct nf_conntrack_expect *a, · 42 unmodified lines | |||
| 292 | void nf_ct_unexpect_related(struct nf_conntrack_expect *exp) | 294 | void nf_ct_unexpect_related(struct nf_conntrack_expect *exp) |
| 293 | { | 295 | { |
| 294 | spin_lock_bh(&nf_conntrack_expect_lock); | 296 | spin_lock_bh(&nf_conntrack_expect_lock); |
| 295 | nf_ct_remove_expect(exp); | 297 | WRITE_ONCE(exp->flags, exp->flags | NF_CT_EXPECT_DEAD); |
| 296 | spin_unlock_bh(&nf_conntrack_expect_lock); | 298 | spin_unlock_bh(&nf_conntrack_expect_lock); |
| 297 | } | 299 | } |
| 298 | EXPORT_SYMBOL_GPL(nf_ct_unexpect_related); | 300 | EXPORT_SYMBOL_GPL(nf_ct_unexpect_related); |
| @@ -308,6 +310,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) · 9 unmodified lines | |||
| 308 | if (!new) | 310 | if (!new) |
| 309 | return NULL; | 311 | return NULL; |
| 310 | 312 | ||
| 313 | new->timeout = nfct_time_stamp; | ||
| 311 | new->master = me; | 314 | new->master = me; |
| 312 | refcount_set(&new->use, 1); | 315 | refcount_set(&new->use, 1); |
| 313 | return new; | 316 | return new; |
| @@ -352,6 +355,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, · 38 unmodified lines | |||
| 352 | exp->tuple.src.l3num = family; | 355 | exp->tuple.src.l3num = family; |
| 353 | exp->tuple.dst.protonum = proto; | 356 | exp->tuple.dst.protonum = proto; |
| 354 | 357 | ||
| 358 | exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
| 359 | |||
| 355 | if (saddr) { | 360 | if (saddr) { |
| 356 | memcpy(&exp->tuple.src.u3, saddr, len); | 361 | memcpy(&exp->tuple.src.u3, saddr, len); |
| 357 | if (sizeof(exp->tuple.src.u3) > len) | 362 | if (sizeof(exp->tuple.src.u3) > len) |
| @@ -413,17 +418,12 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp, · 55 unmodified lines | |||
| 413 | struct net *net = nf_ct_exp_net(exp); | 418 | struct net *net = nf_ct_exp_net(exp); |
| 414 | unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple); | 419 | unsigned int h = nf_ct_expect_dst_hash(net, &exp->tuple); |
| 415 | 420 | ||
| 416 | /* two references : one for hash insert, one for the timer */ | 421 | refcount_inc(&exp->use); |
| 417 | refcount_add(2, &exp->use); | ||
| 418 | 422 | ||
| 419 | timer_setup(&exp->timeout, nf_ct_expectation_timed_out, 0); | ||
| 420 | helper = rcu_dereference_protected(master_help->helper, | 423 | helper = rcu_dereference_protected(master_help->helper, |
| 421 | lockdep_is_held(&nf_conntrack_expect_lock)); | 424 | lockdep_is_held(&nf_conntrack_expect_lock)); |
| 422 | if (helper) { | 425 | if (helper) |
| 423 | exp->timeout.expires = jiffies + | 426 | exp->timeout += helper->expect_policy[exp->class].timeout * HZ; |
| 424 | helper->expect_policy[exp->class].timeout * HZ; | ||
| 425 | } | ||
| 426 | add_timer(&exp->timeout); | ||
| 427 | 427 | ||
| 428 | hlist_add_head_rcu(&exp->lnode, &master_help->expectations); | 428 | hlist_add_head_rcu(&exp->lnode, &master_help->expectations); |
| 429 | master_help->expecting[exp->class]++; | 429 | master_help->expecting[exp->class]++; |
| @@ -435,19 +435,26 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp, · 5 unmodified lines | |||
| 435 | NF_CT_STAT_INC(net, expect_create); | 435 | NF_CT_STAT_INC(net, expect_create); |
| 436 | } | 436 | } |
| 437 | 437 | ||
| 438 | /* Race with expectations being used means we could have none to find; OK. */ | ||
| 439 | static void evict_oldest_expect(struct nf_conn_help *master_help, | 438 | static void evict_oldest_expect(struct nf_conn_help *master_help, |
| 440 | struct nf_conntrack_expect *new) | 439 | struct nf_conntrack_expect *new, |
| 440 | const struct nf_conntrack_expect_policy *p) | ||
| 441 | { | 441 | { |
| 442 | struct nf_conntrack_expect *exp, *last = NULL; | 442 | struct nf_conntrack_expect *exp, *last = NULL; |
| 443 | struct hlist_node *next; | ||
| 443 | 444 | ||
| 444 | hlist_for_each_entry(exp, &master_help->expectations, lnode) { | 445 | hlist_for_each_entry_safe(exp, next, &master_help->expectations, lnode) { |
| 446 | if (nf_ct_exp_is_expired(exp)) { | ||
| 447 | nf_ct_unlink_expect(exp); | ||
| 448 | continue; | ||
| 449 | } | ||
| 445 | if (exp->class == new->class) | 450 | if (exp->class == new->class) |
| 446 | last = exp; | 451 | last = exp; |
| 447 | } | 452 | } |
| 448 | 453 | ||
| 449 | if (last) | 454 | /* Still worth to evict oldest expectation after garbage collection? */ |
| 450 | nf_ct_remove_expect(last); | 455 | if (last && |
| 456 | master_help->expecting[last->class] >= p->max_expected) | ||
| 457 | nf_ct_unlink_expect(last); | ||
| 451 | } | 458 | } |
| 452 | 459 | ||
| 453 | static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, | 460 | static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, |
| @@ -467,14 +474,18 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, · 13 unmodified lines | |||
| 467 | 474 | ||
| 468 | h = nf_ct_expect_dst_hash(net, &expect->tuple); | 475 | h = nf_ct_expect_dst_hash(net, &expect->tuple); |
| 469 | hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { | 476 | hlist_for_each_entry_safe(i, next, &nf_ct_expect_hash[h], hnode) { |
| 477 | if (nf_ct_exp_is_expired(i)) { | ||
| 478 | nf_ct_unlink_expect(i); | ||
| 479 | continue; | ||
| 480 | } | ||
| 470 | if (master_matches(i, expect, flags) && | 481 | if (master_matches(i, expect, flags) && |
| 471 | expect_matches(i, expect)) { | 482 | expect_matches(i, expect)) { |
| 472 | if (i->class != expect->class || | 483 | if (i->class != expect->class || |
| 473 | i->master != expect->master) | 484 | i->master != expect->master) |
| 474 | return -EALREADY; | 485 | return -EALREADY; |
| 475 | 486 | ||
| 476 | if (nf_ct_remove_expect(i)) | 487 | nf_ct_unlink_expect(i); |
| 477 | break; | 488 | break; |
| 478 | } else if (expect_clash(i, expect)) { | 489 | } else if (expect_clash(i, expect)) { |
| 479 | ret = -EBUSY; | 490 | ret = -EBUSY; |
| 480 | goto out; | 491 | goto out; |
| @@ -485,15 +496,15 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect, · 4 unmodified lines | |||
| 485 | lockdep_is_held(&nf_conntrack_expect_lock)); | 496 | lockdep_is_held(&nf_conntrack_expect_lock)); |
| 486 | if (helper) { | 497 | if (helper) { |
| 487 | p = &helper->expect_policy[expect->class]; | 498 | p = &helper->expect_policy[expect->class]; |
| 488 | if (p->max_expected && | 499 | if (master_help->expecting[expect->class] >= p->max_expected) |
| 489 | master_help->expecting[expect->class] >= p->max_expected) { | 500 | evict_oldest_expect(master_help, expect, p); |
| 490 | evict_oldest_expect(master_help, expect); | 501 | } else { |
| 491 | if (master_help->expecting[expect->class] | 502 | const struct nf_conntrack_expect_policy default_exp_policy = { |
| 492 | >= p->max_expected) { | 503 | .max_expected = NF_CT_EXPECT_MAX_CNT, |
| 493 | ret = -EMFILE; | 504 | }; |
| 494 | goto out; | 505 | |
| 495 | } | 506 | if (master_help->expecting[expect->class] >= default_exp_policy.max_expected) |
| 496 | } | 507 | evict_oldest_expect(master_help, expect, &default_exp_policy); |
| 497 | } | 508 | } |
| 498 | 509 | ||
| 499 | cnet = nf_ct_pernet(net); | 510 | cnet = nf_ct_pernet(net); |
| @@ -547,10 +558,8 @@ void nf_ct_expect_iterate_destroy(bool (*iter)(struct nf_conntrack_expect *e, vo · 47 unmodified lines | |||
| 547 | hlist_for_each_entry_safe(exp, next, | 558 | hlist_for_each_entry_safe(exp, next, |
| 548 | &nf_ct_expect_hash[i], | 559 | &nf_ct_expect_hash[i], |
| 549 | hnode) { | 560 | hnode) { |
| 550 | if (iter(exp, data) && timer_delete(&exp->timeout)) { | 561 | if (iter(exp, data)) |
| 551 | nf_ct_unlink_expect(exp); | 562 | nf_ct_unlink_expect(exp); |
| 552 | nf_ct_expect_put(exp); | ||
| 553 | } | ||
| 554 | } | 563 | } |
| 555 | } | 564 | } |
| 556 | 565 | ||
| @@ -577,10 +586,8 @@ void nf_ct_expect_iterate_net(struct net *net, · 20 unmodified lines | |||
| 577 | if (!net_eq(nf_ct_exp_net(exp), net)) | 586 | if (!net_eq(nf_ct_exp_net(exp), net)) |
| 578 | continue; | 587 | continue; |
| 579 | 588 | ||
| 580 | if (iter(exp, data) && timer_delete(&exp->timeout)) { | 589 | if (iter(exp, data)) |
| 581 | nf_ct_unlink_expect_report(exp, portid, report); | 590 | nf_ct_unlink_expect_report(exp, portid, report); |
| 582 | nf_ct_expect_put(exp); | ||
| 583 | } | ||
| 584 | } | 591 | } |
| 585 | } | 592 | } |
| 586 | 593 | ||
| @@ -657,17 +664,17 @@ static int exp_seq_show(struct seq_file *s, void *v) · 70 unmodified lines | |||
| 657 | struct net *net = seq_file_net(s); | 664 | struct net *net = seq_file_net(s); |
| 658 | struct hlist_node *n = v; | 665 | struct hlist_node *n = v; |
| 659 | char *delim = ""; | 666 | char *delim = ""; |
| 667 | __s32 timeout; | ||
| 660 | 668 | ||
| 661 | expect = hlist_entry(n, struct nf_conntrack_expect, hnode); | 669 | expect = hlist_entry(n, struct nf_conntrack_expect, hnode); |
| 662 | 670 | ||
| 663 | if (!net_eq(nf_ct_exp_net(expect), net)) | 671 | if (!net_eq(nf_ct_exp_net(expect), net)) |
| 664 | return 0; | 672 | return 0; |
| 673 | if (nf_ct_exp_is_expired(expect)) | ||
| 674 | return 0; | ||
| 665 | 675 | ||
| 666 | if (expect->timeout.function) | 676 | timeout = (__s32)(READ_ONCE(expect->timeout) - nfct_time_stamp) / HZ; |
| 667 | seq_printf(s, "%ld ", timer_pending(&expect->timeout) | 677 | seq_printf(s, "%d ", timeout > 0 ? timeout : 0); |
| 668 | ? (long)(expect->timeout.expires - jiffies)/HZ : 0); | ||
| 669 | else | ||
| 670 | seq_puts(s, "- "); | ||
| 671 | seq_printf(s, "l3proto = %u proto=%u ", | 678 | seq_printf(s, "l3proto = %u proto=%u ", |
| 672 | expect->tuple.src.l3num, | 679 | expect->tuple.src.l3num, |
| 673 | expect->tuple.dst.protonum); | 680 | expect->tuple.dst.protonum); |
| @@ -1388,8 +1388,8 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, · 1387 unmodified lines | |||
| 1388 | "timeout to %u seconds for", | 1388 | "timeout to %u seconds for", |
| 1389 | info->timeout); | 1389 | info->timeout); |
| 1390 | nf_ct_dump_tuple(&exp->tuple); | 1390 | nf_ct_dump_tuple(&exp->tuple); |
| 1391 | mod_timer_pending(&exp->timeout, | 1391 | WRITE_ONCE(exp->timeout, |
| 1392 | jiffies + info->timeout * HZ); | 1392 | nfct_time_stamp + (info->timeout * HZ)); |
| 1393 | } | 1393 | } |
| 1394 | spin_unlock_bh(&nf_conntrack_expect_lock); | 1394 | spin_unlock_bh(&nf_conntrack_expect_lock); |
| 1395 | } | 1395 | } |
| @@ -181,10 +181,10 @@ nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) · 180 unmodified lines | |||
| 181 | struct nf_conn_help *help; | 181 | struct nf_conn_help *help; |
| 182 | 182 | ||
| 183 | help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp); | 183 | help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp); |
| 184 | if (help) | 184 | if (help) { |
| 185 | __set_bit(IPS_HELPER_BIT, &ct->status); | ||
| 185 | INIT_HLIST_HEAD(&help->expectations); | 186 | INIT_HLIST_HEAD(&help->expectations); |
| 186 | else | 187 | } |
| 187 | pr_debug("failed to add helper extension area"); | ||
| 188 | return help; | 188 | return help; |
| 189 | } | 189 | } |
| 190 | EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); | 190 | EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); |
| @@ -203,10 +203,8 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, · 12 unmodified lines | |||
| 203 | return 0; | 203 | return 0; |
| 204 | 204 | ||
| 205 | help = nfct_help(tmpl); | 205 | help = nfct_help(tmpl); |
| 206 | if (help != NULL) { | 206 | if (help) |
| 207 | helper = rcu_dereference(help->helper); | 207 | helper = rcu_dereference(help->helper); |
| 208 | set_bit(IPS_HELPER_BIT, &ct->status); | ||
| 209 | } | ||
| 210 | 208 | ||
| 211 | help = nfct_help(ct); | 209 | help = nfct_help(ct); |
| 212 | 210 | ||
| @@ -376,8 +374,13 @@ int __nf_conntrack_helper_register(struct nf_conntrack_helper *me) · 163 unmodified lines | |||
| 376 | if (!nf_ct_helper_hash) | 374 | if (!nf_ct_helper_hash) |
| 377 | return -ENOENT; | 375 | return -ENOENT; |
| 378 | 376 | ||
| 379 | if (me->expect_policy->max_expected > NF_CT_EXPECT_MAX_CNT) | 377 | for (i = 0; i <= me->expect_class_max; i++) { |
| 380 | return -EINVAL; | 378 | if (!me->expect_policy[i].max_expected) |
| 379 | me->expect_policy[i].max_expected = NF_CT_EXPECT_MAX_CNT; | ||
| 380 | |||
| 381 | if (me->expect_policy[i].max_expected > NF_CT_EXPECT_MAX_CNT) | ||
| 382 | return -EINVAL; | ||
| 383 | } | ||
| 381 | 384 | ||
| 382 | mutex_lock(&nf_ct_helper_mutex); | 385 | mutex_lock(&nf_ct_helper_mutex); |
| 383 | for (i = 0; i < nf_ct_helper_hsize; i++) { | 386 | for (i = 0; i < nf_ct_helper_hsize; i++) { |
| @@ -262,6 +262,8 @@ static int __init nf_conntrack_irc_init(void) · 261 unmodified lines | |||
| 262 | { | 262 | { |
| 263 | int i, ret; | 263 | int i, ret; |
| 264 | 264 | ||
| 265 | nf_conntrack_helper_deprecated(HELPER_NAME); | ||
| 266 | |||
| 265 | if (max_dcc_channels < 1) { | 267 | if (max_dcc_channels < 1) { |
| 266 | pr_err("max_dcc_channels must not be zero\n"); | 268 | pr_err("max_dcc_channels must not be zero\n"); |
| 267 | return -EINVAL; | 269 | return -EINVAL; |
| @@ -1953,19 +1953,6 @@ static int ctnetlink_change_helper(struct nf_conn *ct, · 1952 unmodified lines | |||
| 1953 | return err; | 1953 | return err; |
| 1954 | } | 1954 | } |
| 1955 | 1955 | ||
| 1956 | if (!strcmp(helpname, "") && help) { | ||
| 1957 | helper = rcu_dereference(help->helper); | ||
| 1958 | if (helper) { | ||
| 1959 | /* we had a helper before ... */ | ||
| 1960 | nf_ct_remove_expectations(ct); | ||
| 1961 | RCU_INIT_POINTER(help->helper, NULL); | ||
| 1962 | if (refcount_dec_and_test(&helper->ct_refcnt)) | ||
| 1963 | kfree_rcu(helper, rcu); | ||
| 1964 | } | ||
| 1965 | rcu_read_unlock(); | ||
| 1966 | return 0; | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), | 1956 | helper = __nf_conntrack_helper_find(helpname, nf_ct_l3num(ct), |
| 1970 | nf_ct_protonum(ct)); | 1957 | nf_ct_protonum(ct)); |
| 1971 | if (helper == NULL) { | 1958 | if (helper == NULL) { |
| @@ -3014,8 +3001,7 @@ static int · 1042 unmodified lines | |||
| 3014 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | 3001 | ctnetlink_exp_dump_expect(struct sk_buff *skb, |
| 3015 | const struct nf_conntrack_expect *exp) | 3002 | const struct nf_conntrack_expect *exp) |
| 3016 | { | 3003 | { |
| 3017 | struct nf_conn *master = exp->master; | 3004 | __s32 timeout = (__s32)(READ_ONCE(exp->timeout) - nfct_time_stamp) / HZ; |
| 3018 | long timeout = ((long)exp->timeout.expires - (long)jiffies) / HZ; | ||
| 3019 | struct nf_conntrack_helper *helper; | 3005 | struct nf_conntrack_helper *helper; |
| 3020 | #if IS_ENABLED(CONFIG_NF_NAT) | 3006 | #if IS_ENABLED(CONFIG_NF_NAT) |
| 3021 | struct nlattr *nest_parms; | 3007 | struct nlattr *nest_parms; |
| @@ -3030,9 +3016,7 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, · 8 unmodified lines | |||
| 3030 | goto nla_put_failure; | 3016 | goto nla_put_failure; |
| 3031 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) | 3017 | if (ctnetlink_exp_dump_mask(skb, &exp->tuple, &exp->mask) < 0) |
| 3032 | goto nla_put_failure; | 3018 | goto nla_put_failure; |
| 3033 | if (ctnetlink_exp_dump_tuple(skb, | 3019 | if (ctnetlink_exp_dump_tuple(skb, &exp->master_tuple, CTA_EXPECT_MASTER) < 0) |
| 3034 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
| 3035 | CTA_EXPECT_MASTER) < 0) | ||
| 3036 | goto nla_put_failure; | 3020 | goto nla_put_failure; |
| 3037 | 3021 | ||
| 3038 | #if IS_ENABLED(CONFIG_NF_NAT) | 3022 | #if IS_ENABLED(CONFIG_NF_NAT) |
| @@ -3045,9 +3029,9 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, · 6 unmodified lines | |||
| 3045 | if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir))) | 3029 | if (nla_put_be32(skb, CTA_EXPECT_NAT_DIR, htonl(exp->dir))) |
| 3046 | goto nla_put_failure; | 3030 | goto nla_put_failure; |
| 3047 | 3031 | ||
| 3048 | nat_tuple.src.l3num = nf_ct_l3num(master); | 3032 | nat_tuple.src.l3num = exp->master_tuple.src.l3num; |
| 3049 | nat_tuple.src.u3 = exp->saved_addr; | 3033 | nat_tuple.src.u3 = exp->saved_addr; |
| 3050 | nat_tuple.dst.protonum = nf_ct_protonum(master); | 3034 | nat_tuple.dst.protonum = exp->master_tuple.dst.protonum; |
| 3051 | nat_tuple.src.u = exp->saved_proto; | 3035 | nat_tuple.src.u = exp->saved_proto; |
| 3052 | 3036 | ||
| 3053 | if (ctnetlink_exp_dump_tuple(skb, &nat_tuple, | 3037 | if (ctnetlink_exp_dump_tuple(skb, &nat_tuple, |
| @@ -3178,6 +3162,9 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) · 124 unmodified lines | |||
| 3178 | restart: | 3162 | restart: |
| 3179 | hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]], | 3163 | hlist_for_each_entry_rcu(exp, &nf_ct_expect_hash[cb->args[0]], |
| 3180 | hnode) { | 3164 | hnode) { |
| 3165 | if (nf_ct_exp_is_expired(exp)) | ||
| 3166 | continue; | ||
| 3167 | |||
| 3181 | if (l3proto && exp->tuple.src.l3num != l3proto) | 3168 | if (l3proto && exp->tuple.src.l3num != l3proto) |
| 3182 | continue; | 3169 | continue; |
| 3183 | 3170 | ||
| @@ -3456,11 +3443,8 @@ static int ctnetlink_del_expect(struct sk_buff *skb, · 272 unmodified lines | |||
| 3456 | } | 3443 | } |
| 3457 | 3444 | ||
| 3458 | /* after list removal, usage count == 1 */ | 3445 | /* after list removal, usage count == 1 */ |
| 3459 | if (timer_delete(&exp->timeout)) { | 3446 | nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, |
| 3460 | nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid, | 3447 | nlmsg_report(info->nlh)); |
| 3461 | nlmsg_report(info->nlh)); | ||
| 3462 | nf_ct_expect_put(exp); | ||
| 3463 | } | ||
| 3464 | spin_unlock_bh(&nf_conntrack_expect_lock); | 3448 | spin_unlock_bh(&nf_conntrack_expect_lock); |
| 3465 | /* have to put what we 'get' above. | 3449 | /* have to put what we 'get' above. |
| 3466 | * after this line usage count == 0 */ | 3450 | * after this line usage count == 0 */ |
| @@ -3484,14 +3468,10 @@ static int · 17 unmodified lines | |||
| 3484 | ctnetlink_change_expect(struct nf_conntrack_expect *x, | 3468 | ctnetlink_change_expect(struct nf_conntrack_expect *x, |
| 3485 | const struct nlattr * const cda[]) | 3469 | const struct nlattr * const cda[]) |
| 3486 | { | 3470 | { |
| 3487 | if (cda[CTA_EXPECT_TIMEOUT]) { | 3471 | if (cda[CTA_EXPECT_TIMEOUT]) |
| 3488 | if (!timer_delete(&x->timeout)) | 3472 | WRITE_ONCE(x->timeout, nfct_time_stamp + |
| 3489 | return -ETIME; | 3473 | ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ); |
| 3490 | 3474 | ||
| 3491 | x->timeout.expires = jiffies + | ||
| 3492 | ntohl(nla_get_be32(cda[CTA_EXPECT_TIMEOUT])) * HZ; | ||
| 3493 | add_timer(&x->timeout); | ||
| 3494 | } | ||
| 3495 | return 0; | 3475 | return 0; |
| 3496 | } | 3476 | } |
| 3497 | 3477 | ||
| @@ -3593,6 +3573,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, · 95 unmodified lines | |||
| 3593 | #endif | 3573 | #endif |
| 3594 | rcu_assign_pointer(exp->helper, helper); | 3574 | rcu_assign_pointer(exp->helper, helper); |
| 3595 | rcu_assign_pointer(exp->assign_helper, assign_helper); | 3575 | rcu_assign_pointer(exp->assign_helper, assign_helper); |
| 3576 | exp->master_tuple = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; | ||
| 3596 | exp->tuple = *tuple; | 3577 | exp->tuple = *tuple; |
| 3597 | exp->mask.src.u3 = mask->src.u3; | 3578 | exp->mask.src.u3 = mask->src.u3; |
| 3598 | exp->mask.src.u.all = mask->src.u.all; | 3579 | exp->mask.src.u.all = mask->src.u.all; |
| @@ -545,6 +545,8 @@ static int __init nf_conntrack_pptp_init(void) · 544 unmodified lines | |||
| 545 | 545 | ||
| 546 | pptp.destroy = gre_pptp_destroy_siblings; | 546 | pptp.destroy = gre_pptp_destroy_siblings; |
| 547 | 547 | ||
| 548 | nf_conntrack_helper_deprecated(pptp.name); | ||
| 549 | |||
| 548 | return nf_conntrack_helper_register(&pptp, &pptp_ptr); | 550 | return nf_conntrack_helper_register(&pptp, &pptp_ptr); |
| 549 | } | 551 | } |
| 550 | 552 | ||
| @@ -897,11 +897,10 @@ static int refresh_signalling_expectation(struct nf_conn *ct, · 896 unmodified lines | |||
| 897 | exp->tuple.dst.protonum != proto || | 897 | exp->tuple.dst.protonum != proto || |
| 898 | exp->tuple.dst.u.udp.port != port) | 898 | exp->tuple.dst.u.udp.port != port) |
| 899 | continue; | 899 | continue; |
| 900 | if (mod_timer_pending(&exp->timeout, jiffies + expires * HZ)) { | 900 | WRITE_ONCE(exp->timeout, nfct_time_stamp + (expires * HZ)); |
| 901 | exp->flags &= ~NF_CT_EXPECT_INACTIVE; | 901 | WRITE_ONCE(exp->flags, exp->flags & ~NF_CT_EXPECT_INACTIVE); |
| 902 | found = 1; | 902 | found = 1; |
| 903 | break; | 903 | break; |
| 904 | } | ||
| 905 | } | 904 | } |
| 906 | spin_unlock_bh(&nf_conntrack_expect_lock); | 905 | spin_unlock_bh(&nf_conntrack_expect_lock); |
| 907 | return found; | 906 | return found; |
| @@ -920,8 +919,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) · 12 unmodified lines | |||
| 920 | hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { | 919 | hlist_for_each_entry_safe(exp, next, &help->expectations, lnode) { |
| 921 | if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) | 920 | if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) |
| 922 | continue; | 921 | continue; |
| 923 | if (!nf_ct_remove_expect(exp)) | 922 | nf_ct_unlink_expect(exp); |
| 924 | continue; | ||
| 925 | if (!media) | 923 | if (!media) |
| 926 | break; | 924 | break; |
| 927 | } | 925 | } |
| @@ -1413,7 +1411,6 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, · 485 unmodified lines | |||
| 1413 | 1411 | ||
| 1414 | nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), | 1412 | nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), |
| 1415 | saddr, &daddr, proto, NULL, &port); | 1413 | saddr, &daddr, proto, NULL, &port); |
| 1416 | exp->timeout.expires = sip_timeout * HZ; | ||
| 1417 | rcu_assign_pointer(exp->assign_helper, helper); | 1414 | rcu_assign_pointer(exp->assign_helper, helper); |
| 1418 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; | 1415 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; |
| 1419 | 1416 | ||
| @@ -505,8 +505,13 @@ static u32 nf_flow_table_tcp_timeout(const struct nf_conn *ct) · 504 unmodified lines | |||
| 505 | */ | 505 | */ |
| 506 | static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct) | 506 | static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct) |
| 507 | { | 507 | { |
| 508 | static const u32 min_timeout = 5 * 60 * HZ; | 508 | static const s32 min_timeout = 5 * 60 * HZ; |
| 509 | u32 expires = nf_ct_expires(ct); | 509 | u32 ct_timeout = READ_ONCE(ct->timeout); |
| 510 | s32 expires; | ||
| 511 | |||
| 512 | expires = ct_timeout - nfct_time_stamp; | ||
| 513 | if (expires <= 0) /* already expired */ | ||
| 514 | return; | ||
| 510 | 515 | ||
| 511 | /* normal case: large enough timeout, nothing to do. */ | 516 | /* normal case: large enough timeout, nothing to do. */ |
| 512 | if (likely(expires >= min_timeout)) | 517 | if (likely(expires >= min_timeout)) |
| @@ -524,7 +529,7 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct) · 11 unmodified lines | |||
| 524 | if (nf_ct_is_confirmed(ct) && | 529 | if (nf_ct_is_confirmed(ct) && |
| 525 | test_bit(IPS_OFFLOAD_BIT, &ct->status)) { | 530 | test_bit(IPS_OFFLOAD_BIT, &ct->status)) { |
| 526 | u8 l4proto = nf_ct_protonum(ct); | 531 | u8 l4proto = nf_ct_protonum(ct); |
| 527 | u32 new_timeout = true; | 532 | u32 new_timeout = 1; |
| 528 | 533 | ||
| 529 | switch (l4proto) { | 534 | switch (l4proto) { |
| 530 | case IPPROTO_UDP: | 535 | case IPPROTO_UDP: |
| @@ -549,7 +554,7 @@ static void nf_flow_table_extend_ct_timeout(struct nf_conn *ct) · 18 unmodified lines | |||
| 549 | */ | 554 | */ |
| 550 | if (new_timeout) { | 555 | if (new_timeout) { |
| 551 | new_timeout += nfct_time_stamp; | 556 | new_timeout += nfct_time_stamp; |
| 552 | cmpxchg(&ct->timeout, expires, new_timeout); | 557 | cmpxchg(&ct->timeout, ct_timeout, new_timeout); |
| 553 | } | 558 | } |
| 554 | } | 559 | } |
| 555 | 560 | ||
| @@ -326,8 +326,10 @@ static bool nf_flow_ip4_tunnel_proto(struct nf_flowtable_ctx *ctx, · 325 unmodified lines | |||
| 326 | return false; | 326 | return false; |
| 327 | 327 | ||
| 328 | iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset); | 328 | iph = (struct iphdr *)(skb_network_header(skb) + ctx->offset); |
| 329 | size = iph->ihl << 2; | 329 | if (iph->ihl < 5) |
| 330 | return false; | ||
| 330 | 331 | ||
| 332 | size = iph->ihl << 2; | ||
| 331 | if (ip_is_fragment(iph) || unlikely(ip_has_options(size))) | 333 | if (ip_is_fragment(iph) || unlikely(ip_has_options(size))) |
| 332 | return false; | 334 | return false; |
| 333 | 335 | ||
| @@ -335,9 +337,9 @@ static bool nf_flow_ip4_tunnel_proto(struct nf_flowtable_ctx *ctx, · 1 unmodified line | |||
| 335 | return false; | 337 | return false; |
| 336 | 338 | ||
| 337 | if (iph->protocol == IPPROTO_IPIP) { | 339 | if (iph->protocol == IPPROTO_IPIP) { |
| 338 | ctx->tun.proto = IPPROTO_IPIP; | 340 | ctx->tun.proto = iph->protocol; |
| 339 | ctx->tun.hdr_size = size; | 341 | ctx->tun.hdr_size = size; |
| 340 | ctx->offset += size; | 342 | ctx->offset += ctx->tun.hdr_size; |
| 341 | } | 343 | } |
| 342 | 344 | ||
| 343 | return true; | 345 | return true; |
| @@ -347,29 +349,23 @@ static bool nf_flow_ip6_tunnel_proto(struct nf_flowtable_ctx *ctx, · 3 unmodified lines | |||
| 347 | struct sk_buff *skb) | 349 | struct sk_buff *skb) |
| 348 | { | 350 | { |
| 349 | #if IS_ENABLED(CONFIG_IPV6) | 351 | #if IS_ENABLED(CONFIG_IPV6) |
| 350 | struct ipv6hdr *ip6h, _ip6h; | 352 | struct ipv6hdr *ip6h; |
| 351 | __be16 frag_off; | ||
| 352 | u8 nexthdr; | ||
| 353 | int hdrlen; | ||
| 354 | 353 | ||
| 355 | ip6h = skb_header_pointer(skb, ctx->offset, sizeof(*ip6h), &_ip6h); | 354 | if (!pskb_may_pull(skb, sizeof(*ip6h) + ctx->offset)) |
| 356 | if (!ip6h) | ||
| 357 | return false; | 355 | return false; |
| 358 | 356 | ||
| 357 | ip6h = (struct ipv6hdr *)(skb_network_header(skb) + ctx->offset); | ||
| 359 | if (ip6h->hop_limit <= 1) | 358 | if (ip6h->hop_limit <= 1) |
| 360 | return false; | 359 | return false; |
| 361 | 360 | ||
| 362 | nexthdr = ip6h->nexthdr; | 361 | if (ipv6_ext_hdr(ip6h->nexthdr)) |
| 363 | hdrlen = ipv6_skip_exthdr(skb, sizeof(*ip6h) + ctx->offset, &nexthdr, | ||
| 364 | &frag_off); | ||
| 365 | if (hdrlen < 0) | ||
| 366 | return false; | 362 | return false; |
| 367 | 363 | ||
| 368 | if (nexthdr == IPPROTO_IPV6) { | 364 | if (ip6h->nexthdr == IPPROTO_IPV6) { |
| 369 | ctx->tun.hdr_size = hdrlen; | 365 | ctx->tun.proto = ip6h->nexthdr; |
| 370 | ctx->tun.proto = IPPROTO_IPV6; | 366 | ctx->tun.hdr_size = sizeof(*ip6h); |
| 367 | ctx->offset += ctx->tun.hdr_size; | ||
| 371 | } | 368 | } |
| 372 | ctx->offset += ctx->tun.hdr_size; | ||
| 373 | 369 | ||
| 374 | return true; | 370 | return true; |
| 375 | #else | 371 | #else |
| @@ -648,25 +644,19 @@ static int nf_flow_tunnel_v4_push(struct net *net, struct sk_buff *skb, · 272 unmodified lines | |||
| 648 | return 0; | 644 | return 0; |
| 649 | } | 645 | } |
| 650 | 646 | ||
| 651 | struct ipv6_tel_txoption { | ||
| 652 | struct ipv6_txoptions ops; | ||
| 653 | __u8 dst_opt[8]; | ||
| 654 | }; | ||
| 655 | |||
| 656 | static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb, | 647 | static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb, |
| 657 | struct flow_offload_tuple *tuple, | 648 | struct flow_offload_tuple *tuple, |
| 658 | struct in6_addr **ip6_daddr, | 649 | struct in6_addr **ip6_daddr) |
| 659 | int encap_limit) | ||
| 660 | { | 650 | { |
| 661 | struct ipv6hdr *ip6h = (struct ipv6hdr *)skb_network_header(skb); | 651 | struct ipv6hdr *ip6h = (struct ipv6hdr *)skb_network_header(skb); |
| 662 | u8 hop_limit = ip6h->hop_limit, proto = IPPROTO_IPV6; | ||
| 663 | struct rtable *rt = dst_rtable(tuple->dst_cache); | 652 | struct rtable *rt = dst_rtable(tuple->dst_cache); |
| 664 | __u8 dsfield = ipv6_get_dsfield(ip6h); | 653 | __u8 dsfield = ipv6_get_dsfield(ip6h); |
| 665 | struct flowi6 fl6 = { | 654 | struct flowi6 fl6 = { |
| 666 | .daddr = tuple->tun.src_v6, | 655 | .daddr = tuple->tun.src_v6, |
| 667 | .saddr = tuple->tun.dst_v6, | 656 | .saddr = tuple->tun.dst_v6, |
| 668 | .flowi6_proto = proto, | 657 | .flowi6_proto = IPPROTO_IPV6, |
| 669 | }; | 658 | }; |
| 659 | u8 hop_limit = ip6h->hop_limit; | ||
| 670 | int err, mtu; | 660 | int err, mtu; |
| 671 | u32 headroom; | 661 | u32 headroom; |
| 672 | 662 | ||
| @@ -674,41 +664,18 @@ static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb, · 1 unmodified line | |||
| 674 | if (err) | 664 | if (err) |
| 675 | return err; | 665 | return err; |
| 676 | 666 | ||
| 677 | skb_set_inner_ipproto(skb, proto); | 667 | skb_set_inner_ipproto(skb, IPPROTO_IPV6); |
| 678 | headroom = sizeof(*ip6h) + LL_RESERVED_SPACE(rt->dst.dev) + | 668 | headroom = sizeof(*ip6h) + LL_RESERVED_SPACE(rt->dst.dev) + |
| 679 | rt->dst.header_len; | 669 | rt->dst.header_len; |
| 680 | if (encap_limit) | ||
| 681 | headroom += 8; | ||
| 682 | err = skb_cow_head(skb, headroom); | 670 | err = skb_cow_head(skb, headroom); |
| 683 | if (err) | 671 | if (err) |
| 684 | return err; | 672 | return err; |
| 685 | 673 | ||
| 686 | skb_scrub_packet(skb, true); | 674 | skb_scrub_packet(skb, true); |
| 687 | mtu = dst_mtu(&rt->dst) - sizeof(*ip6h); | 675 | mtu = dst_mtu(&rt->dst) - sizeof(*ip6h); |
| 688 | if (encap_limit) | ||
| 689 | mtu -= 8; | ||
| 690 | mtu = max(mtu, IPV6_MIN_MTU); | 676 | mtu = max(mtu, IPV6_MIN_MTU); |
| 691 | skb_dst_update_pmtu_no_confirm(skb, mtu); | 677 | skb_dst_update_pmtu_no_confirm(skb, mtu); |
| 692 | 678 | ||
| 693 | if (encap_limit > 0) { | ||
| 694 | struct ipv6_tel_txoption opt = { | ||
| 695 | .dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT, | ||
| 696 | .dst_opt[3] = 1, | ||
| 697 | .dst_opt[4] = encap_limit, | ||
| 698 | .dst_opt[5] = IPV6_TLV_PADN, | ||
| 699 | .dst_opt[6] = 1, | ||
| 700 | }; | ||
| 701 | struct ipv6_opt_hdr *hopt; | ||
| 702 | |||
| 703 | opt.ops.dst1opt = (struct ipv6_opt_hdr *)opt.dst_opt; | ||
| 704 | opt.ops.opt_nflen = 8; | ||
| 705 | |||
| 706 | hopt = skb_push(skb, ipv6_optlen(opt.ops.dst1opt)); | ||
| 707 | memcpy(hopt, opt.ops.dst1opt, ipv6_optlen(opt.ops.dst1opt)); | ||
| 708 | hopt->nexthdr = IPPROTO_IPV6; | ||
| 709 | proto = NEXTHDR_DEST; | ||
| 710 | } | ||
| 711 | |||
| 712 | skb_push(skb, sizeof(*ip6h)); | 679 | skb_push(skb, sizeof(*ip6h)); |
| 713 | skb_reset_network_header(skb); | 680 | skb_reset_network_header(skb); |
| 714 | 681 | ||
| @@ -716,7 +683,7 @@ static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb, · 1 unmodified line | |||
| 716 | ip6_flow_hdr(ip6h, dsfield, | 683 | ip6_flow_hdr(ip6h, dsfield, |
| 717 | ip6_make_flowlabel(net, skb, fl6.flowlabel, true, &fl6)); | 684 | ip6_make_flowlabel(net, skb, fl6.flowlabel, true, &fl6)); |
| 718 | ip6h->hop_limit = hop_limit; | 685 | ip6h->hop_limit = hop_limit; |
| 719 | ip6h->nexthdr = proto; | 686 | ip6h->nexthdr = IPPROTO_IPV6; |
| 720 | ip6h->daddr = tuple->tun.src_v6; | 687 | ip6h->daddr = tuple->tun.src_v6; |
| 721 | ip6h->saddr = tuple->tun.dst_v6; | 688 | ip6h->saddr = tuple->tun.dst_v6; |
| 722 | ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(*ip6h)); | 689 | ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(*ip6h)); |
| @@ -729,12 +696,10 @@ static int nf_flow_tunnel_ip6ip6_push(struct net *net, struct sk_buff *skb, · 6 unmodified lines | |||
| 729 | 696 | ||
| 730 | static int nf_flow_tunnel_v6_push(struct net *net, struct sk_buff *skb, | 697 | static int nf_flow_tunnel_v6_push(struct net *net, struct sk_buff *skb, |
| 731 | struct flow_offload_tuple *tuple, | 698 | struct flow_offload_tuple *tuple, |
| 732 | struct in6_addr **ip6_daddr, | 699 | struct in6_addr **ip6_daddr) |
| 733 | int encap_limit) | ||
| 734 | { | 700 | { |
| 735 | if (tuple->tun_num) | 701 | if (tuple->tun_num) |
| 736 | return nf_flow_tunnel_ip6ip6_push(net, skb, tuple, ip6_daddr, | 702 | return nf_flow_tunnel_ip6ip6_push(net, skb, tuple, ip6_daddr); |
| 737 | encap_limit); | ||
| 738 | 703 | ||
| 739 | return 0; | 704 | return 0; |
| 740 | } | 705 | } |
| @@ -1089,7 +1054,7 @@ static int nf_flow_tuple_ipv6(struct nf_flowtable_ctx *ctx, struct sk_buff *skb, · 348 unmodified lines | |||
| 1089 | static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx, | 1054 | static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx, |
| 1090 | struct nf_flowtable *flow_table, | 1055 | struct nf_flowtable *flow_table, |
| 1091 | struct flow_offload_tuple_rhash *tuplehash, | 1056 | struct flow_offload_tuple_rhash *tuplehash, |
| 1092 | struct sk_buff *skb, int encap_limit) | 1057 | struct sk_buff *skb) |
| 1093 | { | 1058 | { |
| 1094 | enum flow_offload_tuple_dir dir; | 1059 | enum flow_offload_tuple_dir dir; |
| 1095 | struct flow_offload *flow; | 1060 | struct flow_offload *flow; |
| @@ -1100,11 +1065,8 @@ static int nf_flow_offload_ipv6_forward(struct nf_flowtable_ctx *ctx, · 4 unmodified lines | |||
| 1100 | flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); | 1065 | flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]); |
| 1101 | 1066 | ||
| 1102 | mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; | 1067 | mtu = flow->tuplehash[dir].tuple.mtu + ctx->offset; |
| 1103 | if (flow->tuplehash[!dir].tuple.tun_num) { | 1068 | if (flow->tuplehash[!dir].tuple.tun_num) |
| 1104 | mtu -= sizeof(*ip6h); | 1069 | mtu -= sizeof(*ip6h); |
| 1105 | if (encap_limit > 0) | ||
| 1106 | mtu -= 8; /* encap limit option */ | ||
| 1107 | } | ||
| 1108 | 1070 | ||
| 1109 | if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) | 1071 | if (unlikely(nf_flow_exceeds_mtu(skb, mtu))) |
| 1110 | return 0; | 1072 | return 0; |
| @@ -1158,7 +1120,6 @@ unsigned int · 47 unmodified lines | |||
| 1158 | nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, | 1120 | nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, |
| 1159 | const struct nf_hook_state *state) | 1121 | const struct nf_hook_state *state) |
| 1160 | { | 1122 | { |
| 1161 | int encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; | ||
| 1162 | struct flow_offload_tuple_rhash *tuplehash; | 1123 | struct flow_offload_tuple_rhash *tuplehash; |
| 1163 | struct nf_flowtable *flow_table = priv; | 1124 | struct nf_flowtable *flow_table = priv; |
| 1164 | struct flow_offload_tuple *other_tuple; | 1125 | struct flow_offload_tuple *other_tuple; |
| @@ -1177,8 +1138,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, · 12 unmodified lines | |||
| 1177 | if (tuplehash == NULL) | 1138 | if (tuplehash == NULL) |
| 1178 | return NF_ACCEPT; | 1139 | return NF_ACCEPT; |
| 1179 | 1140 | ||
| 1180 | ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb, | 1141 | ret = nf_flow_offload_ipv6_forward(&ctx, flow_table, tuplehash, skb); |
| 1181 | encap_limit); | ||
| 1182 | if (ret < 0) | 1142 | if (ret < 0) |
| 1183 | return NF_DROP; | 1143 | return NF_DROP; |
| 1184 | else if (ret == 0) | 1144 | else if (ret == 0) |
| @@ -1198,7 +1158,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb, · 13 unmodified lines | |||
| 1198 | ip6_daddr = &other_tuple->src_v6; | 1158 | ip6_daddr = &other_tuple->src_v6; |
| 1199 | 1159 | ||
| 1200 | if (nf_flow_tunnel_v6_push(state->net, skb, other_tuple, | 1160 | if (nf_flow_tunnel_v6_push(state->net, skb, other_tuple, |
| 1201 | &ip6_daddr, encap_limit) < 0) | 1161 | &ip6_daddr) < 0) |
| 1202 | return NF_DROP; | 1162 | return NF_DROP; |
| 1203 | 1163 | ||
| 1204 | switch (tuplehash->tuple.xmit_type) { | 1164 | switch (tuplehash->tuple.xmit_type) { |
| @@ -53,8 +53,10 @@ static int nft_dev_fill_forward_path(const struct nf_flow_route *route, · 52 unmodified lines | |||
| 53 | struct neighbour *n; | 53 | struct neighbour *n; |
| 54 | u8 nud_state; | 54 | u8 nud_state; |
| 55 | 55 | ||
| 56 | if (!nft_is_valid_ether_device(dev)) | 56 | if (!nft_is_valid_ether_device(dev)) { |
| 57 | eth_zero_addr(ha); | ||
| 57 | goto out; | 58 | goto out; |
| 59 | } | ||
| 58 | 60 | ||
| 59 | n = dst_neigh_lookup(dst_cache, daddr); | 61 | n = dst_neigh_lookup(dst_cache, daddr); |
| 60 | if (!n) | 62 | if (!n) |
| @@ -1181,6 +1181,16 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, · 1180 unmodified lines | |||
| 1181 | struct nf_hook_ops *nat_ops; | 1181 | struct nf_hook_ops *nat_ops; |
| 1182 | int i, ret; | 1182 | int i, ret; |
| 1183 | 1183 | ||
| 1184 | #ifndef MODULE | ||
| 1185 | /* If nf_nat_core is built-in and nf_nat_init() fails, dependent | ||
| 1186 | * modules like nft_chain_nat.ko may still call this function. | ||
| 1187 | * However, nat_net would be invalid, likely pointing to some other | ||
| 1188 | * per-net structure. | ||
| 1189 | */ | ||
| 1190 | if (WARN_ON_ONCE(!nf_nat_hook)) | ||
| 1191 | return -EOPNOTSUPP; | ||
| 1192 | #endif | ||
| 1193 | |||
| 1184 | if (WARN_ON_ONCE(pf >= ARRAY_SIZE(nat_net->nat_proto_net))) | 1194 | if (WARN_ON_ONCE(pf >= ARRAY_SIZE(nat_net->nat_proto_net))) |
| 1185 | return -EINVAL; | 1195 | return -EINVAL; |
| 1186 | 1196 | ||
| @@ -68,6 +68,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry) · 67 unmodified lines | |||
| 68 | nf_queue_sock_put(state->sk); | 68 | nf_queue_sock_put(state->sk); |
| 69 | 69 | ||
| 70 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 70 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
| 71 | dev_put(entry->bridge_dev); | ||
| 71 | dev_put(entry->physin); | 72 | dev_put(entry->physin); |
| 72 | dev_put(entry->physout); | 73 | dev_put(entry->physout); |
| 73 | #endif | 74 | #endif |
| @@ -84,6 +85,8 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry) · 10 unmodified lines | |||
| 84 | { | 85 | { |
| 85 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 86 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
| 86 | const struct sk_buff *skb = entry->skb; | 87 | const struct sk_buff *skb = entry->skb; |
| 88 | struct dst_entry *dst = skb_dst(skb); | ||
| 89 | struct net_device *dev = NULL; | ||
| 87 | 90 | ||
| 88 | if (nf_bridge_info_exists(skb)) { | 91 | if (nf_bridge_info_exists(skb)) { |
| 89 | entry->physin = nf_bridge_get_physindev(skb, entry->state.net); | 92 | entry->physin = nf_bridge_get_physindev(skb, entry->state.net); |
| @@ -92,6 +95,16 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry) · 2 unmodified lines | |||
| 92 | entry->physin = NULL; | 95 | entry->physin = NULL; |
| 93 | entry->physout = NULL; | 96 | entry->physout = NULL; |
| 94 | } | 97 | } |
| 98 | |||
| 99 | if (entry->state.pf == NFPROTO_BRIDGE && | ||
| 100 | dst && (dst->flags & DST_FAKE_RTABLE)) | ||
| 101 | dev = dst_dev_rcu(dst); | ||
| 102 | |||
| 103 | /* Must hold a reference on the bridge device: dst_hold() protects | ||
| 104 | * the dst itself, but the fake rtable is embedded in bridge-private | ||
| 105 | * storage that netdevice teardown can free independently. | ||
| 106 | */ | ||
| 107 | entry->bridge_dev = dev; | ||
| 95 | #endif | 108 | #endif |
| 96 | } | 109 | } |
| 97 | 110 | ||
| @@ -108,6 +121,7 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry) · 10 unmodified lines | |||
| 108 | dev_hold(state->out); | 121 | dev_hold(state->out); |
| 109 | 122 | ||
| 110 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 123 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
| 124 | dev_hold(entry->bridge_dev); | ||
| 111 | dev_hold(entry->physin); | 125 | dev_hold(entry->physin); |
| 112 | dev_hold(entry->physout); | 126 | dev_hold(entry->physout); |
| 113 | #endif | 127 | #endif |
| @@ -1262,6 +1262,9 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) · 1261 unmodified lines | |||
| 1262 | 1262 | ||
| 1263 | if (physinif == ifindex || physoutif == ifindex) | 1263 | if (physinif == ifindex || physoutif == ifindex) |
| 1264 | return 1; | 1264 | return 1; |
| 1265 | |||
| 1266 | if (entry->bridge_dev && entry->bridge_dev->ifindex == ifindex) | ||
| 1267 | return 1; | ||
| 1265 | #endif | 1268 | #endif |
| 1266 | if (entry->skb_dev && entry->skb_dev->ifindex == ifindex) | 1269 | if (entry->skb_dev && entry->skb_dev->ifindex == ifindex) |
| 1267 | return 1; | 1270 | return 1; |
| @@ -397,6 +397,22 @@ static int nft_target_validate(const struct nft_ctx *ctx, · 396 unmodified lines | |||
| 397 | return 0; | 397 | return 0; |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | static int nft_target_bridge_validate(const struct nft_ctx *ctx, | ||
| 401 | const struct nft_expr *expr) | ||
| 402 | { | ||
| 403 | struct xt_target *target = expr->ops->data; | ||
| 404 | |||
| 405 | /* Do not allow UNSPEC to stand-in for NFPROTO_BRIDGE | ||
| 406 | * targets: they are incompatible. ebtables targets return | ||
| 407 | * EBT_ACCEPT, DROP and so on which are not compatible with | ||
| 408 | * NF_ACCEPT, NF_DROP and so on. | ||
| 409 | */ | ||
| 410 | if (target->family != NFPROTO_BRIDGE) | ||
| 411 | return -ENOENT; | ||
| 412 | |||
| 413 | return nft_target_validate(ctx, expr); | ||
| 414 | } | ||
| 415 | |||
| 400 | static void __nft_match_eval(const struct nft_expr *expr, | 416 | static void __nft_match_eval(const struct nft_expr *expr, |
| 401 | struct nft_regs *regs, | 417 | struct nft_regs *regs, |
| 402 | const struct nft_pktinfo *pkt, | 418 | const struct nft_pktinfo *pkt, |
| @@ -932,13 +948,15 @@ nft_target_select_ops(const struct nft_ctx *ctx, · 529 unmodified lines | |||
| 932 | ops->init = nft_target_init; | 948 | ops->init = nft_target_init; |
| 933 | ops->destroy = nft_target_destroy; | 949 | ops->destroy = nft_target_destroy; |
| 934 | ops->dump = nft_target_dump; | 950 | ops->dump = nft_target_dump; |
| 935 | ops->validate = nft_target_validate; | ||
| 936 | ops->data = target; | 951 | ops->data = target; |
| 937 | 952 | ||
| 938 | if (family == NFPROTO_BRIDGE) | 953 | if (family == NFPROTO_BRIDGE) { |
| 939 | ops->eval = nft_target_eval_bridge; | 954 | ops->eval = nft_target_eval_bridge; |
| 940 | else | 955 | ops->validate = nft_target_bridge_validate; |
| 956 | } else { | ||
| 941 | ops->eval = nft_target_eval_xt; | 957 | ops->eval = nft_target_eval_xt; |
| 958 | ops->validate = nft_target_validate; | ||
| 959 | } | ||
| 942 | 960 | ||
| 943 | return ops; | 961 | return ops; |
| 944 | err: | 962 | err: |
| @@ -1145,7 +1145,6 @@ static void nft_ct_helper_obj_eval(struct nft_object *obj, · 1144 unmodified lines | |||
| 1145 | help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); | 1145 | help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); |
| 1146 | if (help && refcount_inc_not_zero(&to_assign->ct_refcnt)) { | 1146 | if (help && refcount_inc_not_zero(&to_assign->ct_refcnt)) { |
| 1147 | rcu_assign_pointer(help->helper, to_assign); | 1147 | rcu_assign_pointer(help->helper, to_assign); |
| 1148 | set_bit(IPS_HELPER_BIT, &ct->status); | ||
| 1149 | 1148 | ||
| 1150 | if ((ct->status & IPS_NAT_MASK) && !nfct_seqadj(ct)) | 1149 | if ((ct->status & IPS_NAT_MASK) && !nfct_seqadj(ct)) |
| 1151 | if (!nfct_seqadj_ext_add(ct)) | 1150 | if (!nfct_seqadj_ext_add(ct)) |
| @@ -1216,11 +1215,23 @@ struct nft_ct_expect_obj { · 64 unmodified lines | |||
| 1216 | u32 timeout; | 1215 | u32 timeout; |
| 1217 | }; | 1216 | }; |
| 1218 | 1217 | ||
| 1218 | static int nft_ct_expect_timeout_get(const struct nlattr *attr, u32 *val) | ||
| 1219 | { | ||
| 1220 | unsigned long jiffies_val = msecs_to_jiffies(nla_get_u32(attr)); | ||
| 1221 | |||
| 1222 | if (jiffies_val > UINT_MAX) | ||
| 1223 | return -ERANGE; | ||
| 1224 | |||
| 1225 | *val = jiffies_val; | ||
| 1226 | return 0; | ||
| 1227 | } | ||
| 1228 | |||
| 1219 | static int nft_ct_expect_obj_init(const struct nft_ctx *ctx, | 1229 | static int nft_ct_expect_obj_init(const struct nft_ctx *ctx, |
| 1220 | const struct nlattr * const tb[], | 1230 | const struct nlattr * const tb[], |
| 1221 | struct nft_object *obj) | 1231 | struct nft_object *obj) |
| 1222 | { | 1232 | { |
| 1223 | struct nft_ct_expect_obj *priv = nft_obj_data(obj); | 1233 | struct nft_ct_expect_obj *priv = nft_obj_data(obj); |
| 1234 | int err; | ||
| 1224 | 1235 | ||
| 1225 | if (!tb[NFTA_CT_EXPECT_L4PROTO] || | 1236 | if (!tb[NFTA_CT_EXPECT_L4PROTO] || |
| 1226 | !tb[NFTA_CT_EXPECT_DPORT] || | 1237 | !tb[NFTA_CT_EXPECT_DPORT] || |
| @@ -1255,8 +1266,11 @@ static int nft_ct_expect_obj_init(const struct nft_ctx *ctx, · 28 unmodified lines | |||
| 1255 | return -EOPNOTSUPP; | 1266 | return -EOPNOTSUPP; |
| 1256 | } | 1267 | } |
| 1257 | 1268 | ||
| 1269 | err = nft_ct_expect_timeout_get(tb[NFTA_CT_EXPECT_TIMEOUT], &priv->timeout); | ||
| 1270 | if (err) | ||
| 1271 | return err; | ||
| 1272 | |||
| 1258 | priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]); | 1273 | priv->dport = nla_get_be16(tb[NFTA_CT_EXPECT_DPORT]); |
| 1259 | priv->timeout = nla_get_u32(tb[NFTA_CT_EXPECT_TIMEOUT]); | ||
| 1260 | priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]); | 1274 | priv->size = nla_get_u8(tb[NFTA_CT_EXPECT_SIZE]); |
| 1261 | 1275 | ||
| 1262 | return nf_ct_netns_get(ctx->net, ctx->family); | 1276 | return nf_ct_netns_get(ctx->net, ctx->family); |
| @@ -1276,7 +1290,7 @@ static int nft_ct_expect_obj_dump(struct sk_buff *skb, · 13 unmodified lines | |||
| 1276 | if (nla_put_be16(skb, NFTA_CT_EXPECT_L3PROTO, htons(priv->l3num)) || | 1290 | if (nla_put_be16(skb, NFTA_CT_EXPECT_L3PROTO, htons(priv->l3num)) || |
| 1277 | nla_put_u8(skb, NFTA_CT_EXPECT_L4PROTO, priv->l4proto) || | 1291 | nla_put_u8(skb, NFTA_CT_EXPECT_L4PROTO, priv->l4proto) || |
| 1278 | nla_put_be16(skb, NFTA_CT_EXPECT_DPORT, priv->dport) || | 1292 | nla_put_be16(skb, NFTA_CT_EXPECT_DPORT, priv->dport) || |
| 1279 | nla_put_u32(skb, NFTA_CT_EXPECT_TIMEOUT, priv->timeout) || | 1293 | nla_put_u32(skb, NFTA_CT_EXPECT_TIMEOUT, jiffies_to_msecs(priv->timeout)) || |
| 1280 | nla_put_u8(skb, NFTA_CT_EXPECT_SIZE, priv->size)) | 1294 | nla_put_u8(skb, NFTA_CT_EXPECT_SIZE, priv->size)) |
| 1281 | return -1; | 1295 | return -1; |
| 1282 | 1296 | ||
| @@ -1326,7 +1340,7 @@ static void nft_ct_expect_obj_eval(struct nft_object *obj, · 43 unmodified lines | |||
| 1326 | &ct->tuplehash[!dir].tuple.src.u3, | 1340 | &ct->tuplehash[!dir].tuple.src.u3, |
| 1327 | &ct->tuplehash[!dir].tuple.dst.u3, | 1341 | &ct->tuplehash[!dir].tuple.dst.u3, |
| 1328 | priv->l4proto, NULL, &priv->dport); | 1342 | priv->l4proto, NULL, &priv->dport); |
| 1329 | exp->timeout.expires = jiffies + priv->timeout * HZ; | 1343 | exp->timeout += priv->timeout; |
| 1330 | 1344 | ||
| 1331 | if (nf_ct_expect_related(exp, 0) != 0) | 1345 | if (nf_ct_expect_related(exp, 0) != 0) |
| 1332 | regs->verdict.code = NF_DROP; | 1346 | regs->verdict.code = NF_DROP; |
| @@ -635,8 +635,8 @@ static int nft_meta_get_validate_xfrm(const struct nft_ctx *ctx) · 634 unmodified lines | |||
| 635 | #endif | 635 | #endif |
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | static int nft_meta_get_validate(const struct nft_ctx *ctx, | 638 | int nft_meta_get_validate(const struct nft_ctx *ctx, |
| 639 | const struct nft_expr *expr) | 639 | const struct nft_expr *expr) |
| 640 | { | 640 | { |
| 641 | const struct nft_meta *priv = nft_expr_priv(expr); | 641 | const struct nft_meta *priv = nft_expr_priv(expr); |
| 642 | 642 | ||
| @@ -652,6 +652,7 @@ static int nft_meta_get_validate(const struct nft_ctx *ctx, · 9 unmodified lines | |||
| 652 | 652 | ||
| 653 | return 0; | 653 | return 0; |
| 654 | } | 654 | } |
| 655 | EXPORT_SYMBOL_GPL(nft_meta_get_validate); | ||
| 655 | 656 | ||
| 656 | int nft_meta_set_validate(const struct nft_ctx *ctx, | 657 | int nft_meta_set_validate(const struct nft_ctx *ctx, |
| 657 | const struct nft_expr *expr) | 658 | const struct nft_expr *expr) |
| @@ -224,11 +224,17 @@ static int nft_payload_init(const struct nft_ctx *ctx, · 223 unmodified lines | |||
| 224 | const struct nlattr * const tb[]) | 224 | const struct nlattr * const tb[]) |
| 225 | { | 225 | { |
| 226 | struct nft_payload *priv = nft_expr_priv(expr); | 226 | struct nft_payload *priv = nft_expr_priv(expr); |
| 227 | u32 offset; | ||
| 228 | int err; | ||
| 227 | 229 | ||
| 228 | priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE])); | 230 | priv->base = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_BASE])); |
| 229 | priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET])); | ||
| 230 | priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); | 231 | priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); |
| 231 | 232 | ||
| 233 | err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset); | ||
| 234 | if (err < 0) | ||
| 235 | return err; | ||
| 236 | priv->offset = offset; | ||
| 237 | |||
| 232 | return nft_parse_register_store(ctx, tb[NFTA_PAYLOAD_DREG], | 238 | return nft_parse_register_store(ctx, tb[NFTA_PAYLOAD_DREG], |
| 233 | &priv->dreg, NULL, NFT_DATA_VALUE, | 239 | &priv->dreg, NULL, NFT_DATA_VALUE, |
| 234 | priv->len); | 240 | priv->len); |
| @@ -621,7 +627,8 @@ static int nft_payload_inner_init(const struct nft_ctx *ctx, · 386 unmodified lines | |||
| 621 | const struct nlattr * const tb[]) | 627 | const struct nlattr * const tb[]) |
| 622 | { | 628 | { |
| 623 | struct nft_payload *priv = nft_expr_priv(expr); | 629 | struct nft_payload *priv = nft_expr_priv(expr); |
| 624 | u32 base; | 630 | u32 base, offset; |
| 631 | int err; | ||
| 625 | 632 | ||
| 626 | if (!tb[NFTA_PAYLOAD_BASE] || !tb[NFTA_PAYLOAD_OFFSET] || | 633 | if (!tb[NFTA_PAYLOAD_BASE] || !tb[NFTA_PAYLOAD_OFFSET] || |
| 627 | !tb[NFTA_PAYLOAD_LEN] || !tb[NFTA_PAYLOAD_DREG]) | 634 | !tb[NFTA_PAYLOAD_LEN] || !tb[NFTA_PAYLOAD_DREG]) |
| @@ -639,8 +646,11 @@ static int nft_payload_inner_init(const struct nft_ctx *ctx, · 11 unmodified lines | |||
| 639 | } | 646 | } |
| 640 | 647 | ||
| 641 | priv->base = base; | 648 | priv->base = base; |
| 642 | priv->offset = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_OFFSET])); | ||
| 643 | priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); | 649 | priv->len = ntohl(nla_get_be32(tb[NFTA_PAYLOAD_LEN])); |
| 650 | err = nft_parse_u32_check(tb[NFTA_PAYLOAD_OFFSET], U16_MAX, &offset); | ||
| 651 | if (err < 0) | ||
| 652 | return err; | ||
| 653 | priv->offset = offset; | ||
| 644 | 654 | ||
| 645 | return nft_parse_register_store(ctx, tb[NFTA_PAYLOAD_DREG], | 655 | return nft_parse_register_store(ctx, tb[NFTA_PAYLOAD_DREG], |
| 646 | &priv->dreg, NULL, NFT_DATA_VALUE, | 656 | &priv->dreg, NULL, NFT_DATA_VALUE, |
| @@ -24,14 +24,13 @@ static const struct nla_policy nft_synproxy_policy[NFTA_SYNPROXY_MAX + 1] = { · 23 unmodified lines | |||
| 24 | static void nft_synproxy_tcp_options(struct synproxy_options *opts, | 24 | static void nft_synproxy_tcp_options(struct synproxy_options *opts, |
| 25 | const struct tcphdr *tcp, | 25 | const struct tcphdr *tcp, |
| 26 | struct synproxy_net *snet, | 26 | struct synproxy_net *snet, |
| 27 | struct nf_synproxy_info *info, | 27 | struct nf_synproxy_info *info) |
| 28 | const struct nft_synproxy *priv) | ||
| 29 | { | 28 | { |
| 30 | this_cpu_inc(snet->stats->syn_received); | 29 | this_cpu_inc(snet->stats->syn_received); |
| 31 | if (tcp->ece && tcp->cwr) | 30 | if (tcp->ece && tcp->cwr) |
| 32 | opts->options |= NF_SYNPROXY_OPT_ECN; | 31 | opts->options |= NF_SYNPROXY_OPT_ECN; |
| 33 | 32 | ||
| 34 | opts->options &= priv->info.options; | 33 | opts->options &= info->options; |
| 35 | opts->mss_encode = opts->mss_option; | 34 | opts->mss_encode = opts->mss_option; |
| 36 | opts->mss_option = info->mss; | 35 | opts->mss_option = info->mss; |
| 37 | if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP) | 36 | if (opts->options & NF_SYNPROXY_OPT_TIMESTAMP) |
| @@ -56,7 +55,7 @@ static void nft_synproxy_eval_v4(const struct nft_synproxy *priv, · 18 unmodified lines | |||
| 56 | 55 | ||
| 57 | if (tcp->syn) { | 56 | if (tcp->syn) { |
| 58 | /* Initial SYN from client */ | 57 | /* Initial SYN from client */ |
| 59 | nft_synproxy_tcp_options(opts, tcp, snet, &info, priv); | 58 | nft_synproxy_tcp_options(opts, tcp, snet, &info); |
| 60 | synproxy_send_client_synack(net, skb, tcp, opts); | 59 | synproxy_send_client_synack(net, skb, tcp, opts); |
| 61 | consume_skb(skb); | 60 | consume_skb(skb); |
| 62 | regs->verdict.code = NF_STOLEN; | 61 | regs->verdict.code = NF_STOLEN; |
| @@ -87,7 +86,7 @@ static void nft_synproxy_eval_v6(const struct nft_synproxy *priv, · 24 unmodified lines | |||
| 87 | 86 | ||
| 88 | if (tcp->syn) { | 87 | if (tcp->syn) { |
| 89 | /* Initial SYN from client */ | 88 | /* Initial SYN from client */ |
| 90 | nft_synproxy_tcp_options(opts, tcp, snet, &info, priv); | 89 | nft_synproxy_tcp_options(opts, tcp, snet, &info); |
| 91 | synproxy_send_client_synack_ipv6(net, skb, tcp, opts); | 90 | synproxy_send_client_synack_ipv6(net, skb, tcp, opts); |
| 92 | consume_skb(skb); | 91 | consume_skb(skb); |
| 93 | regs->verdict.code = NF_STOLEN; | 92 | regs->verdict.code = NF_STOLEN; |
| @@ -107,7 +107,7 @@ xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par) · 106 unmodified lines | |||
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | ct = nf_ct_get(skb, &ctinfo); | 109 | ct = nf_ct_get(skb, &ctinfo); |
| 110 | if (ct == NULL) | 110 | if (!ct || nf_ct_is_template(ct)) |
| 111 | return false; | 111 | return false; |
| 112 | 112 | ||
| 113 | if (ct->master) | 113 | if (ct->master) |
| @@ -883,7 +883,8 @@ static void ct_limit_set(const struct ovs_ct_limit_info *info, · 882 unmodified lines | |||
| 883 | struct hlist_head *head; | 883 | struct hlist_head *head; |
| 884 | 884 | ||
| 885 | head = ct_limit_hash_bucket(info, new_ct_limit->zone); | 885 | head = ct_limit_hash_bucket(info, new_ct_limit->zone); |
| 886 | hlist_for_each_entry_rcu(ct_limit, head, hlist_node) { | 886 | hlist_for_each_entry_rcu(ct_limit, head, hlist_node, |
| 887 | lockdep_ovsl_is_held()) { | ||
| 887 | if (ct_limit->zone == new_ct_limit->zone) { | 888 | if (ct_limit->zone == new_ct_limit->zone) { |
| 888 | hlist_replace_rcu(&ct_limit->hlist_node, | 889 | hlist_replace_rcu(&ct_limit->hlist_node, |
| 889 | &new_ct_limit->hlist_node); | 890 | &new_ct_limit->hlist_node); |
| @@ -476,15 +476,17 @@ void psample_sample_packet(struct psample_group *group, · 475 unmodified lines | |||
| 476 | goto error; | 476 | goto error; |
| 477 | 477 | ||
| 478 | if (data_len) { | 478 | if (data_len) { |
| 479 | int nla_len = nla_total_size(data_len); | 479 | int nla_len = nla_attr_size(data_len); |
| 480 | struct nlattr *nla; | 480 | struct nlattr *nla; |
| 481 | 481 | ||
| 482 | nla = skb_put(nl_skb, nla_len); | 482 | nla = skb_put(nl_skb, nla_len); |
| 483 | nla->nla_type = PSAMPLE_ATTR_DATA; | 483 | nla->nla_type = PSAMPLE_ATTR_DATA; |
| 484 | nla->nla_len = nla_attr_size(data_len); | 484 | nla->nla_len = nla_len; |
| 485 | 485 | ||
| 486 | if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) | 486 | if (skb_copy_bits(skb, 0, nla_data(nla), data_len)) |
| 487 | goto error; | 487 | goto error; |
| 488 | |||
| 489 | skb_put_zero(nl_skb, nla_padlen(data_len)); | ||
| 488 | } | 490 | } |
| 489 | 491 | ||
| 490 | #ifdef CONFIG_INET | 492 | #ifdef CONFIG_INET |
| @@ -967,6 +967,8 @@ static int rds_rm_size(struct msghdr *msg, int num_sgs, · 966 unmodified lines | |||
| 967 | 967 | ||
| 968 | switch (cmsg->cmsg_type) { | 968 | switch (cmsg->cmsg_type) { |
| 969 | case RDS_CMSG_RDMA_ARGS: | 969 | case RDS_CMSG_RDMA_ARGS: |
| 970 | if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))) | ||
| 971 | return -EINVAL; | ||
| 970 | if (vct->indx >= vct->len) { | 972 | if (vct->indx >= vct->len) { |
| 971 | vct->len += vct->incr; | 973 | vct->len += vct->incr; |
| 972 | tmp_iov = | 974 | tmp_iov = |
| @@ -669,7 +669,9 @@ enum rxrpc_call_event { · 668 unmodified lines | |||
| 669 | enum rxrpc_call_state { | 669 | enum rxrpc_call_state { |
| 670 | RXRPC_CALL_UNINITIALISED, | 670 | RXRPC_CALL_UNINITIALISED, |
| 671 | RXRPC_CALL_CLIENT_AWAIT_CONN, /* - client waiting for connection to become available */ | 671 | RXRPC_CALL_CLIENT_AWAIT_CONN, /* - client waiting for connection to become available */ |
| 672 | RXRPC_CALL_CLIENT_PRE_SEND, /* - client is connected, but hasn't sent anything yet */ | ||
| 672 | RXRPC_CALL_CLIENT_SEND_REQUEST, /* - client sending request phase */ | 673 | RXRPC_CALL_CLIENT_SEND_REQUEST, /* - client sending request phase */ |
| 674 | RXRPC_CALL_CLIENT_AWAIT_ACK, /* - client awaiting ACKs of request */ | ||
| 673 | RXRPC_CALL_CLIENT_AWAIT_REPLY, /* - client awaiting reply */ | 675 | RXRPC_CALL_CLIENT_AWAIT_REPLY, /* - client awaiting reply */ |
| 674 | RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */ | 676 | RXRPC_CALL_CLIENT_RECV_REPLY, /* - client receiving reply phase */ |
| 675 | RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */ | 677 | RXRPC_CALL_SERVER_PREALLOC, /* - service preallocation */ |
| @@ -1374,9 +1376,9 @@ static inline struct rxrpc_net *rxrpc_net(struct net *net) · 698 unmodified lines | |||
| 1374 | } | 1376 | } |
| 1375 | 1377 | ||
| 1376 | /* | 1378 | /* |
| 1377 | * out_of_band.c | 1379 | * oob.c |
| 1378 | */ | 1380 | */ |
| 1379 | void rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb); | 1381 | bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb); |
| 1380 | void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb); | 1382 | void rxrpc_add_pending_oob(struct rxrpc_sock *rx, struct sk_buff *skb); |
| 1381 | int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len); | 1383 | int rxrpc_sendmsg_oob(struct rxrpc_sock *rx, struct msghdr *msg, size_t len); |
| 1382 | 1384 | ||
| @@ -178,7 +178,7 @@ static void rxrpc_close_tx_phase(struct rxrpc_call *call) · 177 unmodified lines | |||
| 178 | 178 | ||
| 179 | switch (__rxrpc_call_state(call)) { | 179 | switch (__rxrpc_call_state(call)) { |
| 180 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | 180 | case RXRPC_CALL_CLIENT_SEND_REQUEST: |
| 181 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_REPLY); | 181 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_AWAIT_ACK); |
| 182 | break; | 182 | break; |
| 183 | case RXRPC_CALL_SERVER_SEND_REPLY: | 183 | case RXRPC_CALL_SERVER_SEND_REPLY: |
| 184 | rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK); | 184 | rxrpc_set_call_state(call, RXRPC_CALL_SERVER_AWAIT_ACK); |
| @@ -244,6 +244,8 @@ static void rxrpc_transmit_fresh_data(struct rxrpc_call *call, unsigned int limi · 59 unmodified lines | |||
| 244 | break; | 244 | break; |
| 245 | } while (req.n < limit && before(seq, send_top)); | 245 | } while (req.n < limit && before(seq, send_top)); |
| 246 | 246 | ||
| 247 | if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_PRE_SEND) | ||
| 248 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_SEND_REQUEST); | ||
| 247 | if (txb->flags & RXRPC_LAST_PACKET) { | 249 | if (txb->flags & RXRPC_LAST_PACKET) { |
| 248 | rxrpc_close_tx_phase(call); | 250 | rxrpc_close_tx_phase(call); |
| 249 | tq = NULL; | 251 | tq = NULL; |
| @@ -267,6 +269,7 @@ void rxrpc_transmit_some_data(struct rxrpc_call *call, unsigned int limit, · 17 unmodified lines | |||
| 267 | fallthrough; | 269 | fallthrough; |
| 268 | 270 | ||
| 269 | case RXRPC_CALL_SERVER_SEND_REPLY: | 271 | case RXRPC_CALL_SERVER_SEND_REPLY: |
| 272 | case RXRPC_CALL_CLIENT_PRE_SEND: | ||
| 270 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | 273 | case RXRPC_CALL_CLIENT_SEND_REQUEST: |
| 271 | if (!rxrpc_tx_window_space(call)) | 274 | if (!rxrpc_tx_window_space(call)) |
| 272 | return; | 275 | return; |
| @@ -18,7 +18,9 @@ · 17 unmodified lines | |||
| 18 | const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = { | 18 | const char *const rxrpc_call_states[NR__RXRPC_CALL_STATES] = { |
| 19 | [RXRPC_CALL_UNINITIALISED] = "Uninit ", | 19 | [RXRPC_CALL_UNINITIALISED] = "Uninit ", |
| 20 | [RXRPC_CALL_CLIENT_AWAIT_CONN] = "ClWtConn", | 20 | [RXRPC_CALL_CLIENT_AWAIT_CONN] = "ClWtConn", |
| 21 | [RXRPC_CALL_CLIENT_PRE_SEND] = "ClPreSnd", | ||
| 21 | [RXRPC_CALL_CLIENT_SEND_REQUEST] = "ClSndReq", | 22 | [RXRPC_CALL_CLIENT_SEND_REQUEST] = "ClSndReq", |
| 23 | [RXRPC_CALL_CLIENT_AWAIT_ACK] = "ClAwtAck", | ||
| 22 | [RXRPC_CALL_CLIENT_AWAIT_REPLY] = "ClAwtRpl", | 24 | [RXRPC_CALL_CLIENT_AWAIT_REPLY] = "ClAwtRpl", |
| 23 | [RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl", | 25 | [RXRPC_CALL_CLIENT_RECV_REPLY] = "ClRcvRpl", |
| 24 | [RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc", | 26 | [RXRPC_CALL_SERVER_PREALLOC] = "SvPrealc", |
| @@ -449,7 +449,7 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn, · 448 unmodified lines | |||
| 449 | trace_rxrpc_connect_call(call); | 449 | trace_rxrpc_connect_call(call); |
| 450 | call->tx_last_sent = ktime_get_real(); | 450 | call->tx_last_sent = ktime_get_real(); |
| 451 | rxrpc_start_call_timer(call); | 451 | rxrpc_start_call_timer(call); |
| 452 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_SEND_REQUEST); | 452 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_PRE_SEND); |
| 453 | wake_up(&call->waitq); | 453 | wake_up(&call->waitq); |
| 454 | } | 454 | } |
| 455 | 455 | ||
| @@ -436,7 +436,7 @@ static bool rxrpc_post_challenge(struct rxrpc_connection *conn, · 435 unmodified lines | |||
| 436 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | 436 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); |
| 437 | struct rxrpc_call *call = NULL; | 437 | struct rxrpc_call *call = NULL; |
| 438 | struct rxrpc_sock *rx; | 438 | struct rxrpc_sock *rx; |
| 439 | bool respond = false; | 439 | bool respond = false, queued = false; |
| 440 | 440 | ||
| 441 | sp->chall.conn = | 441 | sp->chall.conn = |
| 442 | rxrpc_get_connection(conn, rxrpc_conn_get_challenge_input); | 442 | rxrpc_get_connection(conn, rxrpc_conn_get_challenge_input); |
| @@ -472,8 +472,13 @@ static bool rxrpc_post_challenge(struct rxrpc_connection *conn, · 29 unmodified lines | |||
| 472 | } | 472 | } |
| 473 | 473 | ||
| 474 | if (call) | 474 | if (call) |
| 475 | rxrpc_notify_socket_oob(call, skb); | 475 | queued = rxrpc_notify_socket_oob(call, skb); |
| 476 | rcu_read_unlock(); | 476 | rcu_read_unlock(); |
| 477 | if (call && !queued) { | ||
| 478 | rxrpc_put_connection(conn, rxrpc_conn_put_challenge_input); | ||
| 479 | sp->chall.conn = NULL; | ||
| 480 | return false; | ||
| 481 | } | ||
| 477 | 482 | ||
| 478 | if (!call) | 483 | if (!call) |
| 479 | rxrpc_post_packet_to_conn(conn, skb); | 484 | rxrpc_post_packet_to_conn(conn, skb); |
| @@ -181,7 +181,8 @@ void rxrpc_congestion_degrade(struct rxrpc_call *call) · 180 unmodified lines | |||
| 181 | if (call->cong_ca_state != RXRPC_CA_SLOW_START && | 181 | if (call->cong_ca_state != RXRPC_CA_SLOW_START && |
| 182 | call->cong_ca_state != RXRPC_CA_CONGEST_AVOIDANCE) | 182 | call->cong_ca_state != RXRPC_CA_CONGEST_AVOIDANCE) |
| 183 | return; | 183 | return; |
| 184 | if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY) | 184 | if (__rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_ACK || |
| 185 | __rxrpc_call_state(call) == RXRPC_CALL_CLIENT_AWAIT_REPLY) | ||
| 185 | return; | 186 | return; |
| 186 | 187 | ||
| 187 | rtt = ns_to_ktime(call->srtt_us * (NSEC_PER_USEC / 8)); | 188 | rtt = ns_to_ktime(call->srtt_us * (NSEC_PER_USEC / 8)); |
| @@ -236,6 +237,9 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, · 48 unmodified lines | |||
| 236 | call->acks_lowest_nak = to; | 237 | call->acks_lowest_nak = to; |
| 237 | } | 238 | } |
| 238 | 239 | ||
| 240 | if (after(seq, to)) | ||
| 241 | return false; | ||
| 242 | |||
| 239 | /* We may have a left over fully-consumed buffer at the front that we | 243 | /* We may have a left over fully-consumed buffer at the front that we |
| 240 | * couldn't drop before (rotate_and_keep below). | 244 | * couldn't drop before (rotate_and_keep below). |
| 241 | */ | 245 | */ |
| @@ -247,7 +251,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, · 5 unmodified lines | |||
| 247 | tq = call->tx_queue; | 251 | tq = call->tx_queue; |
| 248 | } | 252 | } |
| 249 | 253 | ||
| 250 | do { | 254 | while (before_eq(seq, to)) { |
| 251 | unsigned int ix = seq - call->tx_qbase; | 255 | unsigned int ix = seq - call->tx_qbase; |
| 252 | 256 | ||
| 253 | _debug("tq=%x seq=%x i=%d f=%x", tq->qbase, seq, ix, tq->bufs[ix]->flags); | 257 | _debug("tq=%x seq=%x i=%d f=%x", tq->qbase, seq, ix, tq->bufs[ix]->flags); |
| @@ -317,8 +321,7 @@ static bool rxrpc_rotate_tx_window(struct rxrpc_call *call, rxrpc_seq_t to, · 63 unmodified lines | |||
| 317 | break; | 321 | break; |
| 318 | } | 322 | } |
| 319 | } | 323 | } |
| 320 | 324 | } | |
| 321 | } while (before_eq(seq, to)); | ||
| 322 | 325 | ||
| 323 | if (trace) | 326 | if (trace) |
| 324 | trace_rxrpc_rack_update(call, summary); | 327 | trace_rxrpc_rack_update(call, summary); |
| @@ -356,6 +359,7 @@ static void rxrpc_end_tx_phase(struct rxrpc_call *call, bool reply_begun, · 31 unmodified lines | |||
| 356 | 359 | ||
| 357 | switch (__rxrpc_call_state(call)) { | 360 | switch (__rxrpc_call_state(call)) { |
| 358 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | 361 | case RXRPC_CALL_CLIENT_SEND_REQUEST: |
| 362 | case RXRPC_CALL_CLIENT_AWAIT_ACK: | ||
| 359 | case RXRPC_CALL_CLIENT_AWAIT_REPLY: | 363 | case RXRPC_CALL_CLIENT_AWAIT_REPLY: |
| 360 | if (reply_begun) { | 364 | if (reply_begun) { |
| 361 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_RECV_REPLY); | 365 | rxrpc_set_call_state(call, RXRPC_CALL_CLIENT_RECV_REPLY); |
| @@ -392,6 +396,14 @@ static bool rxrpc_receiving_reply(struct rxrpc_call *call) · 30 unmodified lines | |||
| 392 | trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack); | 396 | trace_rxrpc_timer_can(call, rxrpc_timer_trace_delayed_ack); |
| 393 | } | 397 | } |
| 394 | 398 | ||
| 399 | /* Deal with an apparent reply coming in before we've got the request | ||
| 400 | * queued or transmitted. | ||
| 401 | */ | ||
| 402 | if (!test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { | ||
| 403 | rxrpc_proto_abort(call, top, rxrpc_eproto_early_reply); | ||
| 404 | return false; | ||
| 405 | } | ||
| 406 | |||
| 395 | if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { | 407 | if (!test_bit(RXRPC_CALL_TX_LAST, &call->flags)) { |
| 396 | if (!rxrpc_rotate_tx_window(call, top, &summary)) { | 408 | if (!rxrpc_rotate_tx_window(call, top, &summary)) { |
| 397 | rxrpc_proto_abort(call, top, rxrpc_eproto_early_reply); | 409 | rxrpc_proto_abort(call, top, rxrpc_eproto_early_reply); |
| @@ -694,6 +706,7 @@ static void rxrpc_input_data(struct rxrpc_call *call, struct sk_buff *skb) · 296 unmodified lines | |||
| 694 | 706 | ||
| 695 | switch (__rxrpc_call_state(call)) { | 707 | switch (__rxrpc_call_state(call)) { |
| 696 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | 708 | case RXRPC_CALL_CLIENT_SEND_REQUEST: |
| 709 | case RXRPC_CALL_CLIENT_AWAIT_ACK: | ||
| 697 | case RXRPC_CALL_CLIENT_AWAIT_REPLY: | 710 | case RXRPC_CALL_CLIENT_AWAIT_REPLY: |
| 698 | /* Received data implicitly ACKs all of the request | 711 | /* Received data implicitly ACKs all of the request |
| 699 | * packets we sent when we're acting as a client. | 712 | * packets we sent when we're acting as a client. |
| @@ -1154,10 +1167,12 @@ static void rxrpc_input_ack(struct rxrpc_call *call, struct sk_buff *skb) · 454 unmodified lines | |||
| 1154 | if (hard_ack + 1 == 0) | 1167 | if (hard_ack + 1 == 0) |
| 1155 | return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero); | 1168 | return rxrpc_proto_abort(call, 0, rxrpc_eproto_ackr_zero); |
| 1156 | 1169 | ||
| 1157 | /* Ignore ACKs unless we are or have just been transmitting. */ | 1170 | /* Ignore ACKs unless we are transmitting or are waiting for |
| 1171 | * acknowledgement of the packets we've just been transmitting. | ||
| 1172 | */ | ||
| 1158 | switch (__rxrpc_call_state(call)) { | 1173 | switch (__rxrpc_call_state(call)) { |
| 1159 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | 1174 | case RXRPC_CALL_CLIENT_SEND_REQUEST: |
| 1160 | case RXRPC_CALL_CLIENT_AWAIT_REPLY: | 1175 | case RXRPC_CALL_CLIENT_AWAIT_ACK: |
| 1161 | case RXRPC_CALL_SERVER_SEND_REPLY: | 1176 | case RXRPC_CALL_SERVER_SEND_REPLY: |
| 1162 | case RXRPC_CALL_SERVER_AWAIT_ACK: | 1177 | case RXRPC_CALL_SERVER_AWAIT_ACK: |
| 1163 | break; | 1178 | break; |
| @@ -1215,7 +1230,17 @@ static void rxrpc_input_ackall(struct rxrpc_call *call, struct sk_buff *skb) · 51 unmodified lines | |||
| 1215 | { | 1230 | { |
| 1216 | struct rxrpc_ack_summary summary = { 0 }; | 1231 | struct rxrpc_ack_summary summary = { 0 }; |
| 1217 | 1232 | ||
| 1218 | if (rxrpc_rotate_tx_window(call, call->tx_top, &summary)) | 1233 | switch (__rxrpc_call_state(call)) { |
| 1234 | case RXRPC_CALL_CLIENT_SEND_REQUEST: | ||
| 1235 | case RXRPC_CALL_CLIENT_AWAIT_ACK: | ||
| 1236 | case RXRPC_CALL_SERVER_SEND_REPLY: | ||
| 1237 | case RXRPC_CALL_SERVER_AWAIT_ACK: | ||
| 1238 | break; | ||
| 1239 | default: | ||
| 1240 | return; | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | if (rxrpc_rotate_tx_window(call, call->tx_transmitted, &summary)) | ||
| 1219 | rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ackall); | 1244 | rxrpc_end_tx_phase(call, false, rxrpc_eproto_unexpected_ackall); |
| 1220 | } | 1245 | } |
| 1221 | 1246 | ||
| @@ -32,11 +32,12 @@ struct rxrpc_oob_params { · 31 unmodified lines | |||
| 32 | * Post an out-of-band message for attention by the socket or kernel service | 32 | * Post an out-of-band message for attention by the socket or kernel service |
| 33 | * associated with a reference call. | 33 | * associated with a reference call. |
| 34 | */ | 34 | */ |
| 35 | void rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb) | 35 | bool rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb) |
| 36 | { | 36 | { |
| 37 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); | 37 | struct rxrpc_skb_priv *sp = rxrpc_skb(skb); |
| 38 | struct rxrpc_sock *rx; | 38 | struct rxrpc_sock *rx; |
| 39 | struct sock *sk; | 39 | struct sock *sk; |
| 40 | bool queued = false; | ||
| 40 | 41 | ||
| 41 | rcu_read_lock(); | 42 | rcu_read_lock(); |
| 42 | 43 | ||
| @@ -49,6 +50,7 @@ void rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb) · 6 unmodified lines | |||
| 49 | skb->skb_mstamp_ns = rx->oob_id_counter++; | 50 | skb->skb_mstamp_ns = rx->oob_id_counter++; |
| 50 | rxrpc_get_skb(skb, rxrpc_skb_get_post_oob); | 51 | rxrpc_get_skb(skb, rxrpc_skb_get_post_oob); |
| 51 | skb_queue_tail(&rx->recvmsg_oobq, skb); | 52 | skb_queue_tail(&rx->recvmsg_oobq, skb); |
| 53 | queued = true; | ||
| 52 | 54 | ||
| 53 | trace_rxrpc_notify_socket(call->debug_id, sp->hdr.serial); | 55 | trace_rxrpc_notify_socket(call->debug_id, sp->hdr.serial); |
| 54 | if (rx->app_ops) | 56 | if (rx->app_ops) |
| @@ -56,11 +58,12 @@ void rxrpc_notify_socket_oob(struct rxrpc_call *call, struct sk_buff *skb) · 1 unmodified line | |||
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | spin_unlock_irq(&rx->recvmsg_lock); | 60 | spin_unlock_irq(&rx->recvmsg_lock); |
| 59 | if (!rx->app_ops && !sock_flag(sk, SOCK_DEAD)) | 61 | if (queued && !rx->app_ops && !sock_flag(sk, SOCK_DEAD)) |
| 60 | sk->sk_data_ready(sk); | 62 | sk->sk_data_ready(sk); |
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | rcu_read_unlock(); | 65 | rcu_read_unlock(); |
| 66 | return queued; | ||
| 64 | } | 67 | } |
| 65 | 68 | ||
| 66 | /* | 69 | /* |
| @@ -210,6 +213,11 @@ static int rxrpc_respond_to_oob(struct rxrpc_sock *rx, · 143 unmodified lines | |||
| 210 | break; | 213 | break; |
| 211 | } | 214 | } |
| 212 | 215 | ||
| 216 | switch (skb->mark) { | ||
| 217 | case RXRPC_OOB_CHALLENGE: | ||
| 218 | rxrpc_put_connection(sp->chall.conn, rxrpc_conn_put_oob); | ||
| 219 | break; | ||
| 220 | } | ||
| 213 | rxrpc_free_skb(skb, rxrpc_skb_put_oob); | 221 | rxrpc_free_skb(skb, rxrpc_skb_put_oob); |
| 214 | return ret; | 222 | return ret; |
| 215 | } | 223 | } |
| @@ -27,8 +27,6 @@ void rxrpc_notify_socket(struct rxrpc_call *call) · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | _enter("%d", call->debug_id); | 28 | _enter("%d", call->debug_id); |
| 29 | 29 | ||
| 30 | if (!list_empty(&call->recvmsg_link)) | ||
| 31 | return; | ||
| 32 | if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) { | 30 | if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) { |
| 33 | rxrpc_see_call(call, rxrpc_call_see_notify_released); | 31 | rxrpc_see_call(call, rxrpc_call_see_notify_released); |
| 34 | return; | 32 | return; |
| @@ -438,7 +436,8 @@ try_again: · 403 unmodified lines | |||
| 438 | return -EAGAIN; | 436 | return -EAGAIN; |
| 439 | } | 437 | } |
| 440 | 438 | ||
| 441 | if (list_empty(&rx->recvmsg_q)) { | 439 | if (list_empty(&rx->recvmsg_q) && |
| 440 | skb_queue_empty_lockless(&rx->recvmsg_oobq)) { | ||
| 442 | ret = -EWOULDBLOCK; | 441 | ret = -EWOULDBLOCK; |
| 443 | if (timeo == 0) { | 442 | if (timeo == 0) { |
| 444 | call = NULL; | 443 | call = NULL; |
| @@ -471,7 +470,7 @@ try_again: · 26 unmodified lines | |||
| 471 | release_sock(&rx->sk); | 470 | release_sock(&rx->sk); |
| 472 | if (ret == -EAGAIN) | 471 | if (ret == -EAGAIN) |
| 473 | goto try_again; | 472 | goto try_again; |
| 474 | goto error_no_call; | 473 | goto error_trace; |
| 475 | } | 474 | } |
| 476 | 475 | ||
| 477 | /* Find the next call and dequeue it if we're not just peeking. If we | 476 | /* Find the next call and dequeue it if we're not just peeking. If we |
| @@ -530,8 +529,7 @@ try_again: · 52 unmodified lines | |||
| 530 | if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) { | 529 | if (test_bit(RXRPC_CALL_RELEASED, &call->flags)) { |
| 531 | rxrpc_see_call(call, rxrpc_call_see_already_released); | 530 | rxrpc_see_call(call, rxrpc_call_see_already_released); |
| 532 | mutex_unlock(&call->user_mutex); | 531 | mutex_unlock(&call->user_mutex); |
| 533 | if (!(flags & MSG_PEEK)) | 532 | rxrpc_put_call(call, rxrpc_call_put_recvmsg); |
| 534 | rxrpc_put_call(call, rxrpc_call_put_recvmsg); | ||
| 535 | goto try_again; | 533 | goto try_again; |
| 536 | } | 534 | } |
| 537 | 535 | ||
| @@ -366,7 +366,8 @@ reload: · 365 unmodified lines | |||
| 366 | if (state >= RXRPC_CALL_COMPLETE) | 366 | if (state >= RXRPC_CALL_COMPLETE) |
| 367 | goto maybe_error; | 367 | goto maybe_error; |
| 368 | ret = -EPROTO; | 368 | ret = -EPROTO; |
| 369 | if (state != RXRPC_CALL_CLIENT_SEND_REQUEST && | 369 | if (state != RXRPC_CALL_CLIENT_PRE_SEND && |
| 370 | state != RXRPC_CALL_CLIENT_SEND_REQUEST && | ||
| 370 | state != RXRPC_CALL_SERVER_ACK_REQUEST && | 371 | state != RXRPC_CALL_SERVER_ACK_REQUEST && |
| 371 | state != RXRPC_CALL_SERVER_SEND_REPLY) { | 372 | state != RXRPC_CALL_SERVER_SEND_REPLY) { |
| 372 | /* Request phase complete for this client call */ | 373 | /* Request phase complete for this client call */ |
| @@ -844,11 +844,11 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb, · 843 unmodified lines | |||
| 844 | u8 family, u16 zone, bool *defrag) | 844 | u8 family, u16 zone, bool *defrag) |
| 845 | { | 845 | { |
| 846 | enum ip_conntrack_info ctinfo; | 846 | enum ip_conntrack_info ctinfo; |
| 847 | struct tc_skb_cb cb; | ||
| 847 | struct nf_conn *ct; | 848 | struct nf_conn *ct; |
| 848 | int err = 0; | 849 | int err = 0; |
| 849 | bool frag; | 850 | bool frag; |
| 850 | u8 proto; | 851 | u8 proto; |
| 851 | u16 mru; | ||
| 852 | 852 | ||
| 853 | /* Previously seen (loopback)? Ignore. */ | 853 | /* Previously seen (loopback)? Ignore. */ |
| 854 | ct = nf_ct_get(skb, &ctinfo); | 854 | ct = nf_ct_get(skb, &ctinfo); |
| @@ -862,12 +862,13 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb, · 7 unmodified lines | |||
| 862 | if (err || !frag) | 862 | if (err || !frag) |
| 863 | return err; | 863 | return err; |
| 864 | 864 | ||
| 865 | err = nf_ct_handle_fragments(net, skb, zone, family, &proto, &mru); | 865 | cb = *tc_skb_cb(skb); |
| 866 | err = nf_ct_handle_fragments(net, skb, zone, family, &proto, &cb.mru); | ||
| 866 | if (err) | 867 | if (err) |
| 867 | return err; | 868 | return err; |
| 868 | 869 | ||
| 869 | *defrag = true; | 870 | *defrag = true; |
| 870 | tc_skb_cb(skb)->mru = mru; | 871 | *tc_skb_cb(skb) = cb; |
| 871 | 872 | ||
| 872 | return 0; | 873 | return 0; |
| 873 | } | 874 | } |
| @@ -1295,7 +1296,8 @@ static int tcf_ct_fill_params(struct net *net, · 421 unmodified lines | |||
| 1295 | if (tb[TCA_CT_ZONE]) { | 1296 | if (tb[TCA_CT_ZONE]) { |
| 1296 | if (!IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)) { | 1297 | if (!IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)) { |
| 1297 | NL_SET_ERR_MSG_MOD(extack, "Conntrack zones isn't enabled."); | 1298 | NL_SET_ERR_MSG_MOD(extack, "Conntrack zones isn't enabled."); |
| 1298 | return -EOPNOTSUPP; | 1299 | err = -EOPNOTSUPP; |
| 1300 | goto err; | ||
| 1299 | } | 1301 | } |
| 1300 | 1302 | ||
| 1301 | tcf_ct_set_key_val(tb, | 1303 | tcf_ct_set_key_val(tb, |
| @@ -1308,7 +1310,8 @@ static int tcf_ct_fill_params(struct net *net, · 6 unmodified lines | |||
| 1308 | tmpl = nf_ct_tmpl_alloc(net, &zone, GFP_KERNEL); | 1310 | tmpl = nf_ct_tmpl_alloc(net, &zone, GFP_KERNEL); |
| 1309 | if (!tmpl) { | 1311 | if (!tmpl) { |
| 1310 | NL_SET_ERR_MSG_MOD(extack, "Failed to allocate conntrack template"); | 1312 | NL_SET_ERR_MSG_MOD(extack, "Failed to allocate conntrack template"); |
| 1311 | return -ENOMEM; | 1313 | err = -ENOMEM; |
| 1314 | goto err; | ||
| 1312 | } | 1315 | } |
| 1313 | p->tmpl = tmpl; | 1316 | p->tmpl = tmpl; |
| 1314 | if (tb[TCA_CT_HELPER_NAME]) { | 1317 | if (tb[TCA_CT_HELPER_NAME]) { |
| @@ -4049,6 +4049,9 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru · 4048 unmodified lines | |||
| 4049 | skb_do_redirect(skb); | 4049 | skb_do_redirect(skb); |
| 4050 | *ret = __NET_XMIT_STOLEN; | 4050 | *ret = __NET_XMIT_STOLEN; |
| 4051 | return NULL; | 4051 | return NULL; |
| 4052 | case TC_ACT_CONSUMED: | ||
| 4053 | *ret = __NET_XMIT_STOLEN; | ||
| 4054 | return NULL; | ||
| 4052 | } | 4055 | } |
| 4053 | 4056 | ||
| 4054 | return skb; | 4057 | return skb; |
| @@ -461,7 +461,7 @@ static int dualpi2_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 460 unmodified lines | |||
| 461 | if (IS_ERR_OR_NULL(nskb)) | 461 | if (IS_ERR_OR_NULL(nskb)) |
| 462 | return qdisc_drop(skb, sch, to_free); | 462 | return qdisc_drop(skb, sch, to_free); |
| 463 | 463 | ||
| 464 | cnt = 1; | 464 | cnt = 0; |
| 465 | byte_len = 0; | 465 | byte_len = 0; |
| 466 | orig_len = qdisc_pkt_len(skb); | 466 | orig_len = qdisc_pkt_len(skb); |
| 467 | skb_list_walk_safe(nskb, nskb, next) { | 467 | skb_list_walk_safe(nskb, nskb, next) { |
| @@ -488,16 +488,15 @@ static int dualpi2_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, · 20 unmodified lines | |||
| 488 | byte_len += nskb->len; | 488 | byte_len += nskb->len; |
| 489 | } | 489 | } |
| 490 | } | 490 | } |
| 491 | if (cnt > 1) { | 491 | if (cnt > 0) { |
| 492 | /* The caller will add the original skb stats to its | 492 | /* The caller will add the original skb stats to its |
| 493 | * backlog, compensate this if any nskb is enqueued. | 493 | * backlog, compensate this if any nskb is enqueued. |
| 494 | */ | 494 | */ |
| 495 | --cnt; | 495 | qdisc_tree_reduce_backlog(sch, 1 - cnt, |
| 496 | byte_len -= orig_len; | 496 | orig_len - byte_len); |
| 497 | } | 497 | } |
| 498 | qdisc_tree_reduce_backlog(sch, -cnt, -byte_len); | ||
| 499 | consume_skb(skb); | 498 | consume_skb(skb); |
| 500 | return err; | 499 | return cnt > 0 ? NET_XMIT_SUCCESS : err; |
| 501 | } | 500 | } |
| 502 | return dualpi2_enqueue_skb(skb, sch, to_free); | 501 | return dualpi2_enqueue_skb(skb, sch, to_free); |
| 503 | } | 502 | } |
| @@ -594,9 +594,8 @@ void netdev_watchdog_up(struct net_device *dev) · 593 unmodified lines | |||
| 594 | return; | 594 | return; |
| 595 | if (dev->watchdog_timeo <= 0) | 595 | if (dev->watchdog_timeo <= 0) |
| 596 | dev->watchdog_timeo = 5*HZ; | 596 | dev->watchdog_timeo = 5*HZ; |
| 597 | spin_lock_bh(&dev->tx_global_lock); | ||
| 598 | 597 | ||
| 599 | spin_lock(&dev->watchdog_lock); | 598 | spin_lock_bh(&dev->watchdog_lock); |
| 600 | if (!mod_timer(&dev->watchdog_timer, | 599 | if (!mod_timer(&dev->watchdog_timer, |
| 601 | round_jiffies(jiffies + dev->watchdog_timeo))) { | 600 | round_jiffies(jiffies + dev->watchdog_timeo))) { |
| 602 | if (!dev->watchdog_ref_held) { | 601 | if (!dev->watchdog_ref_held) { |
| @@ -605,9 +604,7 @@ void netdev_watchdog_up(struct net_device *dev) · 2 unmodified lines | |||
| 605 | dev->watchdog_ref_held = true; | 604 | dev->watchdog_ref_held = true; |
| 606 | } | 605 | } |
| 607 | } | 606 | } |
| 608 | spin_unlock(&dev->watchdog_lock); | 607 | spin_unlock_bh(&dev->watchdog_lock); |
| 609 | |||
| 610 | spin_unlock_bh(&dev->tx_global_lock); | ||
| 611 | } | 608 | } |
| 612 | EXPORT_SYMBOL_GPL(netdev_watchdog_up); | 609 | EXPORT_SYMBOL_GPL(netdev_watchdog_up); |
| 613 | 610 | ||
| @@ -92,6 +92,7 @@ static int inet_diag_msg_sctpladdrs_fill(struct sk_buff *skb, · 91 unmodified lines | |||
| 92 | if (!--addrcnt) | 92 | if (!--addrcnt) |
| 93 | break; | 93 | break; |
| 94 | } | 94 | } |
| 95 | WARN_ON_ONCE(addrcnt); | ||
| 95 | rcu_read_unlock(); | 96 | rcu_read_unlock(); |
| 96 | 97 | ||
| 97 | return 0; | 98 | return 0; |
| @@ -373,42 +374,39 @@ static int sctp_ep_dump(struct sctp_endpoint *ep, void *p) · 275 unmodified lines | |||
| 373 | struct sk_buff *skb = commp->skb; | 374 | struct sk_buff *skb = commp->skb; |
| 374 | struct netlink_callback *cb = commp->cb; | 375 | struct netlink_callback *cb = commp->cb; |
| 375 | const struct inet_diag_req_v2 *r = commp->r; | 376 | const struct inet_diag_req_v2 *r = commp->r; |
| 376 | struct net *net = sock_net(skb->sk); | ||
| 377 | struct inet_sock *inet = inet_sk(sk); | 377 | struct inet_sock *inet = inet_sk(sk); |
| 378 | int err = 0; | 378 | int err = 0; |
| 379 | 379 | ||
| 380 | if (!net_eq(sock_net(sk), net)) | 380 | lock_sock(sk); |
| 381 | if (ep->base.dead) | ||
| 381 | goto out; | 382 | goto out; |
| 382 | 383 | ||
| 383 | if (cb->args[4] < cb->args[1]) | 384 | /* Skip eps with assocs if non-LISTEN states were requested, since |
| 384 | goto next; | 385 | * they'll be dumped by sctp_sock_dump() during assoc traversal. |
| 385 | 386 | */ | |
| 386 | if (!(r->idiag_states & TCPF_LISTEN) && !list_empty(&ep->asocs)) | 387 | if ((r->idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)) && |
| 387 | goto next; | 388 | !list_empty(&ep->asocs)) |
| 389 | goto out; | ||
| 388 | 390 | ||
| 389 | if (r->sdiag_family != AF_UNSPEC && | 391 | if (r->sdiag_family != AF_UNSPEC && |
| 390 | sk->sk_family != r->sdiag_family) | 392 | sk->sk_family != r->sdiag_family) |
| 391 | goto next; | 393 | goto out; |
| 392 | 394 | ||
| 393 | if (r->id.idiag_sport != inet->inet_sport && | 395 | if (r->id.idiag_sport != inet->inet_sport && |
| 394 | r->id.idiag_sport) | 396 | r->id.idiag_sport) |
| 395 | goto next; | 397 | goto out; |
| 396 | 398 | ||
| 397 | if (r->id.idiag_dport != inet->inet_dport && | 399 | if (r->id.idiag_dport != inet->inet_dport && |
| 398 | r->id.idiag_dport) | 400 | r->id.idiag_dport) |
| 399 | goto next; | ||
| 400 | |||
| 401 | if (inet_sctp_diag_fill(sk, NULL, skb, r, | ||
| 402 | sk_user_ns(NETLINK_CB(cb->skb).sk), | ||
| 403 | NETLINK_CB(cb->skb).portid, | ||
| 404 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
| 405 | cb->nlh, commp->net_admin) < 0) { | ||
| 406 | err = 2; | ||
| 407 | goto out; | 401 | goto out; |
| 408 | } | 402 | |
| 409 | next: | 403 | err = inet_sctp_diag_fill(sk, NULL, skb, r, |
| 410 | cb->args[4]++; | 404 | sk_user_ns(NETLINK_CB(cb->skb).sk), |
| 405 | NETLINK_CB(cb->skb).portid, | ||
| 406 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
| 407 | cb->nlh, commp->net_admin); | ||
| 411 | out: | 408 | out: |
| 409 | release_sock(sk); | ||
| 412 | return err; | 410 | return err; |
| 413 | } | 411 | } |
| 414 | 412 | ||
| @@ -479,41 +477,40 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, · 64 unmodified lines | |||
| 479 | .r = r, | 477 | .r = r, |
| 480 | .net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN), | 478 | .net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN), |
| 481 | }; | 479 | }; |
| 482 | int pos = cb->args[2]; | 480 | int pos; |
| 483 | 481 | ||
| 484 | /* eps hashtable dumps | 482 | /* eps hashtable dumps |
| 485 | * args: | 483 | * args: |
| 486 | * 0 : if it will traversal listen sock | 484 | * 0 : if it will traversal listen sock |
| 487 | * 1 : to record the sock pos of this time's traversal | 485 | * 1 : to record the sock pos of this time's traversal |
| 488 | * 4 : to work as a temporary variable to traversal list | ||
| 489 | */ | 486 | */ |
| 490 | if (cb->args[0] == 0) { | 487 | if (cb->args[0] == 0) { |
| 491 | if (!(idiag_states & TCPF_LISTEN)) | 488 | if (idiag_states & TCPF_LISTEN) { |
| 492 | goto skip; | 489 | pos = cb->args[1]; |
| 493 | if (sctp_for_each_endpoint(sctp_ep_dump, &commp)) | 490 | if (sctp_for_each_endpoint(sctp_ep_dump, net, &pos, |
| 494 | goto done; | 491 | &commp)) { |
| 495 | skip: | 492 | cb->args[1] = pos; |
| 493 | return; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | cb->args[0] = 1; | 496 | cb->args[0] = 1; |
| 497 | cb->args[1] = 0; | 497 | cb->args[1] = 0; |
| 498 | cb->args[4] = 0; | ||
| 499 | } | 498 | } |
| 500 | 499 | ||
| 500 | if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE))) | ||
| 501 | return; | ||
| 502 | |||
| 501 | /* asocs by transport hashtable dump | 503 | /* asocs by transport hashtable dump |
| 502 | * args: | 504 | * args: |
| 503 | * 1 : to record the assoc pos of this time's traversal | 505 | * 1 : to record the assoc pos of this time's traversal |
| 504 | * 2 : to record the transport pos of this time's traversal | 506 | * 2 : to record the transport pos of this time's traversal |
| 505 | * 3 : to mark if we have dumped the ep info of the current asoc | 507 | * 3 : to mark if we have dumped the ep info of the current asoc |
| 506 | * 4 : to work as a temporary variable to traversal list | 508 | * 4 : to track position within ep->asocs list in sctp_sock_dump() |
| 507 | * 5 : to save the sk we get from travelsing the tsp list. | ||
| 508 | */ | 509 | */ |
| 509 | if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE))) | 510 | pos = cb->args[2]; |
| 510 | goto done; | ||
| 511 | |||
| 512 | sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump, | 511 | sctp_transport_traverse_process(sctp_sock_filter, sctp_sock_dump, |
| 513 | net, &pos, &commp); | 512 | net, &pos, &commp); |
| 514 | cb->args[2] = pos; | 513 | cb->args[2] = pos; |
| 515 | |||
| 516 | done: | ||
| 517 | cb->args[1] = cb->args[4]; | 514 | cb->args[1] = cb->args[4]; |
| 518 | cb->args[4] = 0; | 515 | cb->args[4] = 0; |
| 519 | } | 516 | } |
| @@ -415,6 +415,8 @@ enum sctp_disposition sctp_sf_do_5_1B_init(struct net *net, · 414 unmodified lines | |||
| 415 | /* Update socket peer label if first association. */ | 415 | /* Update socket peer label if first association. */ |
| 416 | if (security_sctp_assoc_request(new_asoc, chunk->skb)) { | 416 | if (security_sctp_assoc_request(new_asoc, chunk->skb)) { |
| 417 | sctp_association_free(new_asoc); | 417 | sctp_association_free(new_asoc); |
| 418 | if (err_chunk) | ||
| 419 | sctp_chunk_free(err_chunk); | ||
| 418 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | 420 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
| 419 | } | 421 | } |
| 420 | 422 | ||
| @@ -1606,6 +1608,8 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( · 1185 unmodified lines | |||
| 1606 | /* Update socket peer label if first association. */ | 1608 | /* Update socket peer label if first association. */ |
| 1607 | if (security_sctp_assoc_request(new_asoc, chunk->skb)) { | 1609 | if (security_sctp_assoc_request(new_asoc, chunk->skb)) { |
| 1608 | sctp_association_free(new_asoc); | 1610 | sctp_association_free(new_asoc); |
| 1611 | if (err_chunk) | ||
| 1612 | sctp_chunk_free(err_chunk); | ||
| 1609 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | 1613 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
| 1610 | } | 1614 | } |
| 1611 | 1615 | ||
| @@ -1671,6 +1675,7 @@ static enum sctp_disposition sctp_sf_do_unexpected_init( · 59 unmodified lines | |||
| 1671 | * parameter type. | 1675 | * parameter type. |
| 1672 | */ | 1676 | */ |
| 1673 | sctp_addto_chunk(repl, len, unk_param); | 1677 | sctp_addto_chunk(repl, len, unk_param); |
| 1678 | sctp_chunk_free(err_chunk); | ||
| 1674 | } | 1679 | } |
| 1675 | 1680 | ||
| 1676 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); | 1681 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc)); |
| @@ -5369,24 +5369,39 @@ struct sctp_transport *sctp_transport_get_idx(struct net *net, · 5368 unmodified lines | |||
| 5369 | } | 5369 | } |
| 5370 | 5370 | ||
| 5371 | int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), | 5371 | int sctp_for_each_endpoint(int (*cb)(struct sctp_endpoint *, void *), |
| 5372 | void *p) { | 5372 | struct net *net, int *pos, void *p) { |
| 5373 | int err = 0; | 5373 | int err, hash = 0, idx = 0, start; |
| 5374 | int hash = 0; | ||
| 5375 | struct sctp_endpoint *ep; | ||
| 5376 | struct sctp_hashbucket *head; | 5374 | struct sctp_hashbucket *head; |
| 5375 | struct sctp_endpoint *ep; | ||
| 5377 | 5376 | ||
| 5378 | for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; | 5377 | for (head = sctp_ep_hashtable; hash < sctp_ep_hashsize; |
| 5379 | hash++, head++) { | 5378 | hash++, head++) { |
| 5379 | start = idx; | ||
| 5380 | again: | ||
| 5380 | read_lock_bh(&head->lock); | 5381 | read_lock_bh(&head->lock); |
| 5381 | sctp_for_each_hentry(ep, &head->chain) { | 5382 | sctp_for_each_hentry(ep, &head->chain) { |
| 5382 | err = cb(ep, p); | 5383 | if (sock_net(ep->base.sk) != net) |
| 5383 | if (err) | 5384 | continue; |
| 5385 | if (idx++ >= *pos) { | ||
| 5386 | sctp_endpoint_hold(ep); | ||
| 5384 | break; | 5387 | break; |
| 5388 | } | ||
| 5385 | } | 5389 | } |
| 5386 | read_unlock_bh(&head->lock); | 5390 | read_unlock_bh(&head->lock); |
| 5391 | |||
| 5392 | if (ep) { | ||
| 5393 | err = cb(ep, p); | ||
| 5394 | sctp_endpoint_put(ep); | ||
| 5395 | if (err) | ||
| 5396 | return err; | ||
| 5397 | (*pos)++; | ||
| 5398 | |||
| 5399 | idx = start; | ||
| 5400 | goto again; | ||
| 5401 | } | ||
| 5387 | } | 5402 | } |
| 5388 | 5403 | ||
| 5389 | return err; | 5404 | return 0; |
| 5390 | } | 5405 | } |
| 5391 | EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); | 5406 | EXPORT_SYMBOL_GPL(sctp_for_each_endpoint); |
| 5392 | 5407 | ||
| @@ -45,6 +45,7 @@ · 44 unmodified lines | |||
| 45 | #include "crypto.h" | 45 | #include "crypto.h" |
| 46 | 46 | ||
| 47 | #include <linux/module.h> | 47 | #include <linux/module.h> |
| 48 | #include <linux/wait_bit.h> | ||
| 48 | 49 | ||
| 49 | /* configurable TIPC parameters */ | 50 | /* configurable TIPC parameters */ |
| 50 | unsigned int tipc_net_id __read_mostly; | 51 | unsigned int tipc_net_id __read_mostly; |
| @@ -118,8 +119,7 @@ static void __net_exit tipc_exit_net(struct net *net) · 67 unmodified lines | |||
| 118 | #ifdef CONFIG_TIPC_CRYPTO | 119 | #ifdef CONFIG_TIPC_CRYPTO |
| 119 | tipc_crypto_stop(&tipc_net(net)->crypto_tx); | 120 | tipc_crypto_stop(&tipc_net(net)->crypto_tx); |
| 120 | #endif | 121 | #endif |
| 121 | while (atomic_read(&tn->wq_count)) | 122 | wait_var_event(&tn->wq_count, atomic_read(&tn->wq_count) == 0); |
| 122 | cond_resched(); | ||
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | static void __net_exit tipc_pernet_pre_exit(struct net *net) | 125 | static void __net_exit tipc_pernet_pre_exit(struct net *net) |
| @@ -218,6 +218,11 @@ static void __exit tipc_exit(void) · 92 unmodified lines | |||
| 218 | unregister_pernet_device(&tipc_net_ops); | 218 | unregister_pernet_device(&tipc_net_ops); |
| 219 | tipc_unregister_sysctl(); | 219 | tipc_unregister_sysctl(); |
| 220 | 220 | ||
| 221 | /* TODO: Wait for all timers that called call_rcu() to finish before | ||
| 222 | * calling rcu_barrier(). | ||
| 223 | */ | ||
| 224 | rcu_barrier(); | ||
| 225 | |||
| 221 | pr_info("Deactivated\n"); | 226 | pr_info("Deactivated\n"); |
| 222 | } | 227 | } |
| 223 | 228 | ||
| @@ -941,12 +941,20 @@ static int tipc_aead_decrypt(struct net *net, struct tipc_aead *aead, · 940 unmodified lines | |||
| 941 | goto exit; | 941 | goto exit; |
| 942 | } | 942 | } |
| 943 | 943 | ||
| 944 | /* Get net to avoid freed tipc_crypto when delete namespace */ | ||
| 945 | if (!maybe_get_net(net)) { | ||
| 946 | tipc_bearer_put(b); | ||
| 947 | rc = -ENODEV; | ||
| 948 | goto exit; | ||
| 949 | } | ||
| 950 | |||
| 944 | /* Now, do decrypt */ | 951 | /* Now, do decrypt */ |
| 945 | rc = crypto_aead_decrypt(req); | 952 | rc = crypto_aead_decrypt(req); |
| 946 | if (rc == -EINPROGRESS || rc == -EBUSY) | 953 | if (rc == -EINPROGRESS || rc == -EBUSY) |
| 947 | return rc; | 954 | return rc; |
| 948 | 955 | ||
| 949 | tipc_bearer_put(b); | 956 | tipc_bearer_put(b); |
| 957 | put_net(net); | ||
| 950 | 958 | ||
| 951 | exit: | 959 | exit: |
| 952 | kfree(ctx); | 960 | kfree(ctx); |
| @@ -984,6 +992,7 @@ static void tipc_aead_decrypt_done(void *data, int err) · 31 unmodified lines | |||
| 984 | } | 992 | } |
| 985 | 993 | ||
| 986 | tipc_bearer_put(b); | 994 | tipc_bearer_put(b); |
| 995 | put_net(net); | ||
| 987 | } | 996 | } |
| 988 | 997 | ||
| 989 | static inline int tipc_ehdr_size(struct tipc_ehdr *ehdr) | 998 | static inline int tipc_ehdr_size(struct tipc_ehdr *ehdr) |
| @@ -58,6 +58,7 @@ · 57 unmodified lines | |||
| 58 | * @skb: request message to be (repeatedly) sent | 58 | * @skb: request message to be (repeatedly) sent |
| 59 | * @timer: timer governing period between requests | 59 | * @timer: timer governing period between requests |
| 60 | * @timer_intv: current interval between requests (in ms) | 60 | * @timer_intv: current interval between requests (in ms) |
| 61 | * @rcu: RCU head for deferred freeing | ||
| 61 | */ | 62 | */ |
| 62 | struct tipc_discoverer { | 63 | struct tipc_discoverer { |
| 63 | u32 bearer_id; | 64 | u32 bearer_id; |
| @@ -69,6 +70,7 @@ struct tipc_discoverer { · 5 unmodified lines | |||
| 69 | struct sk_buff *skb; | 70 | struct sk_buff *skb; |
| 70 | struct timer_list timer; | 71 | struct timer_list timer; |
| 71 | unsigned long timer_intv; | 72 | unsigned long timer_intv; |
| 73 | struct rcu_head rcu; | ||
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| 74 | /** | 76 | /** |
| @@ -382,6 +384,15 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b, · 307 unmodified lines | |||
| 382 | return 0; | 384 | return 0; |
| 383 | } | 385 | } |
| 384 | 386 | ||
| 387 | static void tipc_disc_free_rcu(struct rcu_head *rp) | ||
| 388 | { | ||
| 389 | struct tipc_discoverer *d = container_of(rp, struct tipc_discoverer, | ||
| 390 | rcu); | ||
| 391 | |||
| 392 | kfree_skb(d->skb); | ||
| 393 | kfree(d); | ||
| 394 | } | ||
| 395 | |||
| 385 | /** | 396 | /** |
| 386 | * tipc_disc_delete - destroy object sending periodic link setup requests | 397 | * tipc_disc_delete - destroy object sending periodic link setup requests |
| 387 | * @d: ptr to link dest structure | 398 | * @d: ptr to link dest structure |
| @@ -389,8 +400,7 @@ int tipc_disc_create(struct net *net, struct tipc_bearer *b, · 1 unmodified line | |||
| 389 | void tipc_disc_delete(struct tipc_discoverer *d) | 400 | void tipc_disc_delete(struct tipc_discoverer *d) |
| 390 | { | 401 | { |
| 391 | timer_shutdown_sync(&d->timer); | 402 | timer_shutdown_sync(&d->timer); |
| 392 | kfree_skb(d->skb); | 403 | call_rcu(&d->rcu, tipc_disc_free_rcu); |
| 393 | kfree(d); | ||
| 394 | } | 404 | } |
| 395 | 405 | ||
| 396 | /** | 406 | /** |
| @@ -40,6 +40,7 @@ · 39 unmodified lines | |||
| 40 | #include <linux/igmp.h> | 40 | #include <linux/igmp.h> |
| 41 | #include <linux/kernel.h> | 41 | #include <linux/kernel.h> |
| 42 | #include <linux/workqueue.h> | 42 | #include <linux/workqueue.h> |
| 43 | #include <linux/wait_bit.h> | ||
| 43 | #include <linux/list.h> | 44 | #include <linux/list.h> |
| 44 | #include <net/sock.h> | 45 | #include <net/sock.h> |
| 45 | #include <net/ip.h> | 46 | #include <net/ip.h> |
| @@ -803,6 +804,14 @@ err: · 757 unmodified lines | |||
| 803 | return err; | 804 | return err; |
| 804 | } | 805 | } |
| 805 | 806 | ||
| 807 | static void rcast_free_rcu(struct rcu_head *rcu) | ||
| 808 | { | ||
| 809 | struct udp_replicast *rcast = container_of(rcu, struct udp_replicast, rcu); | ||
| 810 | |||
| 811 | dst_cache_destroy(&rcast->dst_cache); | ||
| 812 | kfree(rcast); | ||
| 813 | } | ||
| 814 | |||
| 806 | /* cleanup_bearer - break the socket/bearer association */ | 815 | /* cleanup_bearer - break the socket/bearer association */ |
| 807 | static void cleanup_bearer(struct work_struct *work) | 816 | static void cleanup_bearer(struct work_struct *work) |
| 808 | { | 817 | { |
| @@ -811,19 +820,19 @@ static void cleanup_bearer(struct work_struct *work) · 2 unmodified lines | |||
| 811 | struct tipc_net *tn; | 820 | struct tipc_net *tn; |
| 812 | 821 | ||
| 813 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { | 822 | list_for_each_entry_safe(rcast, tmp, &ub->rcast.list, list) { |
| 814 | dst_cache_destroy(&rcast->dst_cache); | ||
| 815 | list_del_rcu(&rcast->list); | 823 | list_del_rcu(&rcast->list); |
| 816 | kfree_rcu(rcast, rcu); | 824 | call_rcu_hurry(&rcast->rcu, rcast_free_rcu); |
| 817 | } | 825 | } |
| 818 | 826 | ||
| 819 | tn = tipc_net(sock_net(ub->sk)); | 827 | tn = tipc_net(sock_net(ub->sk)); |
| 820 | 828 | ||
| 821 | dst_cache_destroy(&ub->rcast.dst_cache); | ||
| 822 | udp_tunnel_sock_release(ub->sk); | 829 | udp_tunnel_sock_release(ub->sk); |
| 823 | 830 | ||
| 824 | /* Note: could use a call_rcu() to avoid another synchronize_net() */ | ||
| 825 | synchronize_net(); | 831 | synchronize_net(); |
| 826 | atomic_dec(&tn->wq_count); | 832 | |
| 833 | dst_cache_destroy(&ub->rcast.dst_cache); | ||
| 834 | if (atomic_dec_and_test(&tn->wq_count)) | ||
| 835 | wake_up_var(&tn->wq_count); | ||
| 827 | kfree(ub); | 836 | kfree(ub); |
| 828 | } | 837 | } |
| 829 | 838 | ||
| @@ -212,43 +212,23 @@ static int espintcp_sendskmsg_locked(struct sock *sk, · 211 unmodified lines | |||
| 212 | struct sk_msg *skmsg = &emsg->skmsg; | 212 | struct sk_msg *skmsg = &emsg->skmsg; |
| 213 | bool more = flags & MSG_MORE; | 213 | bool more = flags & MSG_MORE; |
| 214 | struct scatterlist *sg; | 214 | struct scatterlist *sg; |
| 215 | int done = 0; | ||
| 216 | int ret; | 215 | int ret; |
| 217 | 216 | ||
| 218 | sg = &skmsg->sg.data[skmsg->sg.start]; | ||
| 219 | do { | 217 | do { |
| 220 | struct bio_vec bvec; | 218 | struct bio_vec bvec; |
| 221 | size_t size = sg->length - emsg->offset; | ||
| 222 | int offset = sg->offset + emsg->offset; | ||
| 223 | struct page *p; | ||
| 224 | |||
| 225 | emsg->offset = 0; | ||
| 226 | 219 | ||
| 220 | sg = &skmsg->sg.data[skmsg->sg.start]; | ||
| 227 | if (sg_is_last(sg) && !more) | 221 | if (sg_is_last(sg) && !more) |
| 228 | msghdr.msg_flags &= ~MSG_MORE; | 222 | msghdr.msg_flags &= ~MSG_MORE; |
| 229 | 223 | ||
| 230 | p = sg_page(sg); | 224 | bvec_set_page(&bvec, sg_page(sg), sg->length, sg->offset); |
| 231 | retry: | 225 | iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, sg->length); |
| 232 | bvec_set_page(&bvec, p, size, offset); | 226 | ret = tcp_sendmsg_locked(sk, &msghdr, sg->length); |
| 233 | iov_iter_bvec(&msghdr.msg_iter, ITER_SOURCE, &bvec, 1, size); | 227 | if (ret < 0) |
| 234 | ret = tcp_sendmsg_locked(sk, &msghdr, size); | ||
| 235 | if (ret < 0) { | ||
| 236 | emsg->offset = offset - sg->offset; | ||
| 237 | skmsg->sg.start += done; | ||
| 238 | return ret; | 228 | return ret; |
| 239 | } | ||
| 240 | |||
| 241 | if (ret != size) { | ||
| 242 | offset += ret; | ||
| 243 | size -= ret; | ||
| 244 | goto retry; | ||
| 245 | } | ||
| 246 | 229 | ||
| 247 | done++; | 230 | sk_msg_free_partial(sk, skmsg, ret); |
| 248 | put_page(p); | 231 | } while (skmsg->sg.size); |
| 249 | sk_mem_uncharge(sk, sg->length); | ||
| 250 | sg = sg_next(sg); | ||
| 251 | } while (sg); | ||
| 252 | 232 | ||
| 253 | memset(emsg, 0, sizeof(*emsg)); | 233 | memset(emsg, 0, sizeof(*emsg)); |
| 254 | 234 | ||
| @@ -467,6 +467,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) · 466 unmodified lines | |||
| 467 | { | 467 | { |
| 468 | const struct xfrm_state_afinfo *afinfo; | 468 | const struct xfrm_state_afinfo *afinfo; |
| 469 | struct net *net = dev_net(skb->dev); | 469 | struct net *net = dev_net(skb->dev); |
| 470 | struct net_device *dev = skb->dev; | ||
| 470 | int err; | 471 | int err; |
| 471 | __be32 seq; | 472 | __be32 seq; |
| 472 | __be32 seq_hi; | 473 | __be32 seq_hi; |
| @@ -493,7 +494,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) · 20 unmodified lines | |||
| 493 | LINUX_MIB_XFRMINSTATEINVALID); | 494 | LINUX_MIB_XFRMINSTATEINVALID); |
| 494 | 495 | ||
| 495 | if (encap_type == -1) | 496 | if (encap_type == -1) |
| 496 | dev_put(skb->dev); | 497 | dev_put(dev); |
| 497 | goto drop; | 498 | goto drop; |
| 498 | } | 499 | } |
| 499 | 500 | ||
| @@ -655,16 +656,16 @@ process: · 155 unmodified lines | |||
| 655 | 656 | ||
| 656 | if (!crypto_done) { | 657 | if (!crypto_done) { |
| 657 | spin_unlock(&x->lock); | 658 | spin_unlock(&x->lock); |
| 658 | dev_hold(skb->dev); | 659 | dev_hold(dev); |
| 659 | 660 | ||
| 660 | nexthdr = x->type->input(x, skb); | 661 | nexthdr = x->type->input(x, skb); |
| 661 | if (nexthdr == -EINPROGRESS) { | 662 | if (nexthdr == -EINPROGRESS) { |
| 662 | if (async) | 663 | if (async) |
| 663 | dev_put(skb->dev); | 664 | dev_put(dev); |
| 664 | return 0; | 665 | return 0; |
| 665 | } | 666 | } |
| 666 | 667 | ||
| 667 | dev_put(skb->dev); | 668 | dev_put(dev); |
| 668 | spin_lock(&x->lock); | 669 | spin_lock(&x->lock); |
| 669 | } | 670 | } |
| 670 | resume: | 671 | resume: |
| @@ -699,7 +700,7 @@ resume: · 28 unmodified lines | |||
| 699 | err = xfrm_inner_mode_input(x, skb); | 700 | err = xfrm_inner_mode_input(x, skb); |
| 700 | if (err == -EINPROGRESS) { | 701 | if (err == -EINPROGRESS) { |
| 701 | if (async) | 702 | if (async) |
| 702 | dev_put(skb->dev); | 703 | dev_put(dev); |
| 703 | return 0; | 704 | return 0; |
| 704 | } else if (err) { | 705 | } else if (err) { |
| 705 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); | 706 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); |
| @@ -726,9 +727,12 @@ resume_decapped: · 20 unmodified lines | |||
| 726 | crypto_done = false; | 727 | crypto_done = false; |
| 727 | } while (!err); | 728 | } while (!err); |
| 728 | 729 | ||
| 730 | rcu_read_lock(); | ||
| 729 | err = xfrm_rcv_cb(skb, family, x->type->proto, 0); | 731 | err = xfrm_rcv_cb(skb, family, x->type->proto, 0); |
| 730 | if (err) | 732 | if (err) { |
| 733 | rcu_read_unlock(); | ||
| 731 | goto drop; | 734 | goto drop; |
| 735 | } | ||
| 732 | 736 | ||
| 733 | nf_reset_ct(skb); | 737 | nf_reset_ct(skb); |
| 734 | 738 | ||
| @@ -739,8 +743,9 @@ resume_decapped: · 4 unmodified lines | |||
| 739 | if (skb_valid_dst(skb)) | 743 | if (skb_valid_dst(skb)) |
| 740 | skb_dst_drop(skb); | 744 | skb_dst_drop(skb); |
| 741 | if (async) | 745 | if (async) |
| 742 | dev_put(skb->dev); | 746 | dev_put(dev); |
| 743 | gro_cells_receive(&gro_cells, skb); | 747 | gro_cells_receive(&gro_cells, skb); |
| 748 | rcu_read_unlock(); | ||
| 744 | return 0; | 749 | return 0; |
| 745 | } else { | 750 | } else { |
| 746 | xo = xfrm_offload(skb); | 751 | xo = xfrm_offload(skb); |
| @@ -748,23 +753,21 @@ resume_decapped: · 1 unmodified line | |||
| 748 | xfrm_gro = xo->flags & XFRM_GRO; | 753 | xfrm_gro = xo->flags & XFRM_GRO; |
| 749 | 754 | ||
| 750 | err = -EAFNOSUPPORT; | 755 | err = -EAFNOSUPPORT; |
| 751 | rcu_read_lock(); | ||
| 752 | afinfo = xfrm_state_afinfo_get_rcu(x->props.family); | 756 | afinfo = xfrm_state_afinfo_get_rcu(x->props.family); |
| 753 | if (likely(afinfo)) | 757 | if (likely(afinfo)) |
| 754 | err = afinfo->transport_finish(skb, xfrm_gro || async); | 758 | err = afinfo->transport_finish(skb, xfrm_gro || async); |
| 755 | rcu_read_unlock(); | ||
| 756 | if (xfrm_gro) { | 759 | if (xfrm_gro) { |
| 757 | sp = skb_sec_path(skb); | 760 | sp = skb_sec_path(skb); |
| 758 | if (sp) | 761 | if (sp) |
| 759 | sp->olen = 0; | 762 | sp->olen = 0; |
| 760 | if (skb_valid_dst(skb)) | 763 | if (skb_valid_dst(skb)) |
| 761 | skb_dst_drop(skb); | 764 | skb_dst_drop(skb); |
| 762 | if (async) | ||
| 763 | dev_put(skb->dev); | ||
| 764 | gro_cells_receive(&gro_cells, skb); | 765 | gro_cells_receive(&gro_cells, skb); |
| 765 | return err; | ||
| 766 | } | 766 | } |
| 767 | 767 | ||
| 768 | if (async) | ||
| 769 | dev_put(dev); | ||
| 770 | rcu_read_unlock(); | ||
| 768 | return err; | 771 | return err; |
| 769 | } | 772 | } |
| 770 | 773 | ||
| @@ -772,7 +775,7 @@ drop_unlock: · 1 unmodified line | |||
| 772 | spin_unlock(&x->lock); | 775 | spin_unlock(&x->lock); |
| 773 | drop: | 776 | drop: |
| 774 | if (async) | 777 | if (async) |
| 775 | dev_put(skb->dev); | 778 | dev_put(dev); |
| 776 | xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); | 779 | xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); |
| 777 | kfree_skb(skb); | 780 | kfree_skb(skb); |
| 778 | return 0; | 781 | return 0; |
| @@ -869,6 +869,9 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[], · 868 unmodified lines | |||
| 869 | struct net *net = xi->net; | 869 | struct net *net = xi->net; |
| 870 | struct xfrm_if_parms p = {}; | 870 | struct xfrm_if_parms p = {}; |
| 871 | 871 | ||
| 872 | if (!rtnl_dev_link_net_capable(dev, net)) | ||
| 873 | return -EPERM; | ||
| 874 | |||
| 872 | xfrmi_netlink_parms(data, &p); | 875 | xfrmi_netlink_parms(data, &p); |
| 873 | if (!p.if_id) { | 876 | if (!p.if_id) { |
| 874 | NL_SET_ERR_MSG(extack, "if_id must be non zero"); | 877 | NL_SET_ERR_MSG(extack, "if_id must be non zero"); |
| @@ -242,6 +242,9 @@ __xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl) · 241 unmodified lines | |||
| 242 | bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl, | 242 | bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl, |
| 243 | unsigned short family) | 243 | unsigned short family) |
| 244 | { | 244 | { |
| 245 | if (family != sel->family && sel->family != AF_UNSPEC) | ||
| 246 | return false; | ||
| 247 | |||
| 245 | switch (family) { | 248 | switch (family) { |
| 246 | case AF_INET: | 249 | case AF_INET: |
| 247 | return __xfrm4_selector_match(sel, fl); | 250 | return __xfrm4_selector_match(sel, fl); |
| @@ -685,7 +688,7 @@ static void xfrm_byidx_resize(struct net *net) · 437 unmodified lines | |||
| 685 | 688 | ||
| 686 | static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) | 689 | static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) |
| 687 | { | 690 | { |
| 688 | unsigned int cnt = net->xfrm.policy_count[dir]; | 691 | unsigned int cnt = READ_ONCE(net->xfrm.policy_count[dir]); |
| 689 | unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; | 692 | unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; |
| 690 | 693 | ||
| 691 | if (total) | 694 | if (total) |
| @@ -711,12 +714,12 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) · 19 unmodified lines | |||
| 711 | 714 | ||
| 712 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) | 715 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) |
| 713 | { | 716 | { |
| 714 | si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; | 717 | si->incnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_IN]); |
| 715 | si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; | 718 | si->outcnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT]); |
| 716 | si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; | 719 | si->fwdcnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_FWD]); |
| 717 | si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; | 720 | si->inscnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]); |
| 718 | si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; | 721 | si->outscnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]); |
| 719 | si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; | 722 | si->fwdscnt = READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]); |
| 720 | si->spdhcnt = net->xfrm.policy_idx_hmask; | 723 | si->spdhcnt = net->xfrm.policy_idx_hmask; |
| 721 | si->spdhmcnt = xfrm_policy_hashmax; | 724 | si->spdhmcnt = xfrm_policy_hashmax; |
| 722 | } | 725 | } |
| @@ -2318,7 +2321,7 @@ static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) · 1595 unmodified lines | |||
| 2318 | } | 2321 | } |
| 2319 | 2322 | ||
| 2320 | list_add(&pol->walk.all, &net->xfrm.policy_all); | 2323 | list_add(&pol->walk.all, &net->xfrm.policy_all); |
| 2321 | net->xfrm.policy_count[dir]++; | 2324 | WRITE_ONCE(net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] + 1); |
| 2322 | xfrm_pol_hold(pol); | 2325 | xfrm_pol_hold(pol); |
| 2323 | } | 2326 | } |
| 2324 | 2327 | ||
| @@ -2337,7 +2340,7 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, · 12 unmodified lines | |||
| 2337 | } | 2340 | } |
| 2338 | 2341 | ||
| 2339 | list_del_init(&pol->walk.all); | 2342 | list_del_init(&pol->walk.all); |
| 2340 | net->xfrm.policy_count[dir]--; | 2343 | WRITE_ONCE(net->xfrm.policy_count[dir], net->xfrm.policy_count[dir] - 1); |
| 2341 | 2344 | ||
| 2342 | return pol; | 2345 | return pol; |
| 2343 | } | 2346 | } |
| @@ -3222,7 +3225,7 @@ struct dst_entry *xfrm_lookup_with_ifid(struct net *net, · 878 unmodified lines | |||
| 3222 | 3225 | ||
| 3223 | /* To accelerate a bit... */ | 3226 | /* To accelerate a bit... */ |
| 3224 | if (!if_id && ((dst_orig->flags & DST_NOXFRM) || | 3227 | if (!if_id && ((dst_orig->flags & DST_NOXFRM) || |
| 3225 | !net->xfrm.policy_count[XFRM_POLICY_OUT])) | 3228 | !READ_ONCE(net->xfrm.policy_count[XFRM_POLICY_OUT]))) |
| 3226 | goto nopol; | 3229 | goto nopol; |
| 3227 | 3230 | ||
| 3228 | xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id); | 3231 | xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id); |
| @@ -3296,7 +3299,7 @@ ok: · 67 unmodified lines | |||
| 3296 | 3299 | ||
| 3297 | nopol: | 3300 | nopol: |
| 3298 | if ((!dst_orig->dev || !(dst_orig->dev->flags & IFF_LOOPBACK)) && | 3301 | if ((!dst_orig->dev || !(dst_orig->dev->flags & IFF_LOOPBACK)) && |
| 3299 | net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) { | 3302 | READ_ONCE(net->xfrm.policy_default[dir]) == XFRM_USERPOLICY_BLOCK) { |
| 3300 | err = -EPERM; | 3303 | err = -EPERM; |
| 3301 | goto error; | 3304 | goto error; |
| 3302 | } | 3305 | } |
| @@ -3750,7 +3753,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, · 447 unmodified lines | |||
| 3750 | const bool is_crypto_offload = sp && | 3753 | const bool is_crypto_offload = sp && |
| 3751 | (xfrm_input_state(skb)->xso.type == XFRM_DEV_OFFLOAD_CRYPTO); | 3754 | (xfrm_input_state(skb)->xso.type == XFRM_DEV_OFFLOAD_CRYPTO); |
| 3752 | 3755 | ||
| 3753 | if (net->xfrm.policy_default[dir] == XFRM_USERPOLICY_BLOCK) { | 3756 | if (READ_ONCE(net->xfrm.policy_default[dir]) == XFRM_USERPOLICY_BLOCK) { |
| 3754 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); | 3757 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); |
| 3755 | return 0; | 3758 | return 0; |
| 3756 | } | 3759 | } |
| @@ -1207,9 +1207,11 @@ struct xfrm_state *xfrm_input_state_lookup(struct net *net, u32 mark, · 1206 unmodified lines | |||
| 1207 | struct hlist_head *state_cache_input; | 1207 | struct hlist_head *state_cache_input; |
| 1208 | struct xfrm_state *x = NULL; | 1208 | struct xfrm_state *x = NULL; |
| 1209 | 1209 | ||
| 1210 | /* BH is always disabled on the input path. */ | ||
| 1211 | lockdep_assert_in_softirq(); | ||
| 1212 | |||
| 1210 | state_cache_input = raw_cpu_ptr(net->xfrm.state_cache_input); | 1213 | state_cache_input = raw_cpu_ptr(net->xfrm.state_cache_input); |
| 1211 | 1214 | ||
| 1212 | rcu_read_lock(); | ||
| 1213 | hlist_for_each_entry_rcu(x, state_cache_input, state_cache_input) { | 1215 | hlist_for_each_entry_rcu(x, state_cache_input, state_cache_input) { |
| 1214 | if (x->props.family != family || | 1216 | if (x->props.family != family || |
| 1215 | x->id.spi != spi || | 1217 | x->id.spi != spi || |
| @@ -1227,20 +1229,25 @@ struct xfrm_state *xfrm_input_state_lookup(struct net *net, u32 mark, · 11 unmodified lines | |||
| 1227 | xfrm_hash_ptrs_get(net, &state_ptrs); | 1229 | xfrm_hash_ptrs_get(net, &state_ptrs); |
| 1228 | 1230 | ||
| 1229 | x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family); | 1231 | x = __xfrm_state_lookup(&state_ptrs, mark, daddr, spi, proto, family); |
| 1230 | 1232 | if (x) { | |
| 1231 | if (x && x->km.state == XFRM_STATE_VALID) { | 1233 | spin_lock(&net->xfrm.xfrm_state_lock); |
| 1232 | spin_lock_bh(&net->xfrm.xfrm_state_lock); | 1234 | if (x->km.state != XFRM_STATE_VALID) { |
| 1233 | if (hlist_unhashed(&x->state_cache_input)) { | 1235 | /* |
| 1236 | * The state is about to be destroyed. | ||
| 1237 | * | ||
| 1238 | * Don't add it to the cache but still | ||
| 1239 | * return it to the caller. | ||
| 1240 | */ | ||
| 1241 | } else if (hlist_unhashed(&x->state_cache_input)) { | ||
| 1234 | hlist_add_head_rcu(&x->state_cache_input, state_cache_input); | 1242 | hlist_add_head_rcu(&x->state_cache_input, state_cache_input); |
| 1235 | } else { | 1243 | } else { |
| 1236 | hlist_del_rcu(&x->state_cache_input); | 1244 | hlist_del_rcu(&x->state_cache_input); |
| 1237 | hlist_add_head_rcu(&x->state_cache_input, state_cache_input); | 1245 | hlist_add_head_rcu(&x->state_cache_input, state_cache_input); |
| 1238 | } | 1246 | } |
| 1239 | spin_unlock_bh(&net->xfrm.xfrm_state_lock); | 1247 | spin_unlock(&net->xfrm.xfrm_state_lock); |
| 1240 | } | 1248 | } |
| 1241 | 1249 | ||
| 1242 | out: | 1250 | out: |
| 1243 | rcu_read_unlock(); | ||
| 1244 | return x; | 1251 | return x; |
| 1245 | } | 1252 | } |
| 1246 | EXPORT_SYMBOL(xfrm_input_state_lookup); | 1253 | EXPORT_SYMBOL(xfrm_input_state_lookup); |
| @@ -3014,7 +3021,7 @@ int xfrm_user_policy(struct sock *sk, int optname, sockptr_t optval, int optlen) · 1767 unmodified lines | |||
| 3014 | if (IS_ERR(data)) | 3021 | if (IS_ERR(data)) |
| 3015 | return PTR_ERR(data); | 3022 | return PTR_ERR(data); |
| 3016 | 3023 | ||
| 3017 | if (in_compat_syscall()) { | 3024 | if (IS_ENABLED(CONFIG_COMPAT_FOR_U64_ALIGNMENT) && in_compat_syscall()) { |
| 3018 | struct xfrm_translator *xtr = xfrm_get_translator(); | 3025 | struct xfrm_translator *xtr = xfrm_get_translator(); |
| 3019 | 3026 | ||
| 3020 | if (!xtr) { | 3027 | if (!xtr) { |
| @@ -2511,9 +2511,9 @@ static int xfrm_notify_userpolicy(struct net *net) · 2510 unmodified lines | |||
| 2511 | } | 2511 | } |
| 2512 | 2512 | ||
| 2513 | up = nlmsg_data(nlh); | 2513 | up = nlmsg_data(nlh); |
| 2514 | up->in = net->xfrm.policy_default[XFRM_POLICY_IN]; | 2514 | up->in = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_IN]); |
| 2515 | up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD]; | 2515 | up->fwd = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_FWD]); |
| 2516 | up->out = net->xfrm.policy_default[XFRM_POLICY_OUT]; | 2516 | up->out = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_OUT]); |
| 2517 | 2517 | ||
| 2518 | nlmsg_end(skb, nlh); | 2518 | nlmsg_end(skb, nlh); |
| 2519 | 2519 | ||
| @@ -2537,13 +2537,13 @@ static int xfrm_set_default(struct sk_buff *skb, struct nlmsghdr *nlh, · 17 unmodified lines | |||
| 2537 | struct xfrm_userpolicy_default *up = nlmsg_data(nlh); | 2537 | struct xfrm_userpolicy_default *up = nlmsg_data(nlh); |
| 2538 | 2538 | ||
| 2539 | if (xfrm_userpolicy_is_valid(up->in)) | 2539 | if (xfrm_userpolicy_is_valid(up->in)) |
| 2540 | net->xfrm.policy_default[XFRM_POLICY_IN] = up->in; | 2540 | WRITE_ONCE(net->xfrm.policy_default[XFRM_POLICY_IN], up->in); |
| 2541 | 2541 | ||
| 2542 | if (xfrm_userpolicy_is_valid(up->fwd)) | 2542 | if (xfrm_userpolicy_is_valid(up->fwd)) |
| 2543 | net->xfrm.policy_default[XFRM_POLICY_FWD] = up->fwd; | 2543 | WRITE_ONCE(net->xfrm.policy_default[XFRM_POLICY_FWD], up->fwd); |
| 2544 | 2544 | ||
| 2545 | if (xfrm_userpolicy_is_valid(up->out)) | 2545 | if (xfrm_userpolicy_is_valid(up->out)) |
| 2546 | net->xfrm.policy_default[XFRM_POLICY_OUT] = up->out; | 2546 | WRITE_ONCE(net->xfrm.policy_default[XFRM_POLICY_OUT], up->out); |
| 2547 | 2547 | ||
| 2548 | rt_genid_bump_all(net); | 2548 | rt_genid_bump_all(net); |
| 2549 | 2549 | ||
| @@ -2573,9 +2573,9 @@ static int xfrm_get_default(struct sk_buff *skb, struct nlmsghdr *nlh, · 23 unmodified lines | |||
| 2573 | } | 2573 | } |
| 2574 | 2574 | ||
| 2575 | r_up = nlmsg_data(r_nlh); | 2575 | r_up = nlmsg_data(r_nlh); |
| 2576 | r_up->in = net->xfrm.policy_default[XFRM_POLICY_IN]; | 2576 | r_up->in = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_IN]); |
| 2577 | r_up->fwd = net->xfrm.policy_default[XFRM_POLICY_FWD]; | 2577 | r_up->fwd = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_FWD]); |
| 2578 | r_up->out = net->xfrm.policy_default[XFRM_POLICY_OUT]; | 2578 | r_up->out = READ_ONCE(net->xfrm.policy_default[XFRM_POLICY_OUT]); |
| 2579 | nlmsg_end(r_skb, r_nlh); | 2579 | nlmsg_end(r_skb, r_nlh); |
| 2580 | 2580 | ||
| 2581 | return nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, portid); | 2581 | return nlmsg_unicast(xfrm_net_nlsk(net, skb), r_skb, portid); |
| @@ -3835,7 +3835,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, · 1253 unmodified lines | |||
| 3835 | if (!netlink_net_capable(skb, CAP_NET_ADMIN)) | 3835 | if (!netlink_net_capable(skb, CAP_NET_ADMIN)) |
| 3836 | return -EPERM; | 3836 | return -EPERM; |
| 3837 | 3837 | ||
| 3838 | if (in_compat_syscall()) { | 3838 | if (IS_ENABLED(CONFIG_COMPAT_FOR_U64_ALIGNMENT) && in_compat_syscall()) { |
| 3839 | struct xfrm_translator *xtr = xfrm_get_translator(); | 3839 | struct xfrm_translator *xtr = xfrm_get_translator(); |
| 3840 | 3840 | ||
| 3841 | if (!xtr) | 3841 | if (!xtr) |
| @@ -22,7 +22,7 @@ tests: | lib generated libynl.a · 21 unmodified lines | |||
| 22 | ynltool: | lib generated libynl.a | 22 | ynltool: | lib generated libynl.a |
| 23 | libynl.a: | lib generated | 23 | libynl.a: | lib generated |
| 24 | @echo -e "\tAR $@" | 24 | @echo -e "\tAR $@" |
| 25 | @ar rcs $@ lib/ynl.o generated/*-user.o | 25 | @$(AR) rcs $@ lib/ynl.o generated/*-user.o |
| 26 | 26 | ||
| 27 | $(SUBDIRS): | 27 | $(SUBDIRS): |
| 28 | @if [ -f "$@/Makefile" ] ; then \ | 28 | @if [ -f "$@/Makefile" ] ; then \ |
| @@ -14,10 +14,12 @@ UAPI_PATH:=../../../../include/uapi/ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) | 15 | get_hdr_inc=-D$(1) -include $(UAPI_PATH)/linux/$(2) |
| 16 | get_hdr_inc2=-D$(1) -D$(2) -include $(UAPI_PATH)/linux/$(3) | 16 | get_hdr_inc2=-D$(1) -D$(2) -include $(UAPI_PATH)/linux/$(3) |
| 17 | get_hdr_inc_drm=-D$(1) -include $(UAPI_PATH)/drm/$(2) | ||
| 17 | 18 | ||
| 18 | CFLAGS_dev-energymodel:=$(call get_hdr_inc,_LINUX_DEV_ENERGYMODEL_H,dev_energymodel.h) | 19 | CFLAGS_dev-energymodel:=$(call get_hdr_inc,_LINUX_DEV_ENERGYMODEL_H,dev_energymodel.h) |
| 19 | CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) | 20 | CFLAGS_devlink:=$(call get_hdr_inc,_LINUX_DEVLINK_H_,devlink.h) |
| 20 | CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h) | 21 | CFLAGS_dpll:=$(call get_hdr_inc,_LINUX_DPLL_H,dpll.h) |
| 22 | CFLAGS_drm_ras:=$(call get_hdr_inc_drm,_LINUX_DRM_RAS_H,drm_ras.h) | ||
| 21 | CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_TYPELIMITS_H,typelimits.h) \ | 23 | CFLAGS_ethtool:=$(call get_hdr_inc,_LINUX_TYPELIMITS_H,typelimits.h) \ |
| 22 | $(call get_hdr_inc,_LINUX_ETHTOOL_H,ethtool.h) \ | 24 | $(call get_hdr_inc,_LINUX_ETHTOOL_H,ethtool.h) \ |
| 23 | $(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) \ | 25 | $(call get_hdr_inc,_LINUX_ETHTOOL_NETLINK_H_,ethtool_netlink.h) \ |
| @@ -37,7 +37,7 @@ all: protos.a $(HDRS) $(SRCS) $(KHDRS) $(KSRCS) $(UAPI) $(RSTS) · 36 unmodified lines | |||
| 37 | 37 | ||
| 38 | protos.a: $(OBJS) | 38 | protos.a: $(OBJS) |
| 39 | @echo -e "\tAR $@" | 39 | @echo -e "\tAR $@" |
| 40 | @ar rcs $@ $(OBJS) | 40 | @$(AR) rcs $@ $(OBJS) |
| 41 | 41 | ||
| 42 | %-user.h: $(SPECS_DIR)/%.yaml $(TOOL) | 42 | %-user.h: $(SPECS_DIR)/%.yaml $(TOOL) |
| 43 | @echo -e "\tGEN $@" | 43 | @echo -e "\tGEN $@" |
| @@ -15,7 +15,7 @@ all: ynl.a · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | ynl.a: $(OBJS) | 16 | ynl.a: $(OBJS) |
| 17 | @echo -e "\tAR $@" | 17 | @echo -e "\tAR $@" |
| 18 | @ar rcs $@ $(OBJS) | 18 | @$(AR) rcs $@ $(OBJS) |
| 19 | 19 | ||
| 20 | clean: | 20 | clean: |
| 21 | rm -f *.o *.d *~ | 21 | rm -f *.o *.d *~ |
| @@ -45,13 +45,16 @@ CONFIG_IPV6=y · 44 unmodified lines | |||
| 45 | CONFIG_IPV6_FOU=y | 45 | CONFIG_IPV6_FOU=y |
| 46 | CONFIG_IPV6_FOU_TUNNEL=y | 46 | CONFIG_IPV6_FOU_TUNNEL=y |
| 47 | CONFIG_IPV6_GRE=y | 47 | CONFIG_IPV6_GRE=y |
| 48 | CONFIG_IPV6_IOAM6_LWTUNNEL=y | ||
| 48 | CONFIG_IPV6_SEG6_BPF=y | 49 | CONFIG_IPV6_SEG6_BPF=y |
| 50 | CONFIG_IPV6_SEG6_LWTUNNEL=y | ||
| 49 | CONFIG_IPV6_SIT=y | 51 | CONFIG_IPV6_SIT=y |
| 50 | CONFIG_IPV6_TUNNEL=y | 52 | CONFIG_IPV6_TUNNEL=y |
| 51 | CONFIG_KEYS=y | 53 | CONFIG_KEYS=y |
| 52 | CONFIG_LIRC=y | 54 | CONFIG_LIRC=y |
| 53 | CONFIG_LIVEPATCH=y | 55 | CONFIG_LIVEPATCH=y |
| 54 | CONFIG_LWTUNNEL=y | 56 | CONFIG_LWTUNNEL=y |
| 57 | CONFIG_LWTUNNEL_BPF=y | ||
| 55 | CONFIG_MODULE_SIG=y | 58 | CONFIG_MODULE_SIG=y |
| 56 | CONFIG_MODULE_SRCVERSION_ALL=y | 59 | CONFIG_MODULE_SRCVERSION_ALL=y |
| 57 | CONFIG_MODULE_UNLOAD=y | 60 | CONFIG_MODULE_UNLOAD=y |
| @@ -7,7 +7,6 @@ · 6 unmodified lines | |||
| 7 | #include <linux/netdev.h> | 7 | #include <linux/netdev.h> |
| 8 | #include <poll.h> | 8 | #include <poll.h> |
| 9 | #include <pthread.h> | 9 | #include <pthread.h> |
| 10 | #include <signal.h> | ||
| 11 | #include <string.h> | 10 | #include <string.h> |
| 12 | #include <sys/mman.h> | 11 | #include <sys/mman.h> |
| 13 | #include <sys/socket.h> | 12 | #include <sys/socket.h> |
| @@ -65,11 +64,6 @@ static void gen_eth_hdr(struct xsk_socket_info *xsk, struct ethhdr *eth_hdr) · 51 unmodified lines | |||
| 65 | eth_hdr->h_proto = htons(ETH_P_LOOPBACK); | 64 | eth_hdr->h_proto = htons(ETH_P_LOOPBACK); |
| 66 | } | 65 | } |
| 67 | 66 | ||
| 68 | static bool is_umem_valid(struct xsk_socket_info *xsk) | ||
| 69 | { | ||
| 70 | return !!xsk->umem->umem; | ||
| 71 | } | ||
| 72 | |||
| 73 | static u32 mode_to_xdp_flags(enum test_mode mode) | 67 | static u32 mode_to_xdp_flags(enum test_mode mode) |
| 74 | { | 68 | { |
| 75 | return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; | 69 | return (mode == TEST_MODE_SKB) ? XDP_FLAGS_SKB_MODE : XDP_FLAGS_DRV_MODE; |
| @@ -1010,7 +1004,7 @@ static int __receive_pkts(struct test_spec *test, struct xsk_socket_info *xsk) · 934 unmodified lines | |||
| 1010 | return TEST_FAILURE; | 1004 | return TEST_FAILURE; |
| 1011 | 1005 | ||
| 1012 | if (!ret) { | 1006 | if (!ret) { |
| 1013 | if (!is_umem_valid(test->ifobj_tx->xsk)) | 1007 | if (test->poll_tmout) |
| 1014 | return TEST_PASS; | 1008 | return TEST_PASS; |
| 1015 | 1009 | ||
| 1016 | ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__); | 1010 | ksft_print_msg("ERROR: [%s] Poll timed out\n", __func__); |
| @@ -1149,7 +1143,7 @@ static int receive_pkts(struct test_spec *test) · 132 unmodified lines | |||
| 1149 | break; | 1143 | break; |
| 1150 | 1144 | ||
| 1151 | res = __receive_pkts(test, xsk); | 1145 | res = __receive_pkts(test, xsk); |
| 1152 | if (!(res == TEST_PASS || res == TEST_CONTINUE)) | 1146 | if (res != TEST_CONTINUE) |
| 1153 | return res; | 1147 | return res; |
| 1154 | 1148 | ||
| 1155 | ret = gettimeofday(&tv_now, NULL); | 1149 | ret = gettimeofday(&tv_now, NULL); |
| @@ -1166,7 +1160,8 @@ static int receive_pkts(struct test_spec *test) · 10 unmodified lines | |||
| 1166 | return TEST_PASS; | 1160 | return TEST_PASS; |
| 1167 | } | 1161 | } |
| 1168 | 1162 | ||
| 1169 | static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, bool timeout) | 1163 | static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, |
| 1164 | bool test_timeout) | ||
| 1170 | { | 1165 | { |
| 1171 | u32 i, idx = 0, valid_pkts = 0, valid_frags = 0, buffer_len; | 1166 | u32 i, idx = 0, valid_pkts = 0, valid_frags = 0, buffer_len; |
| 1172 | struct pkt_stream *pkt_stream = xsk->pkt_stream; | 1167 | struct pkt_stream *pkt_stream = xsk->pkt_stream; |
| @@ -1178,7 +1173,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b · 5 unmodified lines | |||
| 1178 | buffer_len = pkt_get_buffer_len(umem, pkt_stream->max_pkt_len); | 1173 | buffer_len = pkt_get_buffer_len(umem, pkt_stream->max_pkt_len); |
| 1179 | /* pkts_in_flight might be negative if many invalid packets are sent */ | 1174 | /* pkts_in_flight might be negative if many invalid packets are sent */ |
| 1180 | if (pkts_in_flight >= (int)((umem_size(umem) - xsk->batch_size * buffer_len) / | 1175 | if (pkts_in_flight >= (int)((umem_size(umem) - xsk->batch_size * buffer_len) / |
| 1181 | buffer_len)) { | 1176 | buffer_len) && !test_timeout) { |
| 1182 | ret = kick_tx(xsk); | 1177 | ret = kick_tx(xsk); |
| 1183 | if (ret) | 1178 | if (ret) |
| 1184 | return TEST_FAILURE; | 1179 | return TEST_FAILURE; |
| @@ -1191,7 +1186,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b · 6 unmodified lines | |||
| 1191 | while (xsk_ring_prod__reserve(&xsk->tx, xsk->batch_size, &idx) < xsk->batch_size) { | 1186 | while (xsk_ring_prod__reserve(&xsk->tx, xsk->batch_size, &idx) < xsk->batch_size) { |
| 1192 | if (use_poll) { | 1187 | if (use_poll) { |
| 1193 | ret = poll(&fds, 1, POLL_TMOUT); | 1188 | ret = poll(&fds, 1, POLL_TMOUT); |
| 1194 | if (timeout) { | 1189 | if (test_timeout) { |
| 1195 | if (ret < 0) { | 1190 | if (ret < 0) { |
| 1196 | ksft_print_msg("ERROR: [%s] Poll error %d\n", | 1191 | ksft_print_msg("ERROR: [%s] Poll error %d\n", |
| 1197 | __func__, errno); | 1192 | __func__, errno); |
| @@ -1271,7 +1266,7 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b · 73 unmodified lines | |||
| 1271 | if (use_poll) { | 1266 | if (use_poll) { |
| 1272 | ret = poll(&fds, 1, POLL_TMOUT); | 1267 | ret = poll(&fds, 1, POLL_TMOUT); |
| 1273 | if (ret <= 0) { | 1268 | if (ret <= 0) { |
| 1274 | if (ret == 0 && timeout) | 1269 | if (ret == 0 && test_timeout) |
| 1275 | return TEST_PASS; | 1270 | return TEST_PASS; |
| 1276 | 1271 | ||
| 1277 | ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret); | 1272 | ksft_print_msg("ERROR: [%s] Poll error %d\n", __func__, ret); |
| @@ -1279,14 +1274,14 @@ static int __send_pkts(struct ifobject *ifobject, struct xsk_socket_info *xsk, b · 1 unmodified line | |||
| 1279 | } | 1274 | } |
| 1280 | } | 1275 | } |
| 1281 | 1276 | ||
| 1282 | if (!timeout) { | 1277 | if (!test_timeout) { |
| 1283 | if (complete_pkts(xsk, i)) | 1278 | if (complete_pkts(xsk, i)) |
| 1284 | return TEST_FAILURE; | 1279 | return TEST_FAILURE; |
| 1285 | 1280 | ||
| 1286 | usleep(10); | 1281 | usleep(10); |
| 1287 | return TEST_PASS; | ||
| 1288 | } | 1282 | } |
| 1289 | 1283 | ||
| 1284 | /* Loop completion is driven by send_pkts() stream progress checks. */ | ||
| 1290 | return TEST_CONTINUE; | 1285 | return TEST_CONTINUE; |
| 1291 | } | 1286 | } |
| 1292 | 1287 | ||
| @@ -1322,7 +1317,6 @@ bool all_packets_sent(struct test_spec *test, unsigned long *bitmap) · 29 unmodified lines | |||
| 1322 | 1317 | ||
| 1323 | static int send_pkts(struct test_spec *test, struct ifobject *ifobject) | 1318 | static int send_pkts(struct test_spec *test, struct ifobject *ifobject) |
| 1324 | { | 1319 | { |
| 1325 | bool timeout = !is_umem_valid(test->ifobj_rx->xsk); | ||
| 1326 | DECLARE_BITMAP(bitmap, test->nb_sockets); | 1320 | DECLARE_BITMAP(bitmap, test->nb_sockets); |
| 1327 | u32 i, ret; | 1321 | u32 i, ret; |
| 1328 | 1322 | ||
| @@ -1337,19 +1331,18 @@ static int send_pkts(struct test_spec *test, struct ifobject *ifobject) · 8 unmodified lines | |||
| 1337 | __set_bit(i, bitmap); | 1331 | __set_bit(i, bitmap); |
| 1338 | continue; | 1332 | continue; |
| 1339 | } | 1333 | } |
| 1340 | ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], timeout); | 1334 | ret = __send_pkts(ifobject, &ifobject->xsk_arr[i], test->poll_tmout); |
| 1341 | if (ret == TEST_CONTINUE && !test->fail) | 1335 | if (ret != TEST_CONTINUE) |
| 1342 | continue; | ||
| 1343 | |||
| 1344 | if ((ret || test->fail) && !timeout) | ||
| 1345 | return TEST_FAILURE; | ||
| 1346 | |||
| 1347 | if (ret == TEST_PASS && timeout) | ||
| 1348 | return ret; | 1336 | return ret; |
| 1349 | 1337 | ||
| 1350 | ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); | 1338 | if (test->fail) |
| 1351 | if (ret) | ||
| 1352 | return TEST_FAILURE; | 1339 | return TEST_FAILURE; |
| 1340 | |||
| 1341 | if (!test->poll_tmout) { | ||
| 1342 | ret = wait_for_tx_completion(&ifobject->xsk_arr[i]); | ||
| 1343 | if (ret) | ||
| 1344 | return TEST_FAILURE; | ||
| 1345 | } | ||
| 1353 | } | 1346 | } |
| 1354 | } | 1347 | } |
| 1355 | 1348 | ||
| @@ -1677,7 +1670,8 @@ void *worker_testapp_validate_rx(void *arg) · 321 unmodified lines | |||
| 1677 | strerror(-err)); | 1670 | strerror(-err)); |
| 1678 | } | 1671 | } |
| 1679 | 1672 | ||
| 1680 | pthread_barrier_wait(&barr); | 1673 | if (test->use_barrier) |
| 1674 | pthread_barrier_wait(&barr); | ||
| 1681 | 1675 | ||
| 1682 | /* We leave only now in case of error to avoid getting stuck in the barrier */ | 1676 | /* We leave only now in case of error to avoid getting stuck in the barrier */ |
| 1683 | if (err) { | 1677 | if (err) { |
| @@ -1716,11 +1710,6 @@ static void testapp_clean_xsk_umem(struct ifobject *ifobj) · 32 unmodified lines | |||
| 1716 | munmap(umem->buffer, umem->mmap_size); | 1710 | munmap(umem->buffer, umem->mmap_size); |
| 1717 | } | 1711 | } |
| 1718 | 1712 | ||
| 1719 | static void handler(int signum) | ||
| 1720 | { | ||
| 1721 | pthread_exit(NULL); | ||
| 1722 | } | ||
| 1723 | |||
| 1724 | static bool xdp_prog_changed_rx(struct test_spec *test) | 1713 | static bool xdp_prog_changed_rx(struct test_spec *test) |
| 1725 | { | 1714 | { |
| 1726 | struct ifobject *ifobj = test->ifobj_rx; | 1715 | struct ifobject *ifobj = test->ifobj_rx; |
| @@ -1825,9 +1814,18 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i · 98 unmodified lines | |||
| 1825 | return TEST_FAILURE; | 1814 | return TEST_FAILURE; |
| 1826 | } | 1815 | } |
| 1827 | 1816 | ||
| 1828 | if (ifobj2) { | 1817 | err = xsk_attach_xdp_progs(test, ifobj1, ifobj2); |
| 1818 | if (err) { | ||
| 1819 | ksft_print_msg("Error: failed to attach XDP programs: %d (%s)\n", | ||
| 1820 | err, strerror(-err)); | ||
| 1821 | return TEST_FAILURE; | ||
| 1822 | } | ||
| 1823 | test->use_barrier = !!ifobj2; | ||
| 1824 | |||
| 1825 | if (test->use_barrier) { | ||
| 1829 | if (pthread_barrier_init(&barr, NULL, 2)) | 1826 | if (pthread_barrier_init(&barr, NULL, 2)) |
| 1830 | return TEST_FAILURE; | 1827 | return TEST_FAILURE; |
| 1828 | |||
| 1831 | pkt_stream_reset(ifobj2->xsk->pkt_stream); | 1829 | pkt_stream_reset(ifobj2->xsk->pkt_stream); |
| 1832 | } | 1830 | } |
| 1833 | 1831 | ||
| @@ -1835,27 +1833,26 @@ static int __testapp_validate_traffic(struct test_spec *test, struct ifobject *i · 1 unmodified line | |||
| 1835 | pkt_stream_reset(ifobj1->xsk->pkt_stream); | 1833 | pkt_stream_reset(ifobj1->xsk->pkt_stream); |
| 1836 | pkts_in_flight = 0; | 1834 | pkts_in_flight = 0; |
| 1837 | 1835 | ||
| 1838 | signal(SIGUSR1, handler); | ||
| 1839 | /*Spawn RX thread */ | 1836 | /*Spawn RX thread */ |
| 1840 | pthread_create(&t0, NULL, ifobj1->func_ptr, test); | 1837 | pthread_create(&t0, NULL, ifobj1->func_ptr, test); |
| 1841 | 1838 | ||
| 1842 | if (ifobj2) { | 1839 | if (test->use_barrier) { |
| 1843 | pthread_barrier_wait(&barr); | 1840 | pthread_barrier_wait(&barr); |
| 1844 | if (pthread_barrier_destroy(&barr)) { | 1841 | if (pthread_barrier_destroy(&barr)) { |
| 1845 | pthread_kill(t0, SIGUSR1); | 1842 | test->use_barrier = false; |
| 1843 | pthread_join(t0, NULL); | ||
| 1846 | clean_sockets(test, ifobj1); | 1844 | clean_sockets(test, ifobj1); |
| 1847 | clean_umem(test, ifobj1, NULL); | 1845 | clean_umem(test, ifobj1, NULL); |
| 1848 | return TEST_FAILURE; | 1846 | return TEST_FAILURE; |
| 1849 | } | 1847 | } |
| 1848 | } | ||
| 1850 | 1849 | ||
| 1850 | if (ifobj2) { | ||
| 1851 | /*Spawn TX thread */ | 1851 | /*Spawn TX thread */ |
| 1852 | pthread_create(&t1, NULL, ifobj2->func_ptr, test); | 1852 | pthread_create(&t1, NULL, ifobj2->func_ptr, test); |
| 1853 | |||
| 1854 | pthread_join(t1, NULL); | 1853 | pthread_join(t1, NULL); |
| 1855 | } | 1854 | } |
| 1856 | 1855 | ||
| 1857 | if (!ifobj2) | ||
| 1858 | pthread_kill(t0, SIGUSR1); | ||
| 1859 | pthread_join(t0, NULL); | 1856 | pthread_join(t0, NULL); |
| 1860 | 1857 | ||
| 1861 | if (test->total_steps == test->current_step || test->fail) { | 1858 | if (test->total_steps == test->current_step || test->fail) { |
| @@ -1893,8 +1890,6 @@ static int testapp_validate_traffic(struct test_spec *test) · 31 unmodified lines | |||
| 1893 | } | 1890 | } |
| 1894 | } | 1891 | } |
| 1895 | 1892 | ||
| 1896 | if (xsk_attach_xdp_progs(test, ifobj_rx, ifobj_tx)) | ||
| 1897 | return TEST_FAILURE; | ||
| 1898 | return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); | 1893 | return __testapp_validate_traffic(test, ifobj_rx, ifobj_tx); |
| 1899 | } | 1894 | } |
| 1900 | 1895 | ||
| @@ -2231,16 +2226,33 @@ int testapp_xdp_shared_umem(struct test_spec *test) · 330 unmodified lines | |||
| 2231 | 2226 | ||
| 2232 | int testapp_poll_txq_tmout(struct test_spec *test) | 2227 | int testapp_poll_txq_tmout(struct test_spec *test) |
| 2233 | { | 2228 | { |
| 2229 | bool shared_umem = test->ifobj_tx->shared_umem; | ||
| 2230 | int ret; | ||
| 2231 | |||
| 2232 | test->poll_tmout = true; | ||
| 2233 | /* | ||
| 2234 | * POLL_TXQ_FULL exercises TX timeout setup in isolation. | ||
| 2235 | * Keep TX out of shared-UMEM mode here so TX setup does not require | ||
| 2236 | * RX UMEM to be initialized first. | ||
| 2237 | */ | ||
| 2238 | test->ifobj_tx->shared_umem = false; | ||
| 2234 | test->ifobj_tx->use_poll = true; | 2239 | test->ifobj_tx->use_poll = true; |
| 2235 | /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ | 2240 | /* create invalid frame by set umem frame_size and pkt length equal to 2048 */ |
| 2236 | test->ifobj_tx->xsk->umem->frame_size = 2048; | 2241 | test->ifobj_tx->xsk->umem->frame_size = 2048; |
| 2237 | if (pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048)) | 2242 | if (pkt_stream_replace(test, 2 * DEFAULT_PKT_CNT, 2048)) { |
| 2243 | test->ifobj_tx->shared_umem = shared_umem; | ||
| 2238 | return TEST_FAILURE; | 2244 | return TEST_FAILURE; |
| 2239 | return testapp_validate_traffic_single_thread(test, test->ifobj_tx); | 2245 | } |
| 2246 | |||
| 2247 | ret = testapp_validate_traffic_single_thread(test, test->ifobj_tx); | ||
| 2248 | test->ifobj_tx->shared_umem = shared_umem; | ||
| 2249 | |||
| 2250 | return ret; | ||
| 2240 | } | 2251 | } |
| 2241 | 2252 | ||
| 2242 | int testapp_poll_rxq_tmout(struct test_spec *test) | 2253 | int testapp_poll_rxq_tmout(struct test_spec *test) |
| 2243 | { | 2254 | { |
| 2255 | test->poll_tmout = true; | ||
| 2244 | test->ifobj_rx->use_poll = true; | 2256 | test->ifobj_rx->use_poll = true; |
| 2245 | return testapp_validate_traffic_single_thread(test, test->ifobj_rx); | 2257 | return testapp_validate_traffic_single_thread(test, test->ifobj_rx); |
| 2246 | } | 2258 | } |
| @@ -207,6 +207,8 @@ struct test_spec { · 206 unmodified lines | |||
| 207 | bool set_ring; | 207 | bool set_ring; |
| 208 | bool adjust_tail; | 208 | bool adjust_tail; |
| 209 | bool adjust_tail_support; | 209 | bool adjust_tail_support; |
| 210 | bool poll_tmout; | ||
| 211 | bool use_barrier; | ||
| 210 | enum test_mode mode; | 212 | enum test_mode mode; |
| 211 | char name[MAX_TEST_NAME_SIZE]; | 213 | char name[MAX_TEST_NAME_SIZE]; |
| 212 | }; | 214 | }; |
| @@ -1,6 +1,8 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | #include <test_progs.h> | 2 | #include <test_progs.h> |
| 3 | #include <network_helpers.h> | 3 | #include <network_helpers.h> |
| 4 | #include <linux/ipv6.h> | ||
| 5 | #include <arpa/inet.h> | ||
| 4 | #include "test_xdp_context_test_run.skel.h" | 6 | #include "test_xdp_context_test_run.skel.h" |
| 5 | #include "test_xdp_meta.skel.h" | 7 | #include "test_xdp_meta.skel.h" |
| 6 | 8 | ||
| @@ -8,9 +10,12 @@ · 1 unmodified line | |||
| 8 | #define TX_NAME "veth1" | 10 | #define TX_NAME "veth1" |
| 9 | #define TX_NETNS "xdp_context_tx" | 11 | #define TX_NETNS "xdp_context_tx" |
| 10 | #define RX_NETNS "xdp_context_rx" | 12 | #define RX_NETNS "xdp_context_rx" |
| 13 | #define RX_MAC "02:00:00:00:00:01" | ||
| 14 | #define TX_MAC "02:00:00:00:00:02" | ||
| 11 | #define TAP_NAME "tap0" | 15 | #define TAP_NAME "tap0" |
| 12 | #define DUMMY_NAME "dum0" | 16 | #define DUMMY_NAME "dum0" |
| 13 | #define TAP_NETNS "xdp_context_tuntap" | 17 | #define TAP_NETNS "xdp_context_tuntap" |
| 18 | #define LWT_NETNS "xdp_context_lwt" | ||
| 14 | 19 | ||
| 15 | #define TEST_PAYLOAD_LEN 32 | 20 | #define TEST_PAYLOAD_LEN 32 |
| 16 | static const __u8 test_payload[TEST_PAYLOAD_LEN] = { | 21 | static const __u8 test_payload[TEST_PAYLOAD_LEN] = { |
| @@ -187,6 +192,42 @@ static int write_test_packet(int tap_fd) · 170 unmodified lines | |||
| 187 | return 0; | 192 | return 0; |
| 188 | } | 193 | } |
| 189 | 194 | ||
| 195 | /* Inject Ethernet+IPv6+UDP frame into TAP */ | ||
| 196 | static int write_test_packet_udp(int tap_fd) | ||
| 197 | { | ||
| 198 | __u8 pkt[sizeof(struct ethhdr) + sizeof(struct ipv6hdr) + | ||
| 199 | sizeof(struct udphdr) + TEST_PAYLOAD_LEN] = {}; | ||
| 200 | struct ethhdr *eth = (void *)pkt; | ||
| 201 | struct ipv6hdr *ip6 = (void *)(eth + 1); | ||
| 202 | struct udphdr *udp = (void *)(ip6 + 1); | ||
| 203 | __u8 *payload = (void *)(udp + 1); | ||
| 204 | const __u8 tap_mac[ETH_ALEN] = { 0x02, 0, 0, 0, 0, 0x01 }; | ||
| 205 | int n; | ||
| 206 | |||
| 207 | memcpy(eth->h_dest, tap_mac, ETH_ALEN); | ||
| 208 | eth->h_proto = htons(ETH_P_IPV6); | ||
| 209 | |||
| 210 | ip6->version = 6; | ||
| 211 | ip6->hop_limit = 64; | ||
| 212 | ip6->nexthdr = IPPROTO_UDP; | ||
| 213 | ip6->payload_len = htons(sizeof(*udp) + TEST_PAYLOAD_LEN); | ||
| 214 | inet_pton(AF_INET6, "fd00::2", &ip6->saddr); | ||
| 215 | inet_pton(AF_INET6, "fd00:1::1", &ip6->daddr); | ||
| 216 | |||
| 217 | udp->source = htons(42); | ||
| 218 | udp->dest = htons(42); | ||
| 219 | udp->len = htons(sizeof(*udp) + TEST_PAYLOAD_LEN); | ||
| 220 | /* UDP checksum is not validated on the forwarding path. */ | ||
| 221 | |||
| 222 | memcpy(payload, test_payload, TEST_PAYLOAD_LEN); | ||
| 223 | |||
| 224 | n = write(tap_fd, pkt, sizeof(pkt)); | ||
| 225 | if (!ASSERT_EQ(n, sizeof(pkt), "write frame")) | ||
| 226 | return -1; | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 190 | static void dump_err_stream(const struct bpf_program *prog) | 231 | static void dump_err_stream(const struct bpf_program *prog) |
| 191 | { | 232 | { |
| 192 | char buf[512]; | 233 | char buf[512]; |
| @@ -518,3 +559,137 @@ void test_xdp_context_tuntap(void) · 325 unmodified lines | |||
| 518 | 559 | ||
| 519 | test_xdp_meta__destroy(skel); | 560 | test_xdp_meta__destroy(skel); |
| 520 | } | 561 | } |
| 562 | |||
| 563 | /* | ||
| 564 | * Test topology: | ||
| 565 | * | ||
| 566 | * tap0 fd00::1 | ||
| 567 | * RX: injected IPv6 UDP frame, XDP ingress sets metadata | ||
| 568 | * fwd: encap route prepends outer header(s) | ||
| 569 | * TX: TC egress validates metadata | ||
| 570 | * | ||
| 571 | * A routable IPv6 UDP frame is written into the tap fd, so it enters the RX | ||
| 572 | * path where XDP stores metadata. Routing then forwards it back out the same | ||
| 573 | * tap through an encapsulating route that prepends outer header(s). The TC | ||
| 574 | * egress program checks that the pushed header did not silently corrupt | ||
| 575 | * metadata. | ||
| 576 | */ | ||
| 577 | #define LWT_PIN_PATH "/sys/fs/bpf/xdp_context_lwt_xmit" | ||
| 578 | |||
| 579 | enum lwt_encap_type { | ||
| 580 | LWT_ENCAP_BPF, | ||
| 581 | LWT_ENCAP_MPLS, | ||
| 582 | LWT_ENCAP_SEG6, | ||
| 583 | LWT_ENCAP_IOAM6, | ||
| 584 | }; | ||
| 585 | |||
| 586 | static void test_lwt_encap(struct test_xdp_meta *skel, | ||
| 587 | enum lwt_encap_type type) | ||
| 588 | { | ||
| 589 | LIBBPF_OPTS(bpf_tc_hook, tc_hook, .attach_point = BPF_TC_EGRESS); | ||
| 590 | LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1); | ||
| 591 | struct bpf_program *lwt_prog = NULL; | ||
| 592 | struct netns_obj *ns = NULL; | ||
| 593 | const char *encap; | ||
| 594 | bool pinned = false; | ||
| 595 | int tap_ifindex; | ||
| 596 | int tap_fd = -1; | ||
| 597 | int ret; | ||
| 598 | |||
| 599 | skel->bss->test_pass = false; | ||
| 600 | |||
| 601 | switch (type) { | ||
| 602 | case LWT_ENCAP_BPF: | ||
| 603 | encap = "encap bpf xmit pinned " LWT_PIN_PATH " via fd00::2"; | ||
| 604 | lwt_prog = skel->progs.dummy_lwt_xmit; | ||
| 605 | break; | ||
| 606 | case LWT_ENCAP_MPLS: | ||
| 607 | encap = "encap mpls 100 via inet6 fd00::2"; | ||
| 608 | break; | ||
| 609 | case LWT_ENCAP_SEG6: | ||
| 610 | encap = "encap seg6 mode encap segs fd00::2"; | ||
| 611 | break; | ||
| 612 | case LWT_ENCAP_IOAM6: | ||
| 613 | encap = "encap ioam6 mode encap tundst fd00::2 " | ||
| 614 | "trace prealloc type 0x800000 ns 0 size 4 via fd00::2"; | ||
| 615 | break; | ||
| 616 | default: | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | |||
| 620 | if (lwt_prog) { | ||
| 621 | unlink(LWT_PIN_PATH); | ||
| 622 | ret = bpf_program__pin(lwt_prog, LWT_PIN_PATH); | ||
| 623 | if (!ASSERT_OK(ret, "pin lwt prog")) | ||
| 624 | return; | ||
| 625 | pinned = true; | ||
| 626 | } | ||
| 627 | |||
| 628 | ns = netns_new(LWT_NETNS, true); | ||
| 629 | if (!ASSERT_OK_PTR(ns, "netns_new")) | ||
| 630 | goto close; | ||
| 631 | |||
| 632 | tap_fd = open_tuntap(TAP_NAME, true); | ||
| 633 | if (!ASSERT_GE(tap_fd, 0, "open_tuntap")) | ||
| 634 | goto close; | ||
| 635 | |||
| 636 | SYS(close, "ip link set dev " TAP_NAME " address " RX_MAC); | ||
| 637 | SYS(close, "sysctl -wq net.ipv6.conf.all.forwarding=1"); | ||
| 638 | SYS(close, "ip addr add fd00::1/64 dev " TAP_NAME " nodad"); | ||
| 639 | SYS(close, "ip link set dev " TAP_NAME " up"); | ||
| 640 | SYS(close, "ip neigh add fd00::2 lladdr " TX_MAC " nud permanent dev " TAP_NAME); | ||
| 641 | SYS(close, "ip -6 route add fd00:1::/64 %s dev %s", encap, TAP_NAME); | ||
| 642 | |||
| 643 | tap_ifindex = if_nametoindex(TAP_NAME); | ||
| 644 | if (!ASSERT_GE(tap_ifindex, 0, "if_nametoindex")) | ||
| 645 | goto close; | ||
| 646 | |||
| 647 | ret = bpf_xdp_attach(tap_ifindex, bpf_program__fd(skel->progs.ing_xdp), | ||
| 648 | 0, NULL); | ||
| 649 | if (!ASSERT_GE(ret, 0, "bpf_xdp_attach")) | ||
| 650 | goto close; | ||
| 651 | |||
| 652 | tc_hook.ifindex = tap_ifindex; | ||
| 653 | ret = bpf_tc_hook_create(&tc_hook); | ||
| 654 | if (!ASSERT_OK(ret, "bpf_tc_hook_create")) | ||
| 655 | goto close; | ||
| 656 | |||
| 657 | tc_opts.prog_fd = bpf_program__fd(skel->progs.tc_is_meta_empty); | ||
| 658 | ret = bpf_tc_attach(&tc_hook, &tc_opts); | ||
| 659 | if (!ASSERT_OK(ret, "bpf_tc_attach")) | ||
| 660 | goto close; | ||
| 661 | |||
| 662 | ret = write_test_packet_udp(tap_fd); | ||
| 663 | if (!ASSERT_OK(ret, "write_test_packet_udp")) | ||
| 664 | goto close; | ||
| 665 | |||
| 666 | if (!ASSERT_TRUE(skel->bss->test_pass, "test_pass")) | ||
| 667 | dump_err_stream(skel->progs.tc_is_meta_empty); | ||
| 668 | |||
| 669 | close: | ||
| 670 | if (tap_fd >= 0) | ||
| 671 | close(tap_fd); | ||
| 672 | netns_free(ns); | ||
| 673 | if (pinned) | ||
| 674 | unlink(LWT_PIN_PATH); | ||
| 675 | } | ||
| 676 | |||
| 677 | void test_xdp_context_lwt_encap(void) | ||
| 678 | { | ||
| 679 | struct test_xdp_meta *skel; | ||
| 680 | |||
| 681 | skel = test_xdp_meta__open_and_load(); | ||
| 682 | if (!ASSERT_OK_PTR(skel, "open and load skeleton")) | ||
| 683 | return; | ||
| 684 | |||
| 685 | if (test__start_subtest("bpf_encap")) | ||
| 686 | test_lwt_encap(skel, LWT_ENCAP_BPF); | ||
| 687 | if (test__start_subtest("mpls_encap")) | ||
| 688 | test_lwt_encap(skel, LWT_ENCAP_MPLS); | ||
| 689 | if (test__start_subtest("seg6_encap")) | ||
| 690 | test_lwt_encap(skel, LWT_ENCAP_SEG6); | ||
| 691 | if (test__start_subtest("ioam6_encap")) | ||
| 692 | test_lwt_encap(skel, LWT_ENCAP_IOAM6); | ||
| 693 | |||
| 694 | test_xdp_meta__destroy(skel); | ||
| 695 | } | ||
| @@ -21,10 +21,6 @@ · 20 unmodified lines | |||
| 21 | 21 | ||
| 22 | bool test_pass; | 22 | bool test_pass; |
| 23 | 23 | ||
| 24 | static const __u8 smac_want[ETH_ALEN] = { | ||
| 25 | 0x12, 0x34, 0xDE, 0xAD, 0xBE, 0xEF, | ||
| 26 | }; | ||
| 27 | |||
| 28 | static const __u8 meta_want[META_SIZE] = { | 24 | static const __u8 meta_want[META_SIZE] = { |
| 29 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, | 25 | 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, |
| 30 | 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, | 26 | 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, |
| @@ -32,11 +28,6 @@ static const __u8 meta_want[META_SIZE] = { · 1 unmodified line | |||
| 32 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, | 28 | 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, |
| 33 | }; | 29 | }; |
| 34 | 30 | ||
| 35 | static bool check_smac(const struct ethhdr *eth) | ||
| 36 | { | ||
| 37 | return !__builtin_memcmp(eth->h_source, smac_want, ETH_ALEN); | ||
| 38 | } | ||
| 39 | |||
| 40 | static bool check_metadata(const char *file, int line, __u8 *meta_have) | 31 | static bool check_metadata(const char *file, int line, __u8 *meta_have) |
| 41 | { | 32 | { |
| 42 | if (!__builtin_memcmp(meta_have, meta_want, META_SIZE)) | 33 | if (!__builtin_memcmp(meta_have, meta_want, META_SIZE)) |
| @@ -280,18 +271,47 @@ fail: · 237 unmodified lines | |||
| 280 | return TC_ACT_SHOT; | 271 | return TC_ACT_SHOT; |
| 281 | } | 272 | } |
| 282 | 273 | ||
| 274 | /* Test packets carry test metadata pattern as payload. */ | ||
| 275 | static bool is_test_packet_xdp(struct xdp_md *ctx) | ||
| 276 | { | ||
| 277 | __u8 meta_have[META_SIZE]; | ||
| 278 | __u32 len; | ||
| 279 | |||
| 280 | len = bpf_xdp_get_buff_len(ctx); | ||
| 281 | if (len < META_SIZE) | ||
| 282 | return false; | ||
| 283 | if (bpf_xdp_load_bytes(ctx, len - META_SIZE, meta_have, META_SIZE)) | ||
| 284 | return false; | ||
| 285 | if (__builtin_memcmp(meta_have, meta_want, META_SIZE)) | ||
| 286 | return false; | ||
| 287 | |||
| 288 | return true; | ||
| 289 | } | ||
| 290 | |||
| 291 | /* Test packets carry test metadata pattern as payload. */ | ||
| 292 | static bool is_test_packet_tc(struct __sk_buff *ctx) | ||
| 293 | { | ||
| 294 | __u8 meta_have[META_SIZE]; | ||
| 295 | |||
| 296 | if (ctx->len < META_SIZE) | ||
| 297 | return false; | ||
| 298 | if (bpf_skb_load_bytes(ctx, ctx->len - META_SIZE, meta_have, META_SIZE)) | ||
| 299 | return false; | ||
| 300 | if (__builtin_memcmp(meta_have, meta_want, META_SIZE)) | ||
| 301 | return false; | ||
| 302 | |||
| 303 | return true; | ||
| 304 | } | ||
| 305 | |||
| 283 | /* Reserve and clear space for metadata but don't populate it */ | 306 | /* Reserve and clear space for metadata but don't populate it */ |
| 284 | SEC("xdp") | 307 | SEC("xdp") |
| 285 | int ing_xdp_zalloc_meta(struct xdp_md *ctx) | 308 | int ing_xdp_zalloc_meta(struct xdp_md *ctx) |
| 286 | { | 309 | { |
| 287 | struct ethhdr *eth = ctx_ptr(ctx, data); | ||
| 288 | __u8 *meta; | 310 | __u8 *meta; |
| 289 | int ret; | 311 | int ret; |
| 290 | 312 | ||
| 291 | /* Drop any non-test packets */ | 313 | /* Drop any non-test packets */ |
| 292 | if (eth + 1 > ctx_ptr(ctx, data_end)) | 314 | if (!is_test_packet_xdp(ctx)) |
| 293 | return XDP_DROP; | ||
| 294 | if (!check_smac(eth)) | ||
| 295 | return XDP_DROP; | 315 | return XDP_DROP; |
| 296 | 316 | ||
| 297 | ret = bpf_xdp_adjust_meta(ctx, -META_SIZE); | 317 | ret = bpf_xdp_adjust_meta(ctx, -META_SIZE); |
| @@ -310,33 +330,24 @@ int ing_xdp_zalloc_meta(struct xdp_md *ctx) · 12 unmodified lines | |||
| 310 | SEC("xdp") | 330 | SEC("xdp") |
| 311 | int ing_xdp(struct xdp_md *ctx) | 331 | int ing_xdp(struct xdp_md *ctx) |
| 312 | { | 332 | { |
| 313 | __u8 *data, *data_meta, *data_end, *payload; | 333 | __u8 *data, *data_meta; |
| 314 | struct ethhdr *eth; | ||
| 315 | int ret; | 334 | int ret; |
| 316 | 335 | ||
| 336 | /* Drop any non-test packets */ | ||
| 337 | if (!is_test_packet_xdp(ctx)) | ||
| 338 | return XDP_DROP; | ||
| 339 | |||
| 317 | ret = bpf_xdp_adjust_meta(ctx, -META_SIZE); | 340 | ret = bpf_xdp_adjust_meta(ctx, -META_SIZE); |
| 318 | if (ret < 0) | 341 | if (ret < 0) |
| 319 | return XDP_DROP; | 342 | return XDP_DROP; |
| 320 | 343 | ||
| 321 | data_meta = ctx_ptr(ctx, data_meta); | 344 | data_meta = ctx_ptr(ctx, data_meta); |
| 322 | data_end = ctx_ptr(ctx, data_end); | ||
| 323 | data = ctx_ptr(ctx, data); | 345 | data = ctx_ptr(ctx, data); |
| 324 | 346 | ||
| 325 | eth = (struct ethhdr *)data; | 347 | if (data_meta + META_SIZE > data) |
| 326 | payload = data + sizeof(struct ethhdr); | ||
| 327 | |||
| 328 | if (payload + META_SIZE > data_end || | ||
| 329 | data_meta + META_SIZE > data) | ||
| 330 | return XDP_DROP; | 348 | return XDP_DROP; |
| 331 | 349 | ||
| 332 | /* The Linux networking stack may send other packets on the test | 350 | __builtin_memcpy(data_meta, meta_want, META_SIZE); |
| 333 | * interface that interfere with the test. Just drop them. | ||
| 334 | * The test packets can be recognized by their source MAC address. | ||
| 335 | */ | ||
| 336 | if (!check_smac(eth)) | ||
| 337 | return XDP_DROP; | ||
| 338 | |||
| 339 | __builtin_memcpy(data_meta, payload, META_SIZE); | ||
| 340 | return XDP_PASS; | 351 | return XDP_PASS; |
| 341 | } | 352 | } |
| 342 | 353 | ||
| @@ -353,7 +364,7 @@ int clone_data_meta_survives_data_write(struct __sk_buff *ctx) · 10 unmodified lines | |||
| 353 | if (eth + 1 > ctx_ptr(ctx, data_end)) | 364 | if (eth + 1 > ctx_ptr(ctx, data_end)) |
| 354 | goto out; | 365 | goto out; |
| 355 | /* Ignore non-test packets */ | 366 | /* Ignore non-test packets */ |
| 356 | if (!check_smac(eth)) | 367 | if (!is_test_packet_tc(ctx)) |
| 357 | goto out; | 368 | goto out; |
| 358 | 369 | ||
| 359 | if (meta_have + META_SIZE > eth) | 370 | if (meta_have + META_SIZE > eth) |
| @@ -383,7 +394,7 @@ int clone_data_meta_survives_meta_write(struct __sk_buff *ctx) · 23 unmodified lines | |||
| 383 | if (eth + 1 > ctx_ptr(ctx, data_end)) | 394 | if (eth + 1 > ctx_ptr(ctx, data_end)) |
| 384 | goto out; | 395 | goto out; |
| 385 | /* Ignore non-test packets */ | 396 | /* Ignore non-test packets */ |
| 386 | if (!check_smac(eth)) | 397 | if (!is_test_packet_tc(ctx)) |
| 387 | goto out; | 398 | goto out; |
| 388 | 399 | ||
| 389 | if (meta_have + META_SIZE > eth) | 400 | if (meta_have + META_SIZE > eth) |
| @@ -416,7 +427,7 @@ int clone_meta_dynptr_survives_data_slice_write(struct __sk_buff *ctx) · 26 unmodified lines | |||
| 416 | if (!eth) | 427 | if (!eth) |
| 417 | goto out; | 428 | goto out; |
| 418 | /* Ignore non-test packets */ | 429 | /* Ignore non-test packets */ |
| 419 | if (!check_smac(eth)) | 430 | if (!is_test_packet_tc(ctx)) |
| 420 | goto out; | 431 | goto out; |
| 421 | 432 | ||
| 422 | bpf_dynptr_from_skb_meta(ctx, 0, &meta); | 433 | bpf_dynptr_from_skb_meta(ctx, 0, &meta); |
| @@ -436,16 +447,11 @@ out: · 13 unmodified lines | |||
| 436 | SEC("tc") | 447 | SEC("tc") |
| 437 | int clone_meta_dynptr_survives_meta_slice_write(struct __sk_buff *ctx) | 448 | int clone_meta_dynptr_survives_meta_slice_write(struct __sk_buff *ctx) |
| 438 | { | 449 | { |
| 439 | struct bpf_dynptr data, meta; | 450 | struct bpf_dynptr meta; |
| 440 | const struct ethhdr *eth; | ||
| 441 | __u8 *meta_have; | 451 | __u8 *meta_have; |
| 442 | 452 | ||
| 443 | bpf_dynptr_from_skb(ctx, 0, &data); | ||
| 444 | eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); | ||
| 445 | if (!eth) | ||
| 446 | goto out; | ||
| 447 | /* Ignore non-test packets */ | 453 | /* Ignore non-test packets */ |
| 448 | if (!check_smac(eth)) | 454 | if (!is_test_packet_tc(ctx)) |
| 449 | goto out; | 455 | goto out; |
| 450 | 456 | ||
| 451 | bpf_dynptr_from_skb_meta(ctx, 0, &meta); | 457 | bpf_dynptr_from_skb_meta(ctx, 0, &meta); |
| @@ -471,15 +477,10 @@ int clone_meta_dynptr_rw_before_data_dynptr_write(struct __sk_buff *ctx) · 19 unmodified lines | |||
| 471 | { | 477 | { |
| 472 | struct bpf_dynptr data, meta; | 478 | struct bpf_dynptr data, meta; |
| 473 | __u8 meta_have[META_SIZE]; | 479 | __u8 meta_have[META_SIZE]; |
| 474 | const struct ethhdr *eth; | ||
| 475 | int err; | 480 | int err; |
| 476 | 481 | ||
| 477 | bpf_dynptr_from_skb(ctx, 0, &data); | ||
| 478 | eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); | ||
| 479 | if (!eth) | ||
| 480 | goto out; | ||
| 481 | /* Ignore non-test packets */ | 482 | /* Ignore non-test packets */ |
| 482 | if (!check_smac(eth)) | 483 | if (!is_test_packet_tc(ctx)) |
| 483 | goto out; | 484 | goto out; |
| 484 | 485 | ||
| 485 | /* Expect read-write metadata before unclone */ | 486 | /* Expect read-write metadata before unclone */ |
| @@ -492,6 +493,7 @@ int clone_meta_dynptr_rw_before_data_dynptr_write(struct __sk_buff *ctx) · 6 unmodified lines | |||
| 492 | goto out; | 493 | goto out; |
| 493 | 494 | ||
| 494 | /* Helper write to payload will unclone the packet */ | 495 | /* Helper write to payload will unclone the packet */ |
| 496 | bpf_dynptr_from_skb(ctx, 0, &data); | ||
| 495 | bpf_dynptr_write(&data, offsetof(struct ethhdr, h_proto), "x", 1, 0); | 497 | bpf_dynptr_write(&data, offsetof(struct ethhdr, h_proto), "x", 1, 0); |
| 496 | 498 | ||
| 497 | err = bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0); | 499 | err = bpf_dynptr_read(meta_have, META_SIZE, &meta, 0, 0); |
| @@ -511,17 +513,12 @@ out: · 13 unmodified lines | |||
| 511 | SEC("tc") | 513 | SEC("tc") |
| 512 | int clone_meta_dynptr_rw_before_meta_dynptr_write(struct __sk_buff *ctx) | 514 | int clone_meta_dynptr_rw_before_meta_dynptr_write(struct __sk_buff *ctx) |
| 513 | { | 515 | { |
| 514 | struct bpf_dynptr data, meta; | 516 | struct bpf_dynptr meta; |
| 515 | __u8 meta_have[META_SIZE]; | 517 | __u8 meta_have[META_SIZE]; |
| 516 | const struct ethhdr *eth; | ||
| 517 | int err; | 518 | int err; |
| 518 | 519 | ||
| 519 | bpf_dynptr_from_skb(ctx, 0, &data); | ||
| 520 | eth = bpf_dynptr_slice(&data, 0, NULL, sizeof(*eth)); | ||
| 521 | if (!eth) | ||
| 522 | goto out; | ||
| 523 | /* Ignore non-test packets */ | 520 | /* Ignore non-test packets */ |
| 524 | if (!check_smac(eth)) | 521 | if (!is_test_packet_tc(ctx)) |
| 525 | goto out; | 522 | goto out; |
| 526 | 523 | ||
| 527 | /* Expect read-write metadata before unclone */ | 524 | /* Expect read-write metadata before unclone */ |
| @@ -545,6 +542,28 @@ out: · 17 unmodified lines | |||
| 545 | return TC_ACT_SHOT; | 542 | return TC_ACT_SHOT; |
| 546 | } | 543 | } |
| 547 | 544 | ||
| 545 | SEC("lwt_xmit") | ||
| 546 | int dummy_lwt_xmit(struct __sk_buff *ctx) | ||
| 547 | { | ||
| 548 | if (bpf_skb_change_head(ctx, sizeof(struct ipv6hdr), 0)) | ||
| 549 | return BPF_DROP; | ||
| 550 | |||
| 551 | return BPF_OK; | ||
| 552 | } | ||
| 553 | |||
| 554 | SEC("tc") | ||
| 555 | int tc_is_meta_empty(struct __sk_buff *ctx) | ||
| 556 | { | ||
| 557 | if (!is_test_packet_tc(ctx)) | ||
| 558 | return TC_ACT_OK; | ||
| 559 | |||
| 560 | if (ctx->data_meta != ctx->data) | ||
| 561 | return TC_ACT_OK; | ||
| 562 | |||
| 563 | test_pass = true; | ||
| 564 | return TC_ACT_OK; | ||
| 565 | } | ||
| 566 | |||
| 548 | SEC("tc") | 567 | SEC("tc") |
| 549 | int helper_skb_vlan_push_pop(struct __sk_buff *ctx) | 568 | int helper_skb_vlan_push_pop(struct __sk_buff *ctx) |
| 550 | { | 569 | { |
| @@ -13,6 +13,7 @@ TEST_PROGS := \ · 12 unmodified lines | |||
| 13 | bond_options.sh \ | 13 | bond_options.sh \ |
| 14 | bond_passive_lacp.sh \ | 14 | bond_passive_lacp.sh \ |
| 15 | bond_stacked_header_parse.sh \ | 15 | bond_stacked_header_parse.sh \ |
| 16 | bond_vlan_real_dev.sh \ | ||
| 16 | dev_addr_lists.sh \ | 17 | dev_addr_lists.sh \ |
| 17 | mode-1-recovery-updelay.sh \ | 18 | mode-1-recovery-updelay.sh \ |
| 18 | mode-2-recovery-updelay.sh \ | 19 | mode-2-recovery-updelay.sh \ |
| @@ -0,0 +1,180 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | # | ||
| 4 | # Test propagation of a real device's state to the VLANs stacked on top of it | ||
| 5 | # when the real device is (or becomes) a bond member. | ||
| 6 | # | ||
| 7 | # The kernel mirrors a real device's UP/DOWN, MTU and feature changes onto its | ||
| 8 | # VLANs. This is done asynchronously (netdev_work): doing it synchronously from | ||
| 9 | # the real device's notifier could deadlock. If the real device is brought up | ||
| 10 | # while enslaved to a bond - so its instance lock is held across NETDEV_UP - and | ||
| 11 | # a VLAN on top of it is itself a bond member, the synchronous propagation | ||
| 12 | # re-entered the stack and tried to take the same instance lock again. | ||
| 13 | # | ||
| 14 | # Cover both halves: | ||
| 15 | # - the deferred UP/DOWN, MTU and feature propagation actually lands on the | ||
| 16 | # VLAN (link state and MTU use an ops-locked dummy, i.e. the deferral path), | ||
| 17 | # - the deadlock-prone topology - a VLAN on a dummy, with the VLAN and the | ||
| 18 | # dummy each enslaved to a different bond - can be built without hanging. | ||
| 19 | |||
| 20 | ALL_TESTS=" | ||
| 21 | vlan_link_state | ||
| 22 | vlan_mtu | ||
| 23 | vlan_features | ||
| 24 | vlan_real_dev_enslave | ||
| 25 | " | ||
| 26 | |||
| 27 | REQUIRE_MZ=no | ||
| 28 | NUM_NETIFS=0 | ||
| 29 | lib_dir=$(dirname "$0") | ||
| 30 | source "$lib_dir"/../../../net/forwarding/lib.sh | ||
| 31 | |||
| 32 | # Return 0 if $dev in netns $ns has flag $flag set (e.g. UP) in its <...> flags. | ||
| 33 | link_has_flag() | ||
| 34 | { | ||
| 35 | local ns=$1 dev=$2 flag=$3 | ||
| 36 | |||
| 37 | ip -n "$ns" link show dev "$dev" 2>/dev/null | grep -q "[<,]${flag}[,>]" | ||
| 38 | } | ||
| 39 | |||
| 40 | link_lacks_flag() | ||
| 41 | { | ||
| 42 | ! link_has_flag "$@" | ||
| 43 | } | ||
| 44 | |||
| 45 | link_mtu_is() | ||
| 46 | { | ||
| 47 | local ns=$1 dev=$2 want=$3 cur | ||
| 48 | |||
| 49 | cur=$(ip -n "$ns" link show dev "$dev" 2>/dev/null | \ | ||
| 50 | sed -n 's/.* mtu \([0-9]\+\).*/\1/p') | ||
| 51 | [ "$cur" = "$want" ] | ||
| 52 | } | ||
| 53 | |||
| 54 | vlan_feature_is() | ||
| 55 | { | ||
| 56 | local ns=$1 dev=$2 feature=$3 value=$4 | ||
| 57 | |||
| 58 | ip netns exec "$ns" ethtool -k "$dev" 2>/dev/null | \ | ||
| 59 | grep -q "^$feature: $value" | ||
| 60 | } | ||
| 61 | |||
| 62 | link_has_master() | ||
| 63 | { | ||
| 64 | local ns=$1 dev=$2 master=$3 | ||
| 65 | |||
| 66 | ip -n "$ns" -o link show dev "$dev" 2>/dev/null | grep -q "master $master" | ||
| 67 | } | ||
| 68 | |||
| 69 | vlan_link_state() | ||
| 70 | { | ||
| 71 | RET=0 | ||
| 72 | |||
| 73 | ip -n "$NS" link add ls_dummy type dummy | ||
| 74 | ip -n "$NS" link add link ls_dummy name ls_vlan type vlan id 100 | ||
| 75 | |||
| 76 | # Bringing the real device up must propagate UP to the VLAN. | ||
| 77 | ip -n "$NS" link set ls_dummy up | ||
| 78 | busywait "$BUSYWAIT_TIMEOUT" link_has_flag "$NS" ls_vlan UP | ||
| 79 | check_err $? "VLAN did not go UP after the real device went UP" | ||
| 80 | |||
| 81 | # ... and likewise for DOWN. | ||
| 82 | ip -n "$NS" link set ls_dummy down | ||
| 83 | busywait "$BUSYWAIT_TIMEOUT" link_lacks_flag "$NS" ls_vlan UP | ||
| 84 | check_err $? "VLAN did not go DOWN after the real device went DOWN" | ||
| 85 | |||
| 86 | ip -n "$NS" link del ls_vlan | ||
| 87 | ip -n "$NS" link del ls_dummy | ||
| 88 | |||
| 89 | log_test "VLAN link state follows the real device" | ||
| 90 | } | ||
| 91 | |||
| 92 | vlan_mtu() | ||
| 93 | { | ||
| 94 | RET=0 | ||
| 95 | |||
| 96 | # The VLAN inherits the real device's MTU (2000) at creation time. | ||
| 97 | ip -n "$NS" link add mtu_dummy mtu 2000 type dummy | ||
| 98 | ip -n "$NS" link add link mtu_dummy name mtu_vlan type vlan id 100 | ||
| 99 | |||
| 100 | # Shrinking the real device's MTU must clamp the VLAN's MTU. | ||
| 101 | ip -n "$NS" link set mtu_dummy mtu 1500 | ||
| 102 | busywait "$BUSYWAIT_TIMEOUT" link_mtu_is "$NS" mtu_vlan 1500 | ||
| 103 | check_err $? "VLAN MTU not clamped after the real device's MTU shrank" | ||
| 104 | |||
| 105 | ip -n "$NS" link del mtu_vlan | ||
| 106 | ip -n "$NS" link del mtu_dummy | ||
| 107 | |||
| 108 | log_test "VLAN MTU clamped to the real device" | ||
| 109 | } | ||
| 110 | |||
| 111 | vlan_features() | ||
| 112 | { | ||
| 113 | RET=0 | ||
| 114 | |||
| 115 | # Use veth as the real device: unlike dummy it exports vlan_features, so | ||
| 116 | # the VLAN actually inherits a toggleable offload to assert on. | ||
| 117 | ip -n "$NS" link add ft_veth type veth peer name ft_veth_pr | ||
| 118 | ip -n "$NS" link add link ft_veth name ft_vlan type vlan id 100 | ||
| 119 | |||
| 120 | vlan_feature_is "$NS" ft_vlan scatter-gather on | ||
| 121 | check_err $? "VLAN did not inherit scatter-gather from the real device" | ||
| 122 | |||
| 123 | # Toggling the offload on the real device must propagate to the VLAN. | ||
| 124 | ip netns exec "$NS" ethtool -K ft_veth sg off | ||
| 125 | busywait "$BUSYWAIT_TIMEOUT" \ | ||
| 126 | vlan_feature_is "$NS" ft_vlan scatter-gather off | ||
| 127 | check_err $? "VLAN scatter-gather still on after disabling it on real dev" | ||
| 128 | |||
| 129 | ip netns exec "$NS" ethtool -K ft_veth sg on | ||
| 130 | busywait "$BUSYWAIT_TIMEOUT" \ | ||
| 131 | vlan_feature_is "$NS" ft_vlan scatter-gather on | ||
| 132 | check_err $? "VLAN scatter-gather still off after enabling it on real dev" | ||
| 133 | |||
| 134 | ip -n "$NS" link del ft_vlan | ||
| 135 | ip -n "$NS" link del ft_veth | ||
| 136 | |||
| 137 | log_test "VLAN features follow the real device" | ||
| 138 | } | ||
| 139 | |||
| 140 | vlan_real_dev_enslave() | ||
| 141 | { | ||
| 142 | RET=0 | ||
| 143 | |||
| 144 | # dummy <- VLAN -> bond0, then enslave the dummy itself to bond1. The | ||
| 145 | # last step brings the dummy up under bond1's instance lock, which used | ||
| 146 | # to deadlock while synchronously propagating UP to the (bond-enslaved) | ||
| 147 | # VLAN on top. | ||
| 148 | ip -n "$NS" link add dl_dummy type dummy | ||
| 149 | ip -n "$NS" link set dl_dummy up | ||
| 150 | ip -n "$NS" link add link dl_dummy name dl_vlan type vlan id 100 | ||
| 151 | |||
| 152 | ip -n "$NS" link add dl_bond0 type bond mode active-backup | ||
| 153 | ip -n "$NS" link set dl_vlan down | ||
| 154 | ip -n "$NS" link set dl_vlan master dl_bond0 | ||
| 155 | check_err $? "could not enslave the VLAN to bond0" | ||
| 156 | |||
| 157 | ip -n "$NS" link add dl_bond1 type bond mode active-backup | ||
| 158 | ip -n "$NS" link set dl_dummy down | ||
| 159 | ip -n "$NS" link set dl_dummy master dl_bond1 | ||
| 160 | check_err $? "could not enslave the real device to bond1" | ||
| 161 | |||
| 162 | # If we got here the kernel did not deadlock; make sure it is still | ||
| 163 | # responsive and the enslave really took effect. | ||
| 164 | link_has_master "$NS" dl_dummy dl_bond1 | ||
| 165 | check_err $? "real device not enslaved to bond1" | ||
| 166 | |||
| 167 | ip -n "$NS" link del dl_bond1 | ||
| 168 | ip -n "$NS" link del dl_bond0 | ||
| 169 | ip -n "$NS" link del dl_vlan | ||
| 170 | ip -n "$NS" link del dl_dummy | ||
| 171 | |||
| 172 | log_test "VLAN real device enslaved to a second bond" | ||
| 173 | } | ||
| 174 | |||
| 175 | setup_ns NS | ||
| 176 | trap 'cleanup_ns $NS' EXIT | ||
| 177 | |||
| 178 | tests_run | ||
| 179 | |||
| 180 | exit "$EXIT_STATUS" | ||
| @@ -37,7 +37,7 @@ · 36 unmodified lines | |||
| 37 | 37 | ||
| 38 | static int cfg_clockid = CLOCK_TAI; | 38 | static int cfg_clockid = CLOCK_TAI; |
| 39 | static uint16_t cfg_port = 8000; | 39 | static uint16_t cfg_port = 8000; |
| 40 | static int cfg_variance_us = 4000; | 40 | static int cfg_variance_us = 8000; |
| 41 | static bool cfg_machine_slow; | 41 | static bool cfg_machine_slow; |
| 42 | static uint64_t cfg_start_time_ns; | 42 | static uint64_t cfg_start_time_ns; |
| 43 | static int cfg_mark; | 43 | static int cfg_mark; |
| @@ -44,7 +44,7 @@ test_broadcast_ether_dst() { · 43 unmodified lines | |||
| 44 | # tcpdump will exit after receiving a single packet | 44 | # tcpdump will exit after receiving a single packet |
| 45 | # timeout will kill tcpdump if it is still running after 2s | 45 | # timeout will kill tcpdump if it is still running after 2s |
| 46 | timeout 2s ip netns exec "${CLIENT_NS}" \ | 46 | timeout 2s ip netns exec "${CLIENT_NS}" \ |
| 47 | tcpdump -i link0 -c 1 -w "${CAPFILE}" icmp &> "${OUTPUT}" & | 47 | tcpdump -i link0 -c 1 -w "${CAPFILE}" -Z root icmp &> "${OUTPUT}" & |
| 48 | pid=$! | 48 | pid=$! |
| 49 | slowwait 1 grep -qs "listening" "${OUTPUT}" | 49 | slowwait 1 grep -qs "listening" "${OUTPUT}" |
| 50 | 50 | ||
| @@ -2,18 +2,32 @@ · 1 unmodified line | |||
| 2 | # SPDX-License-Identifier: GPL-2.0 | 2 | # SPDX-License-Identifier: GPL-2.0 |
| 3 | # | 3 | # |
| 4 | # Testing For SCTP COLLISION SCENARIO as Below: | 4 | # Testing For SCTP COLLISION SCENARIO as Below: |
| 5 | # | 5 | # 1. Stale INIT_ACK capture: |
| 6 | # 14:35:47.655279 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT] [init tag: 2017837359] | 6 | # 14:35:47.655279 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT] [init tag: 2017837359] |
| 7 | # 14:35:48.353250 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT] [init tag: 1187206187] | 7 | # 14:35:48.353250 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT] [init tag: 1187206187] |
| 8 | # 14:35:48.353275 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT ACK] [init tag: 2017837359] | 8 | # 14:35:48.353275 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT ACK] [init tag: 2017837359] |
| 9 | # 14:35:48.353283 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [COOKIE ECHO] | 9 | # 14:35:48.353283 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [COOKIE ECHO] |
| 10 | # 14:35:48.353977 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [COOKIE ACK] | 10 | # 14:35:48.353977 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [COOKIE ACK] |
| 11 | # 14:35:48.855335 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT ACK] [init tag: 164579970] | 11 | # 14:35:48.855335 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT ACK] [init tag: 164579970] |
| 12 | # (Delayed) | ||
| 13 | # | ||
| 14 | # 2. Stale INIT capture: | ||
| 15 | # 14:35:48.353250 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT] [init tag: 1187206187] | ||
| 16 | # 14:35:48.353275 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT ACK] [init tag: 2017837359] | ||
| 17 | # 14:35:48.353283 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [COOKIE ECHO] | ||
| 18 | # 14:35:48.353977 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [COOKIE ACK] | ||
| 19 | # 14:35:47.655279 IP CLIENT_IP.PORT > SERVER_IP.PORT: sctp (1) [INIT] [init tag: 2017837359] | ||
| 20 | # (Delayed) | ||
| 21 | # 14:35:48.855335 IP SERVER_IP.PORT > CLIENT_IP.PORT: sctp (1) [INIT ACK] [init tag: 164579970] | ||
| 12 | # | 22 | # |
| 13 | # TOPO: SERVER_NS (link0)<--->(link1) ROUTER_NS (link2)<--->(link3) CLIENT_NS | 23 | # TOPO: SERVER_NS (link0)<--->(link1) ROUTER_NS (link2)<--->(link3) CLIENT_NS |
| 14 | 24 | ||
| 15 | source lib.sh | 25 | source lib.sh |
| 16 | 26 | ||
| 27 | checktool "nft --version" "run test without nft" | ||
| 28 | checktool "tc -h" "run test without tc" | ||
| 29 | checktool "modprobe -q sctp" "load sctp module" | ||
| 30 | |||
| 17 | CLIENT_IP="198.51.200.1" | 31 | CLIENT_IP="198.51.200.1" |
| 18 | CLIENT_PORT=1234 | 32 | CLIENT_PORT=1234 |
| 19 | 33 | ||
| @@ -24,7 +38,8 @@ CLIENT_GW="198.51.200.2" · 4 unmodified lines | |||
| 24 | SERVER_GW="198.51.100.2" | 38 | SERVER_GW="198.51.100.2" |
| 25 | 39 | ||
| 26 | # setup the topo | 40 | # setup the topo |
| 27 | setup() { | 41 | topo_setup() { |
| 42 | # setup_ns cleans up existing net namespaces first. | ||
| 28 | setup_ns CLIENT_NS SERVER_NS ROUTER_NS | 43 | setup_ns CLIENT_NS SERVER_NS ROUTER_NS |
| 29 | ip -n "$SERVER_NS" link add link0 type veth peer name link1 netns "$ROUTER_NS" | 44 | ip -n "$SERVER_NS" link add link0 type veth peer name link1 netns "$ROUTER_NS" |
| 30 | ip -n "$CLIENT_NS" link add link3 type veth peer name link2 netns "$ROUTER_NS" | 45 | ip -n "$CLIENT_NS" link add link3 type veth peer name link2 netns "$ROUTER_NS" |
| @@ -38,35 +53,53 @@ setup() { · 7 unmodified lines | |||
| 38 | ip -n "$ROUTER_NS" addr add $SERVER_GW/24 dev link1 | 53 | ip -n "$ROUTER_NS" addr add $SERVER_GW/24 dev link1 |
| 39 | ip -n "$ROUTER_NS" addr add $CLIENT_GW/24 dev link2 | 54 | ip -n "$ROUTER_NS" addr add $CLIENT_GW/24 dev link2 |
| 40 | ip net exec "$ROUTER_NS" sysctl -wq net.ipv4.ip_forward=1 | 55 | ip net exec "$ROUTER_NS" sysctl -wq net.ipv4.ip_forward=1 |
| 56 | sysctl -wq net.netfilter.nf_log_all_netns=1 | ||
| 41 | 57 | ||
| 42 | ip -n "$CLIENT_NS" link set link3 up | 58 | ip -n "$CLIENT_NS" link set link3 up |
| 43 | ip -n "$CLIENT_NS" addr add $CLIENT_IP/24 dev link3 | 59 | ip -n "$CLIENT_NS" addr add $CLIENT_IP/24 dev link3 |
| 44 | ip -n "$CLIENT_NS" route add $SERVER_IP dev link3 via $CLIENT_GW | 60 | ip -n "$CLIENT_NS" route add $SERVER_IP dev link3 via $CLIENT_GW |
| 61 | } | ||
| 62 | |||
| 63 | conf_delay() | ||
| 64 | { | ||
| 65 | # simulate the delay on OVS upcall by setting up a delay for INIT_ACK/INIT with | ||
| 66 | local ns=$1 | ||
| 67 | local link=$2 | ||
| 68 | local chunk_type=$3 | ||
| 45 | 69 | ||
| 46 | # simulate the delay on OVS upcall by setting up a delay for INIT_ACK with | 70 | # use a smaller number for assoc's max_retrans to reproduce the issue |
| 47 | # tc on $SERVER_NS side | 71 | ip net exec "$CLIENT_NS" sysctl -wq net.sctp.association_max_retrans=3 |
| 48 | tc -n "$SERVER_NS" qdisc add dev link0 root handle 1: htb r2q 64 | 72 | |
| 49 | tc -n "$SERVER_NS" class add dev link0 parent 1: classid 1:1 htb rate 100mbit | 73 | tc -n "$ns" qdisc add dev "$link" root handle 1: htb r2q 64 |
| 50 | tc -n "$SERVER_NS" filter add dev link0 parent 1: protocol ip u32 match ip protocol 132 \ | 74 | tc -n "$ns" class add dev "$link" parent 1: classid 1:1 htb rate 100mbit |
| 51 | 0xff match u8 2 0xff at 32 flowid 1:1 | 75 | tc -n "$ns" filter add dev "$link" parent 1: protocol ip \ |
| 52 | if ! tc -n "$SERVER_NS" qdisc add dev link0 parent 1:1 handle 10: netem delay 1200ms; then | 76 | u32 match ip protocol 132 0xff match u8 "$chunk_type" 0xff at 32 flowid 1:1 |
| 77 | if ! tc -n "$ns" qdisc add dev "$link" parent 1:1 handle 10: netem delay 1200ms; then | ||
| 53 | echo "SKIP: Cannot add netem qdisc" | 78 | echo "SKIP: Cannot add netem qdisc" |
| 54 | exit $ksft_skip | 79 | return $ksft_skip |
| 55 | fi | 80 | fi |
| 56 | 81 | ||
| 57 | # simulate the ctstate check on OVS nf_conntrack | 82 | # simulate the ctstate check on OVS nf_conntrack |
| 58 | ip net exec "$ROUTER_NS" iptables -A FORWARD -m state --state INVALID,UNTRACKED -j DROP | 83 | ip net exec "$ROUTER_NS" nft -f - <<-EOF |
| 59 | ip net exec "$ROUTER_NS" iptables -A INPUT -p sctp -j DROP | 84 | table ip t { |
| 60 | 85 | chain forward { | |
| 61 | # use a smaller number for assoc's max_retrans to reproduce the issue | 86 | type filter hook forward priority filter; policy accept; |
| 62 | modprobe -q sctp | 87 | meta l4proto icmp counter accept |
| 63 | ip net exec "$CLIENT_NS" sysctl -wq net.sctp.association_max_retrans=3 | 88 | ct state new counter accept |
| 89 | ct state established,related counter accept | ||
| 90 | ct state invalid log flags all counter drop comment \ | ||
| 91 | "Expect to drop stale INIT/INIT_ACK chunks" | ||
| 92 | counter | ||
| 93 | } | ||
| 94 | } | ||
| 95 | EOF | ||
| 96 | return 0 | ||
| 64 | } | 97 | } |
| 65 | 98 | ||
| 66 | cleanup() { | 99 | cleanup() { |
| 67 | ip net exec "$CLIENT_NS" pkill sctp_collision >/dev/null 2>&1 | 100 | # cleanup_all_ns terminates running processes in the namespaces. |
| 68 | ip net exec "$SERVER_NS" pkill sctp_collision >/dev/null 2>&1 | ||
| 69 | cleanup_all_ns | 101 | cleanup_all_ns |
| 102 | sysctl -wq net.netfilter.nf_log_all_netns=0 | ||
| 70 | } | 103 | } |
| 71 | 104 | ||
| 72 | do_test() { | 105 | do_test() { |
| @@ -81,7 +114,19 @@ do_test() { · 8 unmodified lines | |||
| 81 | 114 | ||
| 82 | # run the test case | 115 | # run the test case |
| 83 | trap cleanup EXIT | 116 | trap cleanup EXIT |
| 84 | setup && \ | 117 | |
| 85 | echo "Test for SCTP Collision in nf_conntrack:" && \ | 118 | echo "Test for SCTP INIT_ACK Collision in nf_conntrack:" |
| 86 | do_test && echo "PASS!" | 119 | topo_setup || exit $? |
| 87 | exit $? | 120 | conf_delay $SERVER_NS link0 2 || exit $? |
| 121 | |||
| 122 | if ! do_test; then | ||
| 123 | exit $ksft_fail | ||
| 124 | fi | ||
| 125 | |||
| 126 | echo "Test for SCTP INIT Collision in nf_conntrack:" | ||
| 127 | topo_setup || exit $? | ||
| 128 | conf_delay $CLIENT_NS link3 1 || exit $? | ||
| 129 | |||
| 130 | if ! do_test; then | ||
| 131 | exit $ksft_fail | ||
| 132 | fi | ||
| @@ -592,7 +592,7 @@ ip -net "$nsr1" link set tun0 up · 591 unmodified lines | |||
| 592 | ip -net "$nsr1" addr add 192.168.100.1/24 dev tun0 | 592 | ip -net "$nsr1" addr add 192.168.100.1/24 dev tun0 |
| 593 | ip netns exec "$nsr1" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null | 593 | ip netns exec "$nsr1" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null |
| 594 | 594 | ||
| 595 | ip -net "$nsr1" link add name tun6 type ip6tnl local fee1:2::1 remote fee1:2::2 | 595 | ip -net "$nsr1" link add name tun6 type ip6tnl local fee1:2::1 remote fee1:2::2 encaplimit none |
| 596 | ip -net "$nsr1" link set tun6 up | 596 | ip -net "$nsr1" link set tun6 up |
| 597 | ip -net "$nsr1" addr add fee1:3::1/64 dev tun6 nodad | 597 | ip -net "$nsr1" addr add fee1:3::1/64 dev tun6 nodad |
| 598 | 598 | ||
| @@ -601,7 +601,7 @@ ip -net "$nsr2" link set tun0 up · 2 unmodified lines | |||
| 601 | ip -net "$nsr2" addr add 192.168.100.2/24 dev tun0 | 601 | ip -net "$nsr2" addr add 192.168.100.2/24 dev tun0 |
| 602 | ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null | 602 | ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0.forwarding=1 > /dev/null |
| 603 | 603 | ||
| 604 | ip -net "$nsr2" link add name tun6 type ip6tnl local fee1:2::2 remote fee1:2::1 || ret=1 | 604 | ip -net "$nsr2" link add name tun6 type ip6tnl local fee1:2::2 remote fee1:2::1 encaplimit none || ret=1 |
| 605 | ip -net "$nsr2" link set tun6 up | 605 | ip -net "$nsr2" link set tun6 up |
| 606 | ip -net "$nsr2" addr add fee1:3::2/64 dev tun6 nodad | 606 | ip -net "$nsr2" addr add fee1:3::2/64 dev tun6 nodad |
| 607 | 607 | ||
| @@ -651,7 +651,7 @@ ip -net "$nsr1" route change default via 192.168.200.2 · 43 unmodified lines | |||
| 651 | ip netns exec "$nsr1" sysctl net.ipv4.conf.tun0/10.forwarding=1 > /dev/null | 651 | ip netns exec "$nsr1" sysctl net.ipv4.conf.tun0/10.forwarding=1 > /dev/null |
| 652 | ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun0.10 accept' | 652 | ip netns exec "$nsr1" nft -a insert rule inet filter forward 'meta oif tun0.10 accept' |
| 653 | 653 | ||
| 654 | ip -net "$nsr1" link add name tun6.10 type ip6tnl local fee1:4::1 remote fee1:4::2 | 654 | ip -net "$nsr1" link add name tun6.10 type ip6tnl local fee1:4::1 remote fee1:4::2 encaplimit none |
| 655 | ip -net "$nsr1" link set tun6.10 up | 655 | ip -net "$nsr1" link set tun6.10 up |
| 656 | ip -net "$nsr1" addr add fee1:5::1/64 dev tun6.10 nodad | 656 | ip -net "$nsr1" addr add fee1:5::1/64 dev tun6.10 nodad |
| 657 | ip -6 -net "$nsr1" route delete default | 657 | ip -6 -net "$nsr1" route delete default |
| @@ -670,7 +670,7 @@ ip -net "$nsr2" addr add 192.168.200.2/24 dev tun0.10 · 12 unmodified lines | |||
| 670 | ip -net "$nsr2" route change default via 192.168.200.1 | 670 | ip -net "$nsr2" route change default via 192.168.200.1 |
| 671 | ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0/10.forwarding=1 > /dev/null | 671 | ip netns exec "$nsr2" sysctl net.ipv4.conf.tun0/10.forwarding=1 > /dev/null |
| 672 | 672 | ||
| 673 | ip -net "$nsr2" link add name tun6.10 type ip6tnl local fee1:4::2 remote fee1:4::1 || ret=1 | 673 | ip -net "$nsr2" link add name tun6.10 type ip6tnl local fee1:4::2 remote fee1:4::1 encaplimit none || ret=1 |
| 674 | ip -net "$nsr2" link set tun6.10 up | 674 | ip -net "$nsr2" link set tun6.10 up |
| 675 | ip -net "$nsr2" addr add fee1:5::2/64 dev tun6.10 nodad | 675 | ip -net "$nsr2" addr add fee1:5::2/64 dev tun6.10 nodad |
| 676 | ip -6 -net "$nsr2" route delete default | 676 | ip -6 -net "$nsr2" route delete default |
| @@ -85,11 +85,12 @@ ip -net "$ns3" route add default via 10.0.3.1 · 84 unmodified lines | |||
| 85 | ip -net "$ns3" route add default via dead:3::1 | 85 | ip -net "$ns3" route add default via dead:3::1 |
| 86 | 86 | ||
| 87 | load_ruleset() { | 87 | load_ruleset() { |
| 88 | local name=$1 | 88 | local family=$1 |
| 89 | local prio=$2 | 89 | local name=$2 |
| 90 | local prio=$3 | ||
| 90 | 91 | ||
| 91 | ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF | 92 | ip netns exec "$nsrouter" nft -f /dev/stdin <<EOF |
| 92 | table inet $name { | 93 | table $family $name { |
| 93 | chain nfq { | 94 | chain nfq { |
| 94 | ip protocol icmp queue bypass | 95 | ip protocol icmp queue bypass |
| 95 | icmpv6 type { "echo-request", "echo-reply" } queue num 1 bypass | 96 | icmpv6 type { "echo-request", "echo-reply" } queue num 1 bypass |
| @@ -228,6 +229,7 @@ nf_queue_wait() · 132 unmodified lines | |||
| 228 | test_queue() | 229 | test_queue() |
| 229 | { | 230 | { |
| 230 | local expected="$1" | 231 | local expected="$1" |
| 232 | local family="$2" | ||
| 231 | local last="" | 233 | local last="" |
| 232 | 234 | ||
| 233 | # spawn nf_queue listeners | 235 | # spawn nf_queue listeners |
| @@ -255,11 +257,13 @@ test_queue() · 21 unmodified lines | |||
| 255 | if [ x"$last" != x"$expected packets total" ]; then | 257 | if [ x"$last" != x"$expected packets total" ]; then |
| 256 | echo "FAIL: Expected $expected packets total, but got $last" 1>&2 | 258 | echo "FAIL: Expected $expected packets total, but got $last" 1>&2 |
| 257 | ip netns exec "$nsrouter" nft list ruleset | 259 | ip netns exec "$nsrouter" nft list ruleset |
| 260 | echo -n "$TMPFILE0: ";cat "$TMPFILE0" | ||
| 261 | echo -n "$TMPFILE1: ";cat "$TMPFILE1" | ||
| 258 | exit 1 | 262 | exit 1 |
| 259 | fi | 263 | fi |
| 260 | done | 264 | done |
| 261 | 265 | ||
| 262 | echo "PASS: Expected and received $last" | 266 | echo "PASS: Expected and received $last ($family)" |
| 263 | } | 267 | } |
| 264 | 268 | ||
| 265 | listener_ready() | 269 | listener_ready() |
| @@ -400,6 +404,8 @@ EOF · 134 unmodified lines | |||
| 400 | 404 | ||
| 401 | kill "$nfqpid" | 405 | kill "$nfqpid" |
| 402 | echo "PASS: icmp+nfqueue via vrf" | 406 | echo "PASS: icmp+nfqueue via vrf" |
| 407 | ip -net "$ns1" link del tvrf | ||
| 408 | ip netns exec "$ns1" nft flush ruleset | ||
| 403 | } | 409 | } |
| 404 | 410 | ||
| 405 | sctp_listener_ready() | 411 | sctp_listener_ready() |
| @@ -814,12 +820,53 @@ EOF · 408 unmodified lines | |||
| 814 | check_tainted "queue program exiting while packets queued" | 820 | check_tainted "queue program exiting while packets queued" |
| 815 | } | 821 | } |
| 816 | 822 | ||
| 823 | test_queue_bridge() | ||
| 824 | { | ||
| 825 | ip -net "$nsrouter" addr flush dev veth0 | ||
| 826 | ip -net "$nsrouter" addr flush dev veth1 | ||
| 827 | |||
| 828 | ip -net "$nsrouter" link add br0 type bridge | ||
| 829 | ip -net "$nsrouter" link set veth0 master br0 | ||
| 830 | ip -net "$nsrouter" link set veth1 master br0 | ||
| 831 | |||
| 832 | ip -net "$nsrouter" link set br0 up | ||
| 833 | |||
| 834 | ip -net "$nsrouter" addr add 10.0.2.1/16 dev br0 | ||
| 835 | ip -net "$nsrouter" addr add dead:2::1/64 dev br0 nodad | ||
| 836 | |||
| 837 | ip -net "$ns1" addr flush dev eth0 | ||
| 838 | ip -net "$ns2" addr flush dev eth0 | ||
| 839 | |||
| 840 | ip -net "$ns1" addr add 10.0.1.1/16 dev eth0 | ||
| 841 | ip -net "$ns1" addr add dead:2::2/64 dev eth0 nodad | ||
| 842 | |||
| 843 | ip -net "$ns2" addr add 10.0.2.99/16 dev eth0 | ||
| 844 | ip -net "$ns2" addr add dead:2::99/64 dev eth0 nodad | ||
| 845 | |||
| 846 | ip netns exec "$nsrouter" nft flush ruleset | ||
| 847 | |||
| 848 | ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=0 > /dev/null | ||
| 849 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=0 > /dev/null | ||
| 850 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=0 > /dev/null | ||
| 851 | |||
| 852 | if ! test_ping;then | ||
| 853 | echo "FAIL: netns bridge connectivity" 1>&2 | ||
| 854 | exit $ret | ||
| 855 | fi | ||
| 856 | |||
| 857 | load_ruleset "bridge" "filter" 10 | ||
| 858 | test_queue 10 "bridge" | ||
| 859 | |||
| 860 | load_ruleset "bridge" "filter2" 20 | ||
| 861 | test_queue 20 "bridge" | ||
| 862 | } | ||
| 863 | |||
| 817 | ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null | 864 | ip netns exec "$nsrouter" sysctl net.ipv6.conf.all.forwarding=1 > /dev/null |
| 818 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null | 865 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth0.forwarding=1 > /dev/null |
| 819 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null | 866 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth1.forwarding=1 > /dev/null |
| 820 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth2.forwarding=1 > /dev/null | 867 | ip netns exec "$nsrouter" sysctl net.ipv4.conf.veth2.forwarding=1 > /dev/null |
| 821 | 868 | ||
| 822 | load_ruleset "filter" 0 | 869 | load_ruleset "inet" "filter" 0 |
| 823 | 870 | ||
| 824 | if test_ping; then | 871 | if test_ping; then |
| 825 | # queue bypass works (rules were skipped, no listener) | 872 | # queue bypass works (rules were skipped, no listener) |
| @@ -842,11 +889,11 @@ load_counter_ruleset 10 · 16 unmodified lines | |||
| 842 | # 1x icmp prerouting,forward,postrouting -> 3 queue events (6 incl. reply). | 889 | # 1x icmp prerouting,forward,postrouting -> 3 queue events (6 incl. reply). |
| 843 | # 1x icmp prerouting,input,output postrouting -> 4 queue events incl. reply. | 890 | # 1x icmp prerouting,input,output postrouting -> 4 queue events incl. reply. |
| 844 | # so we expect that userspace program receives 10 packets. | 891 | # so we expect that userspace program receives 10 packets. |
| 845 | test_queue 10 | 892 | test_queue 10 "inet" |
| 846 | 893 | ||
| 847 | # same. We queue to a second program as well. | 894 | # same. We queue to a second program as well. |
| 848 | load_ruleset "filter2" 20 | 895 | load_ruleset "inet" "filter2" 20 |
| 849 | test_queue 20 | 896 | test_queue 20 "inet" |
| 850 | ip netns exec "$ns1" nft flush ruleset | 897 | ip netns exec "$ns1" nft flush ruleset |
| 851 | 898 | ||
| 852 | test_tcp_forward | 899 | test_tcp_forward |
| @@ -863,4 +910,7 @@ test_queue_stress · 10 unmodified lines | |||
| 863 | test_icmp_vrf | 910 | test_icmp_vrf |
| 864 | test_queue_removal | 911 | test_queue_removal |
| 865 | 912 | ||
| 913 | # turns router into a bridge | ||
| 914 | test_queue_bridge | ||
| 915 | |||
| 866 | exit $ret | 916 | exit $ret |
| @@ -997,6 +997,8 @@ TEST_F(tls, splice_short) · 996 unmodified lines | |||
| 997 | char sendbuf[0x100]; | 997 | char sendbuf[0x100]; |
| 998 | char sendchar = 'S'; | 998 | char sendchar = 'S'; |
| 999 | int pipefds[2]; | 999 | int pipefds[2]; |
| 1000 | int pipe_sz; | ||
| 1001 | int ret; | ||
| 1000 | int i; | 1002 | int i; |
| 1001 | 1003 | ||
| 1002 | sendchar_iov.iov_base = &sendchar; | 1004 | sendchar_iov.iov_base = &sendchar; |
| @@ -1005,7 +1007,11 @@ TEST_F(tls, splice_short) · 2 unmodified lines | |||
| 1005 | memset(sendbuf, 's', sizeof(sendbuf)); | 1007 | memset(sendbuf, 's', sizeof(sendbuf)); |
| 1006 | 1008 | ||
| 1007 | ASSERT_GE(pipe2(pipefds, O_NONBLOCK), 0); | 1009 | ASSERT_GE(pipe2(pipefds, O_NONBLOCK), 0); |
| 1008 | ASSERT_GE(fcntl(pipefds[0], F_SETPIPE_SZ, (MAX_FRAGS + 1) * 0x1000), 0); | 1010 | pipe_sz = (MAX_FRAGS + 1) * getpagesize(); |
| 1011 | ret = fcntl(pipefds[0], F_SETPIPE_SZ, pipe_sz); | ||
| 1012 | if (ret < 0 && errno == EPERM) | ||
| 1013 | SKIP(return, "insufficient pipe capacity"); | ||
| 1014 | ASSERT_GE(ret, pipe_sz); | ||
| 1009 | 1015 | ||
| 1010 | for (i = 0; i < MAX_FRAGS; i++) | 1016 | for (i = 0; i < MAX_FRAGS; i++) |
| 1011 | ASSERT_GE(vmsplice(pipefds[1], &sendchar_iov, 1, 0), 0); | 1017 | ASSERT_GE(vmsplice(pipefds[1], &sendchar_iov, 1, 0), 0); |
| @@ -64,7 +64,7 @@ check_operstate() · 63 unmodified lines | |||
| 64 | local expect=$1; shift | 64 | local expect=$1; shift |
| 65 | local operstate | 65 | local operstate |
| 66 | 66 | ||
| 67 | operstate=$(busywait 1000 \ | 67 | operstate=$(busywait 2000 \ |
| 68 | operstate_is "$dev" "$expect") | 68 | operstate_is "$dev" "$expect") |
| 69 | check_err $? "Got operstate of $operstate, expected $expect" | 69 | check_err $? "Got operstate of $operstate, expected $expect" |
| 70 | } | 70 | } |
| @@ -664,5 +664,43 @@ · 663 unmodified lines | |||
| 664 | "teardown": [ | 664 | "teardown": [ |
| 665 | "$TC qdisc del dev $DEV1 ingress_block 21 clsact" | 665 | "$TC qdisc del dev $DEV1 ingress_block 21 clsact" |
| 666 | ] | 666 | ] |
| 667 | }, | ||
| 668 | { | ||
| 669 | "id": "9c2a", | ||
| 670 | "name": "Act_ct preserves skb cb across defrag before prio dequeue", | ||
| 671 | "category": [ | ||
| 672 | "actions", | ||
| 673 | "ct", | ||
| 674 | "scapy" | ||
| 675 | ], | ||
| 676 | "plugins": { | ||
| 677 | "requires": [ | ||
| 678 | "nsPlugin", | ||
| 679 | "scapyPlugin" | ||
| 680 | ] | ||
| 681 | }, | ||
| 682 | "setup": [ | ||
| 683 | "$TC qdisc add dev $DUMMY root handle 1: prio", | ||
| 684 | "$TC qdisc add dev $DUMMY clsact", | ||
| 685 | "$TC qdisc add dev $DEV1 clsact", | ||
| 686 | "$TC filter add dev $DEV1 ingress protocol ip prio 1 matchall action mirred egress redirect dev $DUMMY" | ||
| 687 | ], | ||
| 688 | "cmdUnderTest": "$TC filter add dev $DUMMY egress protocol ip prio 1 matchall action ct zone 1 pipe", | ||
| 689 | "scapy": [ | ||
| 690 | { | ||
| 691 | "iface": "$DEV0", | ||
| 692 | "count": 1, | ||
| 693 | "packet": "[Ether()/frag for frag in fragment(IP(src='10.0.0.10', dst='10.0.0.1', id=1)/UDP(sport=12345, dport=9)/Raw(b'A' * 4000), fragsize=1400)]" | ||
| 694 | } | ||
| 695 | ], | ||
| 696 | "expExitCode": "0", | ||
| 697 | "verifyCmd": "$TC -s qdisc show dev $DUMMY | grep -A 1 '^qdisc prio 1:'", | ||
| 698 | "matchPattern": "Sent [1-9][0-9]* bytes [1-9][0-9]* pkt", | ||
| 699 | "matchCount": "1", | ||
| 700 | "teardown": [ | ||
| 701 | "$TC qdisc del dev $DEV1 clsact", | ||
| 702 | "$TC qdisc del dev $DUMMY clsact", | ||
| 703 | "$TC qdisc del dev $DUMMY root handle 1:" | ||
| 704 | ] | ||
| 667 | } | 705 | } |
| 668 | ] | 706 | ] |
| @@ -250,5 +250,49 @@ · 249 unmodified lines | |||
| 250 | "teardown": [ | 250 | "teardown": [ |
| 251 | "$TC qdisc del dev $DUMMY handle 1: root" | 251 | "$TC qdisc del dev $DUMMY handle 1: root" |
| 252 | ] | 252 | ] |
| 253 | }, | ||
| 254 | { | ||
| 255 | "id": "891f", | ||
| 256 | "name": "Verify DualPI2 GSO backlog accounting with QFQ parent", | ||
| 257 | "category": [ | ||
| 258 | "qdisc", | ||
| 259 | "dualpi2", | ||
| 260 | "qfq", | ||
| 261 | "gso" | ||
| 262 | ], | ||
| 263 | "plugins": { | ||
| 264 | "requires": "nsPlugin" | ||
| 265 | }, | ||
| 266 | "setup": [ | ||
| 267 | "$IP link set dev $DUMMY up || true", | ||
| 268 | "$IP addr add 10.10.10.10/24 dev $DUMMY || true", | ||
| 269 | "$TC qdisc add dev $DUMMY root handle 1: qfq", | ||
| 270 | "$TC class add dev $DUMMY parent 1: classid 1:1 qfq weight 1 maxpkt 4096", | ||
| 271 | "$TC qdisc add dev $DUMMY parent 1:1 handle 2: dualpi2", | ||
| 272 | "$TC filter add dev $DUMMY parent 1: matchall classid 1:1" | ||
| 273 | ], | ||
| 274 | "cmdUnderTest": "./tdc_gso.py 10.10.10.10 10.10.10.1 9000 1200 2400", | ||
| 275 | "expExitCode": "0", | ||
| 276 | "verifyCmd": "$TC -j -s qdisc ls dev $DUMMY", | ||
| 277 | "matchJSON": [ | ||
| 278 | { | ||
| 279 | "kind": "qfq", | ||
| 280 | "handle": "1:", | ||
| 281 | "packets": 2, | ||
| 282 | "backlog": 0, | ||
| 283 | "qlen": 0 | ||
| 284 | }, | ||
| 285 | { | ||
| 286 | "kind": "dualpi2", | ||
| 287 | "handle": "2:", | ||
| 288 | "packets": 2, | ||
| 289 | "backlog": 0, | ||
| 290 | "qlen": 0 | ||
| 291 | } | ||
| 292 | ], | ||
| 293 | "teardown": [ | ||
| 294 | "$TC qdisc del dev $DUMMY root", | ||
| 295 | "$IP addr del 10.10.10.10/24 dev $DUMMY || true" | ||
| 296 | ] | ||
| 253 | } | 297 | } |
| 254 | ] | 298 | ] |
| @@ -0,0 +1,43 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | """ | ||
| 5 | tdc_gso.py - send a UDP GSO datagram | ||
| 6 | |||
| 7 | Copyright (C) 2026 Xingquan Liu <b1n@b1n.io> | ||
| 8 | """ | ||
| 9 | |||
| 10 | import argparse | ||
| 11 | import socket | ||
| 12 | import struct | ||
| 13 | import sys | ||
| 14 | |||
| 15 | UDP_MAX_SEGMENTS = 1 << 7 | ||
| 16 | |||
| 17 | |||
| 18 | parser = argparse.ArgumentParser(description="UDP GSO datagram sender") | ||
| 19 | parser.add_argument("src", help="source IPv4 address") | ||
| 20 | parser.add_argument("dst", help="destination IPv4 address") | ||
| 21 | parser.add_argument("port", type=int, help="destination UDP port") | ||
| 22 | parser.add_argument("gso_size", type=int, help="UDP GSO segment payload size") | ||
| 23 | parser.add_argument("payload_len", type=int, help="total UDP payload length") | ||
| 24 | args = parser.parse_args() | ||
| 25 | |||
| 26 | if args.gso_size <= 0 or args.gso_size > 0xFFFF: | ||
| 27 | parser.error("gso_size must fit in an unsigned 16-bit integer") | ||
| 28 | if args.payload_len <= args.gso_size: | ||
| 29 | parser.error("payload_len must be larger than gso_size") | ||
| 30 | if args.payload_len > args.gso_size * UDP_MAX_SEGMENTS: | ||
| 31 | parser.error("payload_len exceeds UDP_MAX_SEGMENTS") | ||
| 32 | |||
| 33 | SOL_UDP = getattr(socket, "SOL_UDP", socket.IPPROTO_UDP) | ||
| 34 | UDP_SEGMENT = getattr(socket, "UDP_SEGMENT", 103) | ||
| 35 | |||
| 36 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | ||
| 37 | sock.bind((args.src, 0)) | ||
| 38 | |||
| 39 | payload = b"b" * args.payload_len | ||
| 40 | cmsg = [(SOL_UDP, UDP_SEGMENT, struct.pack("=H", args.gso_size))] | ||
| 41 | |||
| 42 | sent = sock.sendmsg([payload], cmsg, 0, (args.dst, args.port)) | ||
| 43 | sys.exit(sent != len(payload)) | ||