From 5191f4d82daf22b7ee9446f83527d2795e225974 Mon Sep 17 00:00:00 2001 From: Arturo Borrero Date: Thu, 29 Jan 2015 19:34:42 +0100 Subject: netfilter: nft_compat: add ebtables support This patch extends nft_compat to support ebtables extensions. ebtables verdict codes are translated to the ones used by the nf_tables engine, so we can properly use ebtables target extensions from nft_compat. This patch extends previous work by Giuseppe Longo . Signed-off-by: Arturo Borrero Gonzalez Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_compat.c | 63 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 265e190f2218..c598f74063a1 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c @@ -19,6 +19,7 @@ #include #include #include +#include #include static int nft_compat_chain_validate_dependency(const char *tablename, @@ -40,6 +41,7 @@ static int nft_compat_chain_validate_dependency(const char *tablename, union nft_entry { struct ipt_entry e4; struct ip6t_entry e6; + struct ebt_entry ebt; }; static inline void @@ -50,9 +52,9 @@ nft_compat_set_par(struct xt_action_param *par, void *xt, const void *xt_info) par->hotdrop = false; } -static void nft_target_eval(const struct nft_expr *expr, - struct nft_data data[NFT_REG_MAX + 1], - const struct nft_pktinfo *pkt) +static void nft_target_eval_xt(const struct nft_expr *expr, + struct nft_data data[NFT_REG_MAX + 1], + const struct nft_pktinfo *pkt) { void *info = nft_expr_priv(expr); struct xt_target *target = expr->ops->data; @@ -66,7 +68,7 @@ static void nft_target_eval(const struct nft_expr *expr, if (pkt->xt.hotdrop) ret = NF_DROP; - switch(ret) { + switch (ret) { case XT_CONTINUE: data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; break; @@ -74,7 +76,41 @@ static void nft_target_eval(const struct nft_expr *expr, data[NFT_REG_VERDICT].verdict = ret; break; } - return; +} + +static void nft_target_eval_bridge(const struct nft_expr *expr, + struct nft_data data[NFT_REG_MAX + 1], + const struct nft_pktinfo *pkt) +{ + void *info = nft_expr_priv(expr); + struct xt_target *target = expr->ops->data; + struct sk_buff *skb = pkt->skb; + int ret; + + nft_compat_set_par((struct xt_action_param *)&pkt->xt, target, info); + + ret = target->target(skb, &pkt->xt); + + if (pkt->xt.hotdrop) + ret = NF_DROP; + + switch (ret) { + case EBT_ACCEPT: + data[NFT_REG_VERDICT].verdict = NF_ACCEPT; + break; + case EBT_DROP: + data[NFT_REG_VERDICT].verdict = NF_DROP; + break; + case EBT_CONTINUE: + data[NFT_REG_VERDICT].verdict = NFT_CONTINUE; + break; + case EBT_RETURN: + data[NFT_REG_VERDICT].verdict = NFT_RETURN; + break; + default: + data[NFT_REG_VERDICT].verdict = ret; + break; + } } static const struct nla_policy nft_target_policy[NFTA_TARGET_MAX + 1] = { @@ -100,6 +136,10 @@ nft_target_set_tgchk_param(struct xt_tgchk_param *par, entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; + case NFPROTO_BRIDGE: + entry->ebt.ethproto = proto; + entry->ebt.invflags = inv ? EBT_IPROTO : 0; + break; } par->entryinfo = entry; par->target = target; @@ -307,6 +347,10 @@ nft_match_set_mtchk_param(struct xt_mtchk_param *par, const struct nft_ctx *ctx, entry->e6.ipv6.proto = proto; entry->e6.ipv6.invflags = inv ? IP6T_INV_PROTO : 0; break; + case NFPROTO_BRIDGE: + entry->ebt.ethproto = proto; + entry->ebt.invflags = inv ? EBT_IPROTO : 0; + break; } par->entryinfo = entry; par->match = match; @@ -490,6 +534,9 @@ nfnl_compat_get(struct sock *nfnl, struct sk_buff *skb, case AF_INET6: fmt = "ip6t_%s"; break; + case NFPROTO_BRIDGE: + fmt = "ebt_%s"; + break; default: pr_err("nft_compat: unsupported protocol %d\n", nfmsg->nfgen_family); @@ -663,13 +710,17 @@ nft_target_select_ops(const struct nft_ctx *ctx, nft_target->ops.type = &nft_target_type; nft_target->ops.size = NFT_EXPR_SIZE(XT_ALIGN(target->targetsize)); - nft_target->ops.eval = nft_target_eval; nft_target->ops.init = nft_target_init; nft_target->ops.destroy = nft_target_destroy; nft_target->ops.dump = nft_target_dump; nft_target->ops.validate = nft_target_validate; nft_target->ops.data = target; + if (family == NFPROTO_BRIDGE) + nft_target->ops.eval = nft_target_eval_bridge; + else + nft_target->ops.eval = nft_target_eval_xt; + list_add(&nft_target->head, &nft_target_list); return &nft_target->ops; -- cgit v1.2.3 From 4c1017aa80c95a74703139bb95c4ce0d130efe4d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 30 Jan 2015 07:46:33 +0000 Subject: netfilter: nft_lookup: add missing attribute validation for NFTA_LOOKUP_SET_ID Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nft_lookup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c index 6404a726d17b..9615b8b9fb37 100644 --- a/net/netfilter/nft_lookup.c +++ b/net/netfilter/nft_lookup.c @@ -39,6 +39,7 @@ static void nft_lookup_eval(const struct nft_expr *expr, static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { [NFTA_LOOKUP_SET] = { .type = NLA_STRING }, + [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, [NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, }; -- cgit v1.2.3 From aeb2d2a4c0ae1739a6e1782bd8c1c96aee8db4e1 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 20 Jan 2015 11:01:20 -0600 Subject: rtlwifi: Remove logging statement that is no longer needed In commit e9538cf4f907 ("rtlwifi: Fix error when accessing unmapped memory in skb"), a printk was included to indicate that the condition had been reached. There is now enough evidence from other users that the fix is working. That logging statement can now be removed. Signed-off-by: Larry Finger Cc: Stable [V3.18] Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/pci.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index ec456f0d972e..a62170ea0481 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -822,11 +822,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) /* get a new skb - if fail, old one will be reused */ new_skb = dev_alloc_skb(rtlpci->rxbuffersize); - if (unlikely(!new_skb)) { - pr_err("Allocation of new skb failed in %s\n", - __func__); + if (unlikely(!new_skb)) goto no_new; - } if (rtlpriv->use_new_trx_flow) { buffer_desc = &rtlpci->rx_ring[rxring_idx].buffer_desc -- cgit v1.2.3 From bf250a1fa769f2eb8fc7a4e28b3b523e9cb67eef Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Tue, 10 Feb 2015 11:37:29 -0500 Subject: ipv6: Partial checksum only UDP packets ip6_append_data is used by other protocols and some of them can't be partially checksummed. Only partially checksum UDP protocol. Fixes: 32dce968dd987a (ipv6: Allow for partial checksums on non-ufo packets) Reported-by: Sabrina Dubroca Tested-by: Sabrina Dubroca Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d33df4cbd872..7deebf102cba 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1273,7 +1273,7 @@ emsgsize: /* If this is the first and only packet and device * supports checksum offloading, let's use it. */ - if (!skb && + if (!skb && sk->sk_protocol == IPPROTO_UDP && length + fragheaderlen < mtu && rt->dst.dev->features & NETIF_F_V6_CSUM && !exthdrlen) -- cgit v1.2.3 From 80ad0d4a7a75158f2824d541e4802c88aba4f063 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Tue, 10 Feb 2015 13:33:37 -0500 Subject: rds: rds_cong_queue_updates needs to defer the congestion update transmission When the RDS transport is TCP, we cannot inline the call to rds_send_xmit from rds_cong_queue_update because (a) we are already holding the sock_lock in the recv path, and will deadlock when tcp_setsockopt/tcp_sendmsg try to get the sock lock (b) cong_queue_update does an irqsave on the rds_cong_lock, and this will trigger warnings (for a good reason) from functions called out of sock_lock. This patch reverts the change introduced by 2fa57129d ("RDS: Bypass workqueue when queueing cong updates"). The patch has been verified for both RDS/TCP as well as RDS/RDMA to ensure that there are not regressions for either transport: - for verification of RDS/TCP a client-server unit-test was used, with the server blocked in gdb and thus unable to drain its rcvbuf, eventually triggering a RDS congestion update. - for RDS/RDMA, the standard IB regression tests were used Signed-off-by: Sowmini Varadhan Signed-off-by: David S. Miller --- net/rds/cong.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/rds/cong.c b/net/rds/cong.c index e5b65acd650b..e6144b8246fd 100644 --- a/net/rds/cong.c +++ b/net/rds/cong.c @@ -221,7 +221,21 @@ void rds_cong_queue_updates(struct rds_cong_map *map) list_for_each_entry(conn, &map->m_conn_list, c_map_item) { if (!test_and_set_bit(0, &conn->c_map_queued)) { rds_stats_inc(s_cong_update_queued); - rds_send_xmit(conn); + /* We cannot inline the call to rds_send_xmit() here + * for two reasons (both pertaining to a TCP transport): + * 1. When we get here from the receive path, we + * are already holding the sock_lock (held by + * tcp_v4_rcv()). So inlining calls to + * tcp_setsockopt and/or tcp_sendmsg will deadlock + * when it tries to get the sock_lock()) + * 2. Interrupts are masked so that we can mark the + * the port congested from both send and recv paths. + * (See comment around declaration of rdc_cong_lock). + * An attempt to get the sock_lock() here will + * therefore trigger warnings. + * Defer the xmit to rds_send_worker() instead. + */ + queue_delayed_work(rds_wq, &conn->c_send_w, 0); } } -- cgit v1.2.3 From f7219b527b5710ae0c4add8faa4d0ea529722cb5 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Feb 2015 12:55:03 -0800 Subject: treewide: Remove unnecessary BCMA_CORETABLE_END macro Use the normal {} instead of a macro to terminate an array. Remove the macro too. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 2 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 2 +- drivers/spi/spi-bcm53xx.c | 2 +- drivers/usb/host/bcma-hcd.c | 2 +- include/linux/mod_devicetable.h | 2 -- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 3007d95fbb9f..ea63cb085d19 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -21,7 +21,7 @@ static const struct bcma_device_id bgmac_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS), - BCMA_CORETABLE_END + {}, }; MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 2c9088633ec6..6acb2b51ab8f 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -127,7 +127,7 @@ static const struct bcma_device_id b43_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS), - BCMA_CORETABLE_END + {}, }; MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl); #endif diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index f95b52442281..48135063347e 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -99,7 +99,7 @@ static struct bcma_device_id brcms_coreid_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS), BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS), - BCMA_CORETABLE_END + {}, }; MODULE_DEVICE_TABLE(bcma, brcms_coreid_table); diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index 17b34cbadc03..3fb91c81015a 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -216,7 +216,7 @@ static struct spi_board_info bcm53xx_info = { static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), - BCMA_CORETABLE_END + {}, }; MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl); diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index cd6d0afb6b8f..526cfab41d5f 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -306,7 +306,7 @@ static int bcma_hcd_resume(struct bcma_device *dev) static const struct bcma_device_id bcma_hcd_table[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), - BCMA_CORETABLE_END + {}, }; MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 745def862580..6711d57f9c05 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -381,8 +381,6 @@ struct bcma_device_id { } __attribute__((packed,aligned(2))); #define BCMA_CORE(_manuf, _id, _rev, _class) \ { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } -#define BCMA_CORETABLE_END \ - { 0, }, #define BCMA_ANY_MANUF 0xFFFF #define BCMA_ANY_ID 0xFFFF -- cgit v1.2.3 From 673e2baaa6d986e2fcd9c867661d8113f6c7dc7b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 10 Feb 2015 13:19:24 -0800 Subject: treewide: Remove unnecessary SSB_DEVTABLE_END macro Use the normal {} instead of a macro to terminate an array. Remove the macro too. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/b44.c | 2 +- drivers/net/wireless/b43/main.c | 2 +- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/ssb/driver_gige.c | 2 +- drivers/usb/host/ssb-hcd.c | 2 +- include/linux/mod_devicetable.h | 2 -- 6 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index d86d6baf9681..bd5916a60cb5 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -121,7 +121,7 @@ static struct pci_driver b44_pci_driver = { static const struct ssb_device_id b44_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV), - SSB_DEVTABLE_END + {}, }; MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 6acb2b51ab8f..ccbdb05b28cd 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -144,7 +144,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16), - SSB_DEVTABLE_END + {}, }; MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); #endif diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1aec2146a2bf..4e58c0069830 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -86,7 +86,7 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load."); static const struct ssb_device_id b43legacy_ssb_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4), - SSB_DEVTABLE_END + {}, }; MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl); diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c index 21f71a1581fa..e9734051e3c4 100644 --- a/drivers/ssb/driver_gige.c +++ b/drivers/ssb/driver_gige.c @@ -24,7 +24,7 @@ MODULE_LICENSE("GPL"); static const struct ssb_device_id ssb_gige_tbl[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV), - SSB_DEVTABLE_END + {}, }; /* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */ diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c index 0196f766df73..ffc32f4b1b1b 100644 --- a/drivers/usb/host/ssb-hcd.c +++ b/drivers/usb/host/ssb-hcd.c @@ -251,7 +251,7 @@ static const struct ssb_device_id ssb_hcd_table[] = { SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), - SSB_DEVTABLE_END + {}, }; MODULE_DEVICE_TABLE(ssb, ssb_hcd_table); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 6711d57f9c05..2bb97175b6cc 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -365,8 +365,6 @@ struct ssb_device_id { } __attribute__((packed, aligned(2))); #define SSB_DEVICE(_vendor, _coreid, _revision) \ { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } -#define SSB_DEVTABLE_END \ - { 0, }, #define SSB_ANY_VENDOR 0xFFFF #define SSB_ANY_ID 0xFFFF -- cgit v1.2.3 From b35725a285768d85b5ba1be7fe5002654a65ce88 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Tue, 10 Feb 2015 13:35:16 -0800 Subject: openvswitch: Reset key metadata for packet execution. Userspace packet execute command pass down flow key for given packet. But userspace can skip some parameter with zero value. Therefore kernel needs to initialize key metadata to zero. Fixes: 0714812134 ("openvswitch: Eliminate memset() from flow_extract.") Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/flow.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index e2c348b8baca..50ec42f170a0 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -717,6 +717,8 @@ int ovs_flow_key_extract_userspace(const struct nlattr *attr, { int err; + memset(key, 0, OVS_SW_FLOW_KEY_METADATA_SIZE); + /* Extract metadata from netlink attributes. */ err = ovs_nla_get_flow_metadata(attr, key, log); if (err) -- cgit v1.2.3 From 13101602c4a9f653d59af9469040797bc5b361ca Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Feb 2015 11:23:38 +0100 Subject: openvswitch: Add missing initialization in validate_and_copy_set_tun() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/openvswitch/flow_netlink.c: In function ‘validate_and_copy_set_tun’: net/openvswitch/flow_netlink.c:1749: warning: ‘err’ may be used uninitialized in this function If ipv4_tun_from_nlattr() returns a different positive value than OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS, err will be uninitialized, and validate_and_copy_set_tun() may return an undefined value instead of a zero success indicator. Initialize err to zero to fix this. Fixes: 1dd144cf5b4b47e1 ("openvswitch: Support VXLAN Group Policy extension") Signed-off-by: Geert Uytterhoeven Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/flow_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 993281e6278d..3829328c5a76 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1746,7 +1746,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, struct sw_flow_key key; struct ovs_tunnel_info *tun_info; struct nlattr *a; - int err, start, opts_type; + int err = 0, start, opts_type; ovs_match_init(&match, &key, NULL); opts_type = ipv4_tun_from_nlattr(nla_data(attr), &match, false, log); -- cgit v1.2.3 From 26c4f7da3e413da697a7beb22ad496390eda7da0 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:27 -0800 Subject: net: Fix remcsum in GRO path to not change packet Remote checksum offload processing is currently the same for both the GRO and non-GRO path. When the remote checksum offload option is encountered, the checksum field referred to is modified in the packet. So in the GRO case, the packet is modified in the GRO path and then the operation is skipped when the packet goes through the normal path based on skb->remcsum_offload. There is a problem in that the packet may be modified in the GRO path, but then forwarded off host still containing the remote checksum option. A remote host will again perform RCO but now the checksum verification will fail since GRO RCO already modified the checksum. To fix this, we ensure that GRO restores a packet to it's original state before returning. In this model, when GRO processes a remote checksum option it still changes the checksum per the algorithm but on return from lower layer processing the checksum is restored to its original value. In this patch we add define gro_remcsum structure which is passed to skb_gro_remcsum_process to save offset and delta for the checksum being changed. After lower layer processing, skb_gro_remcsum_cleanup is called to restore the checksum before returning from GRO. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 19 +++++++++---------- include/linux/netdevice.h | 25 +++++++++++++++++++++++-- include/net/checksum.h | 5 +++++ net/ipv4/fou.c | 20 ++++++++++---------- 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0e57e862c399..30310a63475a 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -555,12 +555,12 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, unsigned int off, struct vxlanhdr *vh, size_t hdrlen, - u32 data) + u32 data, struct gro_remcsum *grc) { size_t start, offset, plen; if (skb->remcsum_offload) - return vh; + return NULL; if (!NAPI_GRO_CB(skb)->csum_valid) return NULL; @@ -579,7 +579,8 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, return NULL; } - skb_gro_remcsum_process(skb, (void *)vh + hdrlen, start, offset); + skb_gro_remcsum_process(skb, (void *)vh + hdrlen, + start, offset, grc); skb->remcsum_offload = 1; @@ -597,6 +598,9 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock, udp_offloads); u32 flags; + struct gro_remcsum grc; + + skb_gro_remcsum_init(&grc); off_vx = skb_gro_offset(skb); hlen = off_vx + sizeof(*vh); @@ -614,7 +618,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr), - ntohl(vh->vx_vni)); + ntohl(vh->vx_vni), &grc); if (!vh) goto out; @@ -637,6 +641,7 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, pp = eth_gro_receive(head, skb); out: + skb_gro_remcsum_cleanup(skb, &grc); NAPI_GRO_CB(skb)->flush |= flush; return pp; @@ -1154,12 +1159,6 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, { size_t start, offset, plen; - if (skb->remcsum_offload) { - /* Already processed in GRO path */ - skb->remcsum_offload = 0; - return vh; - } - start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; offset = start + ((data & VXLAN_RCO_UDP) ? offsetof(struct udphdr, check) : diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d115256ed5a2..3aa02457fe4f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2321,8 +2321,19 @@ do { \ compute_pseudo(skb, proto)); \ } while (0) +struct gro_remcsum { + int offset; + __wsum delta; +}; + +static inline void skb_gro_remcsum_init(struct gro_remcsum *grc) +{ + grc->delta = 0; +} + static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, - int start, int offset) + int start, int offset, + struct gro_remcsum *grc) { __wsum delta; @@ -2331,10 +2342,20 @@ static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset); /* Adjust skb->csum since we changed the packet */ - skb->csum = csum_add(skb->csum, delta); NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); + + grc->offset = (ptr + offset) - (void *)skb->head; + grc->delta = delta; } +static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb, + struct gro_remcsum *grc) +{ + if (!grc->delta) + return; + + remcsum_unadjust((__sum16 *)(skb->head + grc->offset), grc->delta); +} static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, diff --git a/include/net/checksum.h b/include/net/checksum.h index e339a9513e29..0a55ac715077 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -167,4 +167,9 @@ static inline __wsum remcsum_adjust(void *ptr, __wsum csum, return delta; } +static inline void remcsum_unadjust(__sum16 *psum, __wsum delta) +{ + *psum = csum_fold(csum_sub(delta, *psum)); +} + #endif diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 92ddea1e6457..7fa8d36e56d4 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -71,12 +71,6 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, size_t offset = ntohs(pd[1]); size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); - if (skb->remcsum_offload) { - /* Already processed in GRO path */ - skb->remcsum_offload = 0; - return guehdr; - } - if (!pskb_may_pull(skb, plen)) return NULL; guehdr = (struct guehdr *)&udp_hdr(skb)[1]; @@ -214,7 +208,8 @@ out_unlock: static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, struct guehdr *guehdr, void *data, - size_t hdrlen, u8 ipproto) + size_t hdrlen, u8 ipproto, + struct gro_remcsum *grc) { __be16 *pd = data; size_t start = ntohs(pd[0]); @@ -222,7 +217,7 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); if (skb->remcsum_offload) - return guehdr; + return NULL; if (!NAPI_GRO_CB(skb)->csum_valid) return NULL; @@ -234,7 +229,8 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, return NULL; } - skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen, start, offset); + skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen, + start, offset, grc); skb->remcsum_offload = 1; @@ -254,6 +250,9 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, void *data; u16 doffset = 0; int flush = 1; + struct gro_remcsum grc; + + skb_gro_remcsum_init(&grc); off = skb_gro_offset(skb); len = off + sizeof(*guehdr); @@ -295,7 +294,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, if (flags & GUE_PFLAG_REMCSUM) { guehdr = gue_gro_remcsum(skb, off, guehdr, data + doffset, hdrlen, - guehdr->proto_ctype); + guehdr->proto_ctype, &grc); if (!guehdr) goto out; @@ -345,6 +344,7 @@ out_unlock: rcu_read_unlock(); out: NAPI_GRO_CB(skb)->flush |= flush; + skb_gro_remcsum_cleanup(skb, &grc); return pp; } -- cgit v1.2.3 From 6edec0e61b1e52f9144935d28c9088f5b202e61c Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:28 -0800 Subject: net: Clarify meaning of CHECKSUM_PARTIAL for receive path The current meaning of CHECKSUM_PARTIAL for validating checksums is that _all_ checksums in the packet are considered valid. However, in the manner that CHECKSUM_PARTIAL is set only the checksum at csum_start+csum_offset and any preceding checksums may be considered valid. If there are checksums in the packet after csum_offset it is possible they have not been verfied. This patch changes CHECKSUM_PARTIAL logic in skb_csum_unnecessary and __skb_gro_checksum_validate_needed to only considered checksums referring to csum_start and any preceding checksums (with starting offset before csum_start) to be verified. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/netdevice.h | 4 +++- include/linux/skbuff.h | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 3aa02457fe4f..9e9be221e4bf 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2246,7 +2246,9 @@ static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, bool zero_okay, __sum16 check) { - return (skb->ip_summed != CHECKSUM_PARTIAL && + return ((skb->ip_summed != CHECKSUM_PARTIAL || + skb_checksum_start_offset(skb) < + skb_gro_offset(skb)) && NAPI_GRO_CB(skb)->csum_cnt == 0 && (!zero_okay || check)); } diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1bb36edb66b9..da6028a50687 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -83,11 +83,15 @@ * * CHECKSUM_PARTIAL: * - * This is identical to the case for output below. This may occur on a packet + * A checksum is set up to be offloaded to a device as described in the + * output description for CHECKSUM_PARTIAL. This may occur on a packet * received directly from another Linux OS, e.g., a virtualized Linux kernel - * on the same host. The packet can be treated in the same way as - * CHECKSUM_UNNECESSARY, except that on output (i.e., forwarding) the - * checksum must be filled in by the OS or the hardware. + * on the same host, or it may be set in the input path in GRO or remote + * checksum offload. For the purposes of checksum verification, the checksum + * referred to by skb->csum_start + skb->csum_offset and any preceding + * checksums in the packet are considered verified. Any checksums in the + * packet that are after the checksum being offloaded are not considered to + * be verified. * * B. Checksumming on output. * @@ -2915,7 +2919,10 @@ __sum16 __skb_checksum_complete(struct sk_buff *skb); static inline int skb_csum_unnecessary(const struct sk_buff *skb) { - return ((skb->ip_summed & CHECKSUM_UNNECESSARY) || skb->csum_valid); + return ((skb->ip_summed == CHECKSUM_UNNECESSARY) || + skb->csum_valid || + (skb->ip_summed == CHECKSUM_PARTIAL && + skb_checksum_start_offset(skb) >= 0)); } /** -- cgit v1.2.3 From 6db93ea13b7937c0523ea1f977b322f1347a5633 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:29 -0800 Subject: udp: Set SKB_GSO_UDP_TUNNEL* in UDP GRO path Properly set GSO types and skb->encapsulation in the UDP tunnel GRO complete so that packets are properly represented for GSO. This sets SKB_GSO_UDP_TUNNEL or SKB_GSO_UDP_TUNNEL_CSUM depending on whether non-zero checksums were received, and sets SKB_GSO_TUNNEL_REMCSUM if the remote checksum option was processed. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/ipv4/udp_offload.c | 13 ++++++++++++- net/ipv6/udp_offload.c | 6 +++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index d10f6f4ead27..4915d8284a86 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c @@ -402,6 +402,13 @@ int udp_gro_complete(struct sk_buff *skb, int nhoff) } rcu_read_unlock(); + + if (skb->remcsum_offload) + skb_shinfo(skb)->gso_type |= SKB_GSO_TUNNEL_REMCSUM; + + skb->encapsulation = 1; + skb_set_inner_mac_header(skb, nhoff + sizeof(struct udphdr)); + return err; } @@ -410,9 +417,13 @@ static int udp4_gro_complete(struct sk_buff *skb, int nhoff) const struct iphdr *iph = ip_hdr(skb); struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); - if (uh->check) + if (uh->check) { + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; uh->check = ~udp_v4_check(skb->len - nhoff, iph->saddr, iph->daddr, 0); + } else { + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; + } return udp_gro_complete(skb, nhoff); } diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index a56276996b72..ab889bb16b3c 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c @@ -161,9 +161,13 @@ static int udp6_gro_complete(struct sk_buff *skb, int nhoff) const struct ipv6hdr *ipv6h = ipv6_hdr(skb); struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); - if (uh->check) + if (uh->check) { + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr, &ipv6h->daddr, 0); + } else { + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; + } return udp_gro_complete(skb, nhoff); } -- cgit v1.2.3 From baa32ff42871f2d4aca9c08c9403d0e497325564 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:30 -0800 Subject: net: Use more bit fields in napi_gro_cb This patch moves the free and same_flow fields to be bit fields (2 and 1 bit sized respectively). This frees up some space for u16's. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/netdevice.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9e9be221e4bf..43fd0a4dcd04 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1923,20 +1923,15 @@ struct napi_gro_cb { /* Number of segments aggregated. */ u16 count; - /* This is non-zero if the packet may be of the same flow. */ - u8 same_flow; - - /* Free the skb? */ - u8 free; -#define NAPI_GRO_FREE 1 -#define NAPI_GRO_FREE_STOLEN_HEAD 2 - /* jiffies when first packet was created/queued */ unsigned long age; /* Used in ipv6_gro_receive() and foo-over-udp */ u16 proto; + /* This is non-zero if the packet may be of the same flow. */ + u8 same_flow:1; + /* Used in udp_gro_receive */ u8 udp_mark:1; @@ -1946,9 +1941,16 @@ struct napi_gro_cb { /* Number of checksums via CHECKSUM_UNNECESSARY */ u8 csum_cnt:3; + /* Free the skb? */ + u8 free:2; +#define NAPI_GRO_FREE 1 +#define NAPI_GRO_FREE_STOLEN_HEAD 2 + /* Used in foo-over-udp, set in udp[46]_gro_receive */ u8 is_ipv6:1; + /* 7 bit hole */ + /* used to support CHECKSUM_COMPLETE for tunneling protocols */ __wsum csum; -- cgit v1.2.3 From 15e2396d4e3ce23188852b74d924107982c63b42 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:31 -0800 Subject: net: Infrastructure for CHECKSUM_PARTIAL with remote checsum offload This patch adds infrastructure so that remote checksum offload can set CHECKSUM_PARTIAL instead of calling csum_partial and writing the modfied checksum field. Add skb_remcsum_adjust_partial function to set an skb for using CHECKSUM_PARTIAL with remote checksum offload. Changed skb_remcsum_process and skb_gro_remcsum_process to take a boolean argument to indicate if checksum partial can be set or the checksum needs to be modified using the normal algorithm. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 ++-- include/linux/netdevice.h | 19 ++++++++++++++++++- include/linux/skbuff.h | 15 ++++++++++++++- net/core/dev.c | 1 + net/ipv4/fou.c | 4 ++-- 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 30310a63475a..4f04443cfd33 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -580,7 +580,7 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, } skb_gro_remcsum_process(skb, (void *)vh + hdrlen, - start, offset, grc); + start, offset, grc, true); skb->remcsum_offload = 1; @@ -1171,7 +1171,7 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, vh = (struct vxlanhdr *)(udp_hdr(skb) + 1); - skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset); + skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset, true); return vh; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 43fd0a4dcd04..5897b4ea5a3f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1923,6 +1923,9 @@ struct napi_gro_cb { /* Number of segments aggregated. */ u16 count; + /* Start offset for remote checksum offload */ + u16 gro_remcsum_start; + /* jiffies when first packet was created/queued */ unsigned long age; @@ -2244,6 +2247,12 @@ static inline void skb_gro_postpull_rcsum(struct sk_buff *skb, __sum16 __skb_gro_checksum_complete(struct sk_buff *skb); +static inline bool skb_at_gro_remcsum_start(struct sk_buff *skb) +{ + return (NAPI_GRO_CB(skb)->gro_remcsum_start - skb_headroom(skb) == + skb_gro_offset(skb)); +} + static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, bool zero_okay, __sum16 check) @@ -2251,6 +2260,7 @@ static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, return ((skb->ip_summed != CHECKSUM_PARTIAL || skb_checksum_start_offset(skb) < skb_gro_offset(skb)) && + !skb_at_gro_remcsum_start(skb) && NAPI_GRO_CB(skb)->csum_cnt == 0 && (!zero_okay || check)); } @@ -2337,12 +2347,19 @@ static inline void skb_gro_remcsum_init(struct gro_remcsum *grc) static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, int start, int offset, - struct gro_remcsum *grc) + struct gro_remcsum *grc, + bool nopartial) { __wsum delta; BUG_ON(!NAPI_GRO_CB(skb)->csum_valid); + if (!nopartial) { + NAPI_GRO_CB(skb)->gro_remcsum_start = + ((unsigned char *)ptr + start) - skb->head; + return; + } + delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset); /* Adjust skb->csum since we changed the packet */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index da6028a50687..30007afe70b3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3104,16 +3104,29 @@ do { \ compute_pseudo(skb, proto)); \ } while (0) +static inline void skb_remcsum_adjust_partial(struct sk_buff *skb, void *ptr, + u16 start, u16 offset) +{ + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = ((unsigned char *)ptr + start) - skb->head; + skb->csum_offset = offset - start; +} + /* Update skbuf and packet to reflect the remote checksum offload operation. * When called, ptr indicates the starting point for skb->csum when * ip_summed is CHECKSUM_COMPLETE. If we need create checksum complete * here, skb_postpull_rcsum is done so skb->csum start is ptr. */ static inline void skb_remcsum_process(struct sk_buff *skb, void *ptr, - int start, int offset) + int start, int offset, bool nopartial) { __wsum delta; + if (!nopartial) { + skb_remcsum_adjust_partial(skb, ptr, start, offset); + return; + } + if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) { __skb_checksum_complete(skb); skb_postpull_rcsum(skb, skb->data, ptr - (void *)skb->data); diff --git a/net/core/dev.c b/net/core/dev.c index d030575532a2..48c6ecb18f3c 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4024,6 +4024,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff NAPI_GRO_CB(skb)->flush = 0; NAPI_GRO_CB(skb)->free = 0; NAPI_GRO_CB(skb)->udp_mark = 0; + NAPI_GRO_CB(skb)->gro_remcsum_start = 0; /* Setup for GRO checksum validation */ switch (skb->ip_summed) { diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 7fa8d36e56d4..d320f575cc62 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -75,7 +75,7 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, return NULL; guehdr = (struct guehdr *)&udp_hdr(skb)[1]; - skb_remcsum_process(skb, (void *)guehdr + hdrlen, start, offset); + skb_remcsum_process(skb, (void *)guehdr + hdrlen, start, offset, true); return guehdr; } @@ -230,7 +230,7 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, } skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen, - start, offset, grc); + start, offset, grc, true); skb->remcsum_offload = 1; -- cgit v1.2.3 From 0ace2ca89cbd6bcdf2b9d2df1fa0fa24ea9d1653 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:32 -0800 Subject: vxlan: Use checksum partial with remote checksum offload Change remote checksum handling to set checksum partial as default behavior. Added an iflink parameter to configure not using checksum partial (calling csum_partial to update checksum). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 25 +++++++++++++++++++------ include/net/vxlan.h | 4 +++- include/uapi/linux/if_link.h | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 4f04443cfd33..1e0a775ea882 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -555,7 +555,8 @@ static int vxlan_fdb_append(struct vxlan_fdb *f, static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, unsigned int off, struct vxlanhdr *vh, size_t hdrlen, - u32 data, struct gro_remcsum *grc) + u32 data, struct gro_remcsum *grc, + bool nopartial) { size_t start, offset, plen; @@ -580,7 +581,7 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, } skb_gro_remcsum_process(skb, (void *)vh + hdrlen, - start, offset, grc, true); + start, offset, grc, nopartial); skb->remcsum_offload = 1; @@ -618,7 +619,9 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr), - ntohl(vh->vx_vni), &grc); + ntohl(vh->vx_vni), &grc, + !!(vs->flags & + VXLAN_F_REMCSUM_NOPARTIAL)); if (!vh) goto out; @@ -1155,7 +1158,7 @@ static void vxlan_igmp_leave(struct work_struct *work) } static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, - size_t hdrlen, u32 data) + size_t hdrlen, u32 data, bool nopartial) { size_t start, offset, plen; @@ -1171,7 +1174,8 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, vh = (struct vxlanhdr *)(udp_hdr(skb) + 1); - skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset, true); + skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset, + nopartial); return vh; } @@ -1208,7 +1212,8 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto drop; if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) { - vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni); + vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni, + !!(vs->flags & VXLAN_F_REMCSUM_NOPARTIAL)); if (!vxh) goto drop; @@ -2437,6 +2442,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 }, [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 }, [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, }, + [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG }, }; static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -2760,6 +2766,9 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, if (data[IFLA_VXLAN_GBP]) vxlan->flags |= VXLAN_F_GBP; + if (data[IFLA_VXLAN_REMCSUM_NOPARTIAL]) + vxlan->flags |= VXLAN_F_REMCSUM_NOPARTIAL; + if (vxlan_find_vni(src_net, vni, use_ipv6 ? AF_INET6 : AF_INET, vxlan->dst_port, vxlan->flags)) { pr_info("duplicate VNI %u\n", vni); @@ -2909,6 +2918,10 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_flag(skb, IFLA_VXLAN_GBP)) goto nla_put_failure; + if (vxlan->flags & VXLAN_F_REMCSUM_NOPARTIAL && + nla_put_flag(skb, IFLA_VXLAN_REMCSUM_NOPARTIAL)) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 2927d6244481..eabd3a038674 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -128,13 +128,15 @@ struct vxlan_sock { #define VXLAN_F_REMCSUM_TX 0x200 #define VXLAN_F_REMCSUM_RX 0x400 #define VXLAN_F_GBP 0x800 +#define VXLAN_F_REMCSUM_NOPARTIAL 0x1000 /* Flags that are used in the receive patch. These flags must match in * order for a socket to be shareable */ #define VXLAN_F_RCV_FLAGS (VXLAN_F_GBP | \ VXLAN_F_UDP_ZERO_CSUM6_RX | \ - VXLAN_F_REMCSUM_RX) + VXLAN_F_REMCSUM_RX | \ + VXLAN_F_REMCSUM_NOPARTIAL) struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, vxlan_rcv_t *rcv, void *data, diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 0deee3eeddbf..dfd0bb22e554 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -374,6 +374,7 @@ enum { IFLA_VXLAN_REMCSUM_TX, IFLA_VXLAN_REMCSUM_RX, IFLA_VXLAN_GBP, + IFLA_VXLAN_REMCSUM_NOPARTIAL, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) -- cgit v1.2.3 From fe881ef11cf0220f118816181930494d484c4883 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 10 Feb 2015 16:30:33 -0800 Subject: gue: Use checksum partial with remote checksum offload Change remote checksum handling to set checksum partial as default behavior. Added an iflink parameter to configure not using checksum partial (calling csum_partial to update checksum). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/uapi/linux/fou.h | 1 + net/ipv4/fou.c | 28 ++++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h index 8df06894da23..c303588bb767 100644 --- a/include/uapi/linux/fou.h +++ b/include/uapi/linux/fou.h @@ -14,6 +14,7 @@ enum { FOU_ATTR_AF, /* u8 */ FOU_ATTR_IPPROTO, /* u8 */ FOU_ATTR_TYPE, /* u8 */ + FOU_ATTR_REMCSUM_NOPARTIAL, /* flag */ __FOU_ATTR_MAX, }; diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index d320f575cc62..ff069f6597ac 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -22,14 +22,18 @@ static LIST_HEAD(fou_list); struct fou { struct socket *sock; u8 protocol; + u8 flags; u16 port; struct udp_offload udp_offloads; struct list_head list; }; +#define FOU_F_REMCSUM_NOPARTIAL BIT(0) + struct fou_cfg { u16 type; u8 protocol; + u8 flags; struct udp_port_cfg udp_config; }; @@ -64,7 +68,8 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb) } static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, - void *data, size_t hdrlen, u8 ipproto) + void *data, size_t hdrlen, u8 ipproto, + bool nopartial) { __be16 *pd = data; size_t start = ntohs(pd[0]); @@ -75,7 +80,8 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, return NULL; guehdr = (struct guehdr *)&udp_hdr(skb)[1]; - skb_remcsum_process(skb, (void *)guehdr + hdrlen, start, offset, true); + skb_remcsum_process(skb, (void *)guehdr + hdrlen, + start, offset, nopartial); return guehdr; } @@ -136,7 +142,9 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) if (flags & GUE_PFLAG_REMCSUM) { guehdr = gue_remcsum(skb, guehdr, data + doffset, - hdrlen, guehdr->proto_ctype); + hdrlen, guehdr->proto_ctype, + !!(fou->flags & + FOU_F_REMCSUM_NOPARTIAL)); if (!guehdr) goto drop; @@ -209,7 +217,7 @@ out_unlock: static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, struct guehdr *guehdr, void *data, size_t hdrlen, u8 ipproto, - struct gro_remcsum *grc) + struct gro_remcsum *grc, bool nopartial) { __be16 *pd = data; size_t start = ntohs(pd[0]); @@ -230,7 +238,7 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, } skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen, - start, offset, grc, true); + start, offset, grc, nopartial); skb->remcsum_offload = 1; @@ -250,6 +258,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, void *data; u16 doffset = 0; int flush = 1; + struct fou *fou = container_of(uoff, struct fou, udp_offloads); struct gro_remcsum grc; skb_gro_remcsum_init(&grc); @@ -294,7 +303,9 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, if (flags & GUE_PFLAG_REMCSUM) { guehdr = gue_gro_remcsum(skb, off, guehdr, data + doffset, hdrlen, - guehdr->proto_ctype, &grc); + guehdr->proto_ctype, &grc, + !!(fou->flags & + FOU_F_REMCSUM_NOPARTIAL)); if (!guehdr) goto out; @@ -455,6 +466,7 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, sk = sock->sk; + fou->flags = cfg->flags; fou->port = cfg->udp_config.local_udp_port; /* Initial for fou type */ @@ -541,6 +553,7 @@ static struct nla_policy fou_nl_policy[FOU_ATTR_MAX + 1] = { [FOU_ATTR_AF] = { .type = NLA_U8, }, [FOU_ATTR_IPPROTO] = { .type = NLA_U8, }, [FOU_ATTR_TYPE] = { .type = NLA_U8, }, + [FOU_ATTR_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG, }, }; static int parse_nl_config(struct genl_info *info, @@ -571,6 +584,9 @@ static int parse_nl_config(struct genl_info *info, if (info->attrs[FOU_ATTR_TYPE]) cfg->type = nla_get_u8(info->attrs[FOU_ATTR_TYPE]); + if (info->attrs[FOU_ATTR_REMCSUM_NOPARTIAL]) + cfg->flags |= FOU_F_REMCSUM_NOPARTIAL; + return 0; } -- cgit v1.2.3 From bc2f3873f74414cdf095b337a73f96262e6aadbc Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 11 Feb 2015 04:27:54 -0500 Subject: et131x: use msecs_to_jiffies for conversions This is only an API consolidation and should make things more readable. Converting milliseconds to jiffies by "val * HZ / 1000" is technically OK but msecs_to_jiffies(val) is the cleaner solution and handles all corner cases correctly. This is a minor API cleanup only. Signed-off-by: Nicholas Mc Guire Acked-by: Mark Einon Signed-off-by: David S. Miller --- drivers/net/ethernet/agere/et131x.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c index 384dc163851b..e0f3d197e7f2 100644 --- a/drivers/net/ethernet/agere/et131x.c +++ b/drivers/net/ethernet/agere/et131x.c @@ -3127,7 +3127,8 @@ static void et131x_error_timer_handler(unsigned long data) } /* This is a periodic timer, so reschedule */ - mod_timer(&adapter->error_timer, jiffies + TX_ERROR_PERIOD * HZ / 1000); + mod_timer(&adapter->error_timer, jiffies + + msecs_to_jiffies(TX_ERROR_PERIOD)); } static void et131x_adapter_memory_free(struct et131x_adapter *adapter) @@ -3647,7 +3648,8 @@ static int et131x_open(struct net_device *netdev) /* Start the timer to track NIC errors */ init_timer(&adapter->error_timer); - adapter->error_timer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000; + adapter->error_timer.expires = jiffies + + msecs_to_jiffies(TX_ERROR_PERIOD); adapter->error_timer.function = et131x_error_timer_handler; adapter->error_timer.data = (unsigned long)adapter; add_timer(&adapter->error_timer); -- cgit v1.2.3 From 163cff31de762a4e21df7050e392bf5f30f17e14 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 11 Feb 2015 11:25:40 +0100 Subject: drivers: net: xgene: Make xgene_enet_of_match depend on CONFIG_OF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_NET_XGENE=y but CONFIG_OF=n: drivers/net/ethernet/apm/xgene/xgene_enet_main.c:1033: warning: ‘xgene_enet_of_match’ defined but not used Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 44b15373d6b3..4de62b210c85 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1030,12 +1030,14 @@ static const struct acpi_device_id xgene_enet_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); #endif +#ifdef CONFIG_OF static struct of_device_id xgene_enet_of_match[] = { {.compatible = "apm,xgene-enet",}, {}, }; MODULE_DEVICE_TABLE(of, xgene_enet_of_match); +#endif static struct platform_driver xgene_enet_driver = { .driver = { -- cgit v1.2.3 From 1d6c4cca41840c82e6967a48137f622547244630 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 11 Feb 2015 15:59:50 +0530 Subject: drivers/net: Use setup_timer and mod_timer This patch introduces the use of functions setup_timer and mod_timer. This is done using Coccinelle and semantic patch used for this as follows: // @@ expression x,y,z,a,b; @@ -init_timer (&x); +setup_timer (&x, y, z); +mod_timer (&a, b); -x.function = y; -x.data = z; -x.expires = b; -add_timer(&a); // Signed-off-by: Vaishali Thakkar Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c589_cs.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index f18647c23559..c5a320507556 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -518,11 +518,8 @@ static int el3_open(struct net_device *dev) netif_start_queue(dev); tc589_reset(dev); - init_timer(&lp->media); - lp->media.function = media_check; - lp->media.data = (unsigned long) dev; - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); + setup_timer(&lp->media, media_check, (unsigned long)dev); + mod_timer(&lp->media, jiffies + HZ); dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); -- cgit v1.2.3 From f7d70f74811f5a522885b2962edeccb417e950c7 Mon Sep 17 00:00:00 2001 From: David L Stevens Date: Wed, 11 Feb 2015 08:20:17 -0500 Subject: sunvnet: don't change gso data on clones This patch unclones an skb for the case where the sunvnet driver needs to change the segmentation size so that it doesn't interfere with TCP SACK's use of them. Signed-off-by: David L Stevens Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ethernet/sun/sunvnet.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index 2b10b85d8a08..22e0cad1b4b5 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c @@ -1192,23 +1192,16 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb) skb_pull(skb, maclen); if (port->tso && gso_size < datalen) { + if (skb_unclone(skb, GFP_ATOMIC)) + goto out_dropped; + /* segment to TSO size */ skb_shinfo(skb)->gso_size = datalen; skb_shinfo(skb)->gso_segs = gso_segs; - - segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); - - /* restore gso_size & gso_segs */ - skb_shinfo(skb)->gso_size = gso_size; - skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len - hlen, - gso_size); - } else - segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); - if (IS_ERR(segs)) { - dev->stats.tx_dropped++; - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; } + segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO); + if (IS_ERR(segs)) + goto out_dropped; skb_push(skb, maclen); skb_reset_mac_header(skb); @@ -1246,6 +1239,10 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb) if (!(status & NETDEV_TX_MASK)) dev_kfree_skb_any(skb); return status; +out_dropped: + dev->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; } static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) -- cgit v1.2.3 From de61390cb3e03186f85997fe08a11dcb9f7a01a3 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 11 Feb 2015 16:40:38 +0200 Subject: net/mlx5_core: Fix configuration of log_uar_page_sz The current code failed to configure the page size for architectures with page size different than 4K - PPC for example. Signed-off-by: Carol L Soto Signed-off-by: Eli Cohen Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index d6651937d899..5394a8486558 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -291,6 +291,7 @@ static void copy_rw_fields(void *to, struct mlx5_caps *from) MLX5_SET(cmd_hca_cap, to, log_max_ra_req_dc, from->gen.log_max_ra_req_dc); MLX5_SET(cmd_hca_cap, to, log_max_ra_res_dc, from->gen.log_max_ra_res_dc); MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size)); + MLX5_SET(cmd_hca_cap, to, log_uar_page_sz, PAGE_SHIFT - 12); v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK; *flags_off = cpu_to_be64(v64); } -- cgit v1.2.3 From fe79fabbed056d081d6130cbd83e5b2fc42c3c52 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Wed, 11 Feb 2015 09:45:24 -0500 Subject: qlcnic: Delete existing multicast MAC list before adding new Driver keeps adding multicast addresses without deleting removed MACs and worrying about adapters filter limit. This results into actual count of programmed multicast addresses get accumulated over the time and overruns the adapter's filter limit without putting device in ACCEPT_ALL_MULTI mode. This causes newly added multicast traffic to fail after the sequence of addition - deletion in certain pattern. This issue is seen only when netdev's mcast list count is less than adapters mcast filter limit. e.g. If adapters multicast filter limit is 38 per function then following sequence would result in multicast traffic failure for newly added MACs. - add less than 38 multicast MACs - remove previously added multicast MACs - add new multicast MACs (less than 38) Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 11 ++++++- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 34 ++++++++++++++++++---- .../ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 19 +++++++----- 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index e56c1bb36141..fa4317611fd6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -848,10 +848,17 @@ struct qlcnic_cardrsp_tx_ctx { #define QLCNIC_MAC_VLAN_ADD 3 #define QLCNIC_MAC_VLAN_DEL 4 +enum qlcnic_mac_type { + QLCNIC_UNICAST_MAC, + QLCNIC_MULTICAST_MAC, + QLCNIC_BROADCAST_MAC, +}; + struct qlcnic_mac_vlan_list { struct list_head list; uint8_t mac_addr[ETH_ALEN+2]; u16 vlan_id; + enum qlcnic_mac_type mac_type; }; /* MAC Learn */ @@ -1615,7 +1622,9 @@ void qlcnic_watchdog_task(struct work_struct *work); void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter, struct qlcnic_host_rds_ring *rds_ring, u8 ring_id); void qlcnic_set_multi(struct net_device *netdev); -int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16); +void qlcnic_flush_mcast_mac(struct qlcnic_adapter *); +int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16, + enum qlcnic_mac_type); int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *); void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter); int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 69b46c051cc0..3e0f705a4311 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -487,7 +487,8 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr) return err; } -int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) +int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan, + enum qlcnic_mac_type mac_type) { struct qlcnic_mac_vlan_list *cur; struct list_head *head; @@ -513,10 +514,29 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan) } cur->vlan_id = vlan; + cur->mac_type = mac_type; + list_add_tail(&cur->list, &adapter->mac_list); return 0; } +void qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter) +{ + struct qlcnic_mac_vlan_list *cur; + struct list_head *head, *tmp; + + list_for_each_safe(head, tmp, &adapter->mac_list) { + cur = list_entry(head, struct qlcnic_mac_vlan_list, list); + if (cur->mac_type != QLCNIC_MULTICAST_MAC) + continue; + + qlcnic_sre_macaddr_change(adapter, cur->mac_addr, + cur->vlan_id, QLCNIC_MAC_DEL); + list_del(&cur->list); + kfree(cur); + } +} + static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) { struct qlcnic_adapter *adapter = netdev_priv(netdev); @@ -530,8 +550,9 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) return; - qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan); - qlcnic_nic_add_mac(adapter, bcast_addr, vlan); + qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan, + QLCNIC_UNICAST_MAC); + qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC); if (netdev->flags & IFF_PROMISC) { if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) @@ -540,8 +561,10 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) (netdev_mc_count(netdev) > ahw->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; } else if (!netdev_mc_empty(netdev)) { + qlcnic_flush_mcast_mac(adapter); netdev_for_each_mc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, vlan); + qlcnic_nic_add_mac(adapter, ha->addr, vlan, + QLCNIC_MULTICAST_MAC); } /* configure unicast MAC address, if there is not sufficient space @@ -551,7 +574,8 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) mode = VPORT_MISS_MODE_ACCEPT_ALL; } else if (!netdev_uc_empty(netdev)) { netdev_for_each_uc_addr(ha, netdev) - qlcnic_nic_add_mac(adapter, ha->addr, vlan); + qlcnic_nic_add_mac(adapter, ha->addr, vlan, + QLCNIC_UNICAST_MAC); } if (mode == VPORT_MISS_MODE_ACCEPT_ALL && diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 1659c804f1d5..e6312465fe45 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -1489,7 +1489,8 @@ out: return ret; } -static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac) +static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac, + enum qlcnic_mac_type mac_type) { struct qlcnic_adapter *adapter = netdev_priv(netdev); struct qlcnic_sriov *sriov = adapter->ahw->sriov; @@ -1500,17 +1501,18 @@ static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac) vf = &adapter->ahw->sriov->vf_info[0]; if (!qlcnic_sriov_check_any_vlan(vf)) { - qlcnic_nic_add_mac(adapter, mac, 0); + qlcnic_nic_add_mac(adapter, mac, 0, mac_type); } else { spin_lock(&vf->vlan_list_lock); for (i = 0; i < sriov->num_allowed_vlans; i++) { vlan_id = vf->sriov_vlans[i]; if (vlan_id) - qlcnic_nic_add_mac(adapter, mac, vlan_id); + qlcnic_nic_add_mac(adapter, mac, vlan_id, + mac_type); } spin_unlock(&vf->vlan_list_lock); if (qlcnic_84xx_check(adapter)) - qlcnic_nic_add_mac(adapter, mac, 0); + qlcnic_nic_add_mac(adapter, mac, 0, mac_type); } } @@ -1549,10 +1551,12 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev) (netdev_mc_count(netdev) > ahw->max_mc_count)) { mode = VPORT_MISS_MODE_ACCEPT_MULTI; } else { - qlcnic_vf_add_mc_list(netdev, bcast_addr); + qlcnic_vf_add_mc_list(netdev, bcast_addr, QLCNIC_BROADCAST_MAC); if (!netdev_mc_empty(netdev)) { + qlcnic_flush_mcast_mac(adapter); netdev_for_each_mc_addr(ha, netdev) - qlcnic_vf_add_mc_list(netdev, ha->addr); + qlcnic_vf_add_mc_list(netdev, ha->addr, + QLCNIC_MULTICAST_MAC); } } @@ -1563,7 +1567,8 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev) mode = VPORT_MISS_MODE_ACCEPT_ALL; } else if (!netdev_uc_empty(netdev)) { netdev_for_each_uc_addr(ha, netdev) - qlcnic_vf_add_mc_list(netdev, ha->addr); + qlcnic_vf_add_mc_list(netdev, ha->addr, + QLCNIC_UNICAST_MAC); } if (adapter->pdev->is_virtfn) { -- cgit v1.2.3 From 21697336d46b71dd031f29e426dda0b1e7f06cc0 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Wed, 11 Feb 2015 18:06:34 +0100 Subject: bgmac: fix device initialization on Northstar SoCs (condition typo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Northstar (Broadcom's ARM architecture) we need to manually enable all cores. Code for that is already in place, but the condition for it was wrong. Signed-off-by: Rafał Miłecki Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index ea63cb085d19..676ffe093180 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1412,6 +1412,7 @@ static void bgmac_mii_unregister(struct bgmac *bgmac) /* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */ static int bgmac_probe(struct bcma_device *core) { + struct bcma_chipinfo *ci = &core->bus->chipinfo; struct net_device *net_dev; struct bgmac *bgmac; struct ssb_sprom *sprom = &core->bus->sprom; @@ -1474,8 +1475,8 @@ static int bgmac_probe(struct bcma_device *core) bgmac_chip_reset(bgmac); /* For Northstar, we have to take all GMAC core out of reset */ - if (core->id.id == BCMA_CHIP_ID_BCM4707 || - core->id.id == BCMA_CHIP_ID_BCM53018) { + if (ci->id == BCMA_CHIP_ID_BCM4707 || + ci->id == BCMA_CHIP_ID_BCM53018) { struct bcma_device *ns_core; int ns_gmac; -- cgit v1.2.3 From d0af71a3573f1217b140c60b66f1a9b335fb058b Mon Sep 17 00:00:00 2001 From: "Jun'ichi Nomura \\(NEC\\)" Date: Thu, 12 Feb 2015 01:26:24 +0000 Subject: tg3: Hold tp->lock before calling tg3_halt() from tg3_init_one() tg3_init_one() calls tg3_halt() without tp->lock despite its assumption and causes deadlock. If lockdep is enabled, a warning like this shows up before the stall: [ BUG: bad unlock balance detected! ] 3.19.0test #3 Tainted: G E ------------------------------------- insmod/369 is trying to release lock (&(&tp->lock)->rlock) at: [] tg3_chip_reset+0x14d/0x780 [tg3] but there are no more locks to release! tg3_init_one() doesn't call tg3_halt() under normal situation but during kexec kdump I hit this problem. Fixes: 932f19de ("tg3: Release tp->lock before invoking synchronize_irq()") Signed-off-by: Jun'ichi Nomura Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 615a6dbde047..23a019cee279 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17855,8 +17855,10 @@ static int tg3_init_one(struct pci_dev *pdev, */ if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) || (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { + tg3_full_lock(tp, 0); tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + tg3_full_unlock(tp); } err = tg3_test_dma(tp); -- cgit v1.2.3 From 6aa6395ff320abe242e05766ae201f23e7978a94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 11 Feb 2015 19:51:46 -0800 Subject: ipvlan: add a missing __percpu pcpu_stats Cosmetic patch to add __percpu qualifier to pcpu_stats Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 2729f64b3e7e..924ea98bd531 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -67,7 +67,7 @@ struct ipvl_dev { struct list_head addrs; int ipv4cnt; int ipv6cnt; - struct ipvl_pcpu_stats *pcpu_stats; + struct ipvl_pcpu_stats __percpu *pcpu_stats; DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE); netdev_features_t sfeatures; u32 msg_enable; -- cgit v1.2.3 From 4762fb980465463734f02c67c67f40beb8903f73 Mon Sep 17 00:00:00 2001 From: Jan Stancek Date: Wed, 11 Feb 2015 14:06:23 +0100 Subject: ipv6: fix possible deadlock in ip6_fl_purge / ip6_fl_gc Use spin_lock_bh in ip6_fl_purge() to prevent following potentially deadlock scenario between ip6_fl_purge() and ip6_fl_gc() timer. ================================= [ INFO: inconsistent lock state ] 3.19.0 #1 Not tainted --------------------------------- inconsistent {SOFTIRQ-ON-W} -> {IN-SOFTIRQ-W} usage. swapper/5/0 [HC0[0]:SC1[1]:HE1:SE0] takes: (ip6_fl_lock){+.?...}, at: [] ip6_fl_gc+0x2d/0x180 {SOFTIRQ-ON-W} state was registered at: [] __lock_acquire+0x4a0/0x10b0 [] lock_acquire+0xc4/0x2b0 [] _raw_spin_lock+0x3d/0x80 [] ip6_flowlabel_net_exit+0x28/0x110 [] ops_exit_list.isra.1+0x39/0x60 [] cleanup_net+0x100/0x1e0 [] process_one_work+0x20a/0x830 [] worker_thread+0x11b/0x460 [] kthread+0x104/0x120 [] ret_from_fork+0x7c/0xb0 irq event stamp: 84640 hardirqs last enabled at (84640): [] _raw_spin_unlock_irq+0x30/0x50 hardirqs last disabled at (84639): [] _raw_spin_lock_irq+0x1f/0x80 softirqs last enabled at (84628): [] _local_bh_enable+0x21/0x50 softirqs last disabled at (84629): [] irq_exit+0x12d/0x150 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(ip6_fl_lock); lock(ip6_fl_lock); *** DEADLOCK *** Signed-off-by: Jan Stancek Signed-off-by: David S. Miller --- net/ipv6/ip6_flowlabel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 2f780cba6e12..f45d6db50a45 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -172,7 +172,7 @@ static void __net_exit ip6_fl_purge(struct net *net) { int i; - spin_lock(&ip6_fl_lock); + spin_lock_bh(&ip6_fl_lock); for (i = 0; i <= FL_HASH_MASK; i++) { struct ip6_flowlabel *fl; struct ip6_flowlabel __rcu **flp; @@ -190,7 +190,7 @@ static void __net_exit ip6_fl_purge(struct net *net) flp = &fl->next; } } - spin_unlock(&ip6_fl_lock); + spin_unlock_bh(&ip6_fl_lock); } static struct ip6_flowlabel *fl_intern(struct net *net, -- cgit v1.2.3 From 9672723973f1e70189b8409eb2da189a980481c5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 12 Feb 2015 15:17:27 +0100 Subject: bridge: netfilter: Move sysctl-specific error code inside #ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If CONFIG_SYSCTL=n: net/bridge/br_netfilter.c: In function ‘br_netfilter_init’: net/bridge/br_netfilter.c:996: warning: label ‘err1’ defined but not used Move the label and the code after it inside the existing #ifdef to get rid of the warning. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- net/bridge/br_netfilter.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 65728e0dc4ff..0ee453fad3de 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -987,15 +987,12 @@ static int __init br_netfilter_init(void) if (brnf_sysctl_header == NULL) { printk(KERN_WARNING "br_netfilter: can't register to sysctl.\n"); - ret = -ENOMEM; - goto err1; + nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); + return -ENOMEM; } #endif printk(KERN_NOTICE "Bridge firewalling registered\n"); return 0; -err1: - nf_unregister_hooks(br_nf_ops, ARRAY_SIZE(br_nf_ops)); - return ret; } static void __exit br_netfilter_fini(void) -- cgit v1.2.3 From ba34e6d9d346fe4e05d7e417b9edf5140772d34c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 13 Feb 2015 04:47:12 -0800 Subject: tcp: make sure skb is not shared before using skb_get() IPv6 can keep a copy of SYN message using skb_get() in tcp_v6_conn_request() so that caller wont free the skb when calling kfree_skb() later. Therefore TCP fast open has to clone the skb it is queuing in child->sk_receive_queue, as all skbs consumed from receive_queue are freed using __kfree_skb() (ie assuming skb->users == 1) Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Fixes: 5b7ed0892f2af ("tcp: move fastopen functions to tcp_fastopen.c") Signed-off-by: David S. Miller --- net/ipv4/tcp_fastopen.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 53db2c309572..ea82fd492c1b 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c @@ -134,6 +134,7 @@ static bool tcp_fastopen_create_child(struct sock *sk, struct tcp_sock *tp; struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; struct sock *child; + u32 end_seq; req->num_retrans = 0; req->num_timeout = 0; @@ -185,20 +186,35 @@ static bool tcp_fastopen_create_child(struct sock *sk, /* Queue the data carried in the SYN packet. We need to first * bump skb's refcnt because the caller will attempt to free it. + * Note that IPv6 might also have used skb_get() trick + * in tcp_v6_conn_request() to keep this SYN around (treq->pktopts) + * So we need to eventually get a clone of the packet, + * before inserting it in sk_receive_queue. * * XXX (TFO) - we honor a zero-payload TFO request for now, * (any reason not to?) but no need to queue the skb since * there is no data. How about SYN+FIN? */ - if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1) { - skb = skb_get(skb); - skb_dst_drop(skb); - __skb_pull(skb, tcp_hdr(skb)->doff * 4); - skb_set_owner_r(skb, child); - __skb_queue_tail(&child->sk_receive_queue, skb); - tp->syn_data_acked = 1; + end_seq = TCP_SKB_CB(skb)->end_seq; + if (end_seq != TCP_SKB_CB(skb)->seq + 1) { + struct sk_buff *skb2; + + if (unlikely(skb_shared(skb))) + skb2 = skb_clone(skb, GFP_ATOMIC); + else + skb2 = skb_get(skb); + + if (likely(skb2)) { + skb_dst_drop(skb2); + __skb_pull(skb2, tcp_hdrlen(skb)); + skb_set_owner_r(skb2, child); + __skb_queue_tail(&child->sk_receive_queue, skb2); + tp->syn_data_acked = 1; + } else { + end_seq = TCP_SKB_CB(skb)->seq + 1; + } } - tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = end_seq; sk->sk_data_ready(sk); bh_unlock_sock(child); sock_put(child); -- cgit v1.2.3 From 0416605548766782acee60701b5c712e9b9e1bc2 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Fri, 13 Feb 2015 14:51:02 +0100 Subject: hso: fix rx parsing logic when skb allocation fails If skb allocation fails once the IP header has been received, the rx state is being set to WAIT_SYNC. The logic, though, shouldn't directly return, as the buffer may contain a full packet, and therefore the WAIT_SYNC state needs to be processed (resetting state to WAIT_IP, clearing rx_buf_size and re-initializing rx_buf_missing). So, just let the while loop continue so that in the next iteration the WAIT_SYNC state cleanly stops the loop. The WAIT_SYNC processing will be done just after that, only if the end of packet is flagged. Signed-off-by: Aleksander Morgado Signed-off-by: David S. Miller --- drivers/net/usb/hso.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 6b8efcabb816..9cdfb3fe9c15 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -914,7 +914,7 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt, /* We got no receive buffer. */ D1("could not allocate memory"); odev->rx_parse_state = WAIT_SYNC; - return; + continue; } /* Copy what we got so far. make room for iphdr -- cgit v1.2.3 From 65bab84c79077f3acbf7dcf2aec0588226d43663 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Thu, 12 Feb 2015 16:20:46 +0800 Subject: r8152: restore hw settings There is a capability which let the hw could change the settings automatically when the power change to ON. However, the USB reset would reset the settings to the hw default, so the driver has to restore the relative settings. Otherwise, it would influence the functions of the hw, and the compatibility for the USB hub and USB host controller. The relative settings are as following. - set the power down scale to 96. - enable the power saving function of USB 2.0. - disable the ALDPS of ECM mode. - set burst mode depending on the burst size. - enable the flow control of endpoint full. - set fifo empty boundary to 32448 bytes. - enable the function of exiting LPM when Rx OK occurs. - set the connect timer to 1. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 5980ac6c48dd..438fc6bcaef1 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -40,6 +40,7 @@ #define PLA_RXFIFO_CTRL0 0xc0a0 #define PLA_RXFIFO_CTRL1 0xc0a4 #define PLA_RXFIFO_CTRL2 0xc0a8 +#define PLA_DMY_REG0 0xc0b0 #define PLA_FMC 0xc0b4 #define PLA_CFG_WOL 0xc0b6 #define PLA_TEREDO_CFG 0xc0bc @@ -90,8 +91,14 @@ #define PLA_BP_7 0xfc36 #define PLA_BP_EN 0xfc38 +#define USB_USB2PHY 0xb41e +#define USB_SSPHYLINK2 0xb428 #define USB_U2P3_CTRL 0xb460 +#define USB_CSR_DUMMY1 0xb464 +#define USB_CSR_DUMMY2 0xb466 #define USB_DEV_STAT 0xb808 +#define USB_CONNECT_TIMER 0xcbf8 +#define USB_BURST_SIZE 0xcfc0 #define USB_USB_CTRL 0xd406 #define USB_PHY_CTRL 0xd408 #define USB_TX_AGG 0xd40a @@ -170,6 +177,9 @@ #define TXFIFO_THR_NORMAL 0x00400008 #define TXFIFO_THR_NORMAL2 0x01000008 +/* PLA_DMY_REG0 */ +#define ECM_ALDPS 0x0002 + /* PLA_FMC */ #define FMC_FCR_MCU_EN 0x0001 @@ -289,6 +299,20 @@ /* PLA_BOOT_CTRL */ #define AUTOLOAD_DONE 0x0002 +/* USB_USB2PHY */ +#define USB2PHY_SUSPEND 0x0001 +#define USB2PHY_L1 0x0002 + +/* USB_SSPHYLINK2 */ +#define pwd_dn_scale_mask 0x3ffe +#define pwd_dn_scale(x) ((x) << 1) + +/* USB_CSR_DUMMY1 */ +#define DYNAMIC_BURST 0x0001 + +/* USB_CSR_DUMMY2 */ +#define EP4_FULL_FC 0x0001 + /* USB_DEV_STAT */ #define STAT_SPEED_MASK 0x0006 #define STAT_SPEED_HIGH 0x0000 @@ -334,9 +358,13 @@ #define TIMER11_EN 0x0001 /* USB_LPM_CTRL */ +/* bit 4 ~ 5: fifo empty boundary */ +#define FIFO_EMPTY_1FB 0x30 /* 0x1fb * 64 = 32448 bytes */ +/* bit 2 ~ 3: LMP timer */ #define LPM_TIMER_MASK 0x0c #define LPM_TIMER_500MS 0x04 /* 500 ms */ #define LPM_TIMER_500US 0x0c /* 500 us */ +#define ROK_EXIT_LPM 0x02 /* USB_AFE_CTRL2 */ #define SEN_VAL_MASK 0xf800 @@ -3230,6 +3258,32 @@ static void r8153_init(struct r8152 *tp) r8153_u2p3en(tp, false); + if (tp->version == RTL_VER_04) { + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2); + ocp_data &= ~pwd_dn_scale_mask; + ocp_data |= pwd_dn_scale(96); + ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY); + ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND; + ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data); + } else if (tp->version == RTL_VER_05) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0); + ocp_data &= ~ECM_ALDPS; + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); + if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) + ocp_data &= ~DYNAMIC_BURST; + else + ocp_data |= DYNAMIC_BURST; + ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); + } + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2); + ocp_data |= EP4_FULL_FC; + ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data); + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); ocp_data &= ~TIMER11_EN; ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); @@ -3238,8 +3292,7 @@ static void r8153_init(struct r8152 *tp) ocp_data &= ~LED_MODE_MASK; ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); - ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); - ocp_data &= ~LPM_TIMER_MASK; + ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM; if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER) ocp_data |= LPM_TIMER_500MS; else @@ -3251,6 +3304,8 @@ static void r8153_init(struct r8152 *tp) ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); + ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001); + r8153_power_cut_en(tp, false); r8153_u1u2en(tp, true); -- cgit v1.2.3 From 26ad0b83587fb6e9a20eef388b0587ada3da5d06 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Thu, 12 Feb 2015 09:58:48 -0800 Subject: openvswitch: Fix key serialization. Fix typo where mask is used rather than key. Fixes: 74ed7ab9264("openvswitch: Add support for unique flow IDs.") Reported-by: Joe Stringer Signed-off-by: Pravin B Shelar Acked-by: Joe Stringer Signed-off-by: David S. Miller --- net/openvswitch/flow_netlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 3829328c5a76..216f20b90aa5 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1516,7 +1516,7 @@ int ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb) /* Called with ovs_mutex or RCU read lock. */ int ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb) { - return ovs_nla_put_key(&flow->mask->key, &flow->key, + return ovs_nla_put_key(&flow->key, &flow->key, OVS_FLOW_ATTR_KEY, false, skb); } -- cgit v1.2.3 From 3b4711757d7903ab6fa88a9e7ab8901b8227da60 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Thu, 12 Feb 2015 16:14:08 -0800 Subject: ipv6: fix ipv6_cow_metrics for non DST_HOST case ipv6_cow_metrics() currently assumes only DST_HOST routes require dynamic metrics allocation from inetpeer. The assumption breaks when ndisc discovered router with RTAX_MTU and RTAX_HOPLIMIT metric. Refer to ndisc_router_discovery() in ndisc.c and note that dst_metric_set() is called after the route is created. This patch creates the metrics array (by calling dst_cow_metrics_generic) in ipv6_cow_metrics(). Test: radvd.conf: interface qemubr0 { AdvLinkMTU 1300; AdvCurHopLimit 30; prefix fd00:face:face:face::/64 { AdvOnLink on; AdvAutonomous on; AdvRouterAddr off; }; }; Before: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec fe80::/64 dev eth0 proto kernel metric 256 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec After: [root@qemu1 ~]# ip -6 r show | egrep -v unreachable fd00:face:face:face::/64 dev eth0 proto kernel metric 256 expires 27sec mtu 1300 fe80::/64 dev eth0 proto kernel metric 256 mtu 1300 default via fe80::74df:d0ff:fe23:8ef2 dev eth0 proto ra metric 1024 expires 27sec mtu 1300 hoplimit 30 Fixes: 8e2ec639173f325 (ipv6: don't use inetpeer to store metrics for routes.) Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller --- net/ipv6/route.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 98565ce0ebcd..4688bd4d7f59 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -141,7 +141,7 @@ static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) u32 *p = NULL; if (!(rt->dst.flags & DST_HOST)) - return NULL; + return dst_cow_metrics_generic(dst, old); peer = rt6_get_peer_create(rt); if (peer) { -- cgit v1.2.3 From 2b0ba96cea6066d2543066fa524120b384f3bd6b Mon Sep 17 00:00:00 2001 From: Sylvain Rochet Date: Fri, 13 Feb 2015 21:35:33 +0100 Subject: net: phy: micrel: disable NAND-tree for KSZ8021, KSZ8031, KSZ8051, KSZ8081 NAND-tree is used to check wiring between MAC and PHY using NAND gates on the PHY side, hence the name. NAND-tree initial status is latched at reset by probing the IRQ pin. However some devices are sharing the PHY IRQ pin with other peripherals such as Atmel SAMA5D[34]x-EK boards when using the optional TM7000 display module, therefore they are switching the PHY in NAND-tree test mode depending on the current IRQ line status at reset. This patch ensure PHY is not in NAND-tree test mode for all Micrel PHYs using IRQ line as a NAND-tree toggle mode at reset. Signed-off-by: Sylvain Rochet Signed-off-by: Boris Brezillon Signed-off-by: David S. Miller --- drivers/net/phy/micrel.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 3ad8ca76196d..1190fd8f0088 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -32,6 +32,7 @@ /* Operation Mode Strap Override */ #define MII_KSZPHY_OMSO 0x16 #define KSZPHY_OMSO_B_CAST_OFF BIT(9) +#define KSZPHY_OMSO_NAND_TREE_ON BIT(5) #define KSZPHY_OMSO_RMII_OVERRIDE BIT(1) #define KSZPHY_OMSO_MII_OVERRIDE BIT(0) @@ -76,6 +77,7 @@ struct kszphy_type { u32 led_mode_reg; u16 interrupt_level_mask; bool has_broadcast_disable; + bool has_nand_tree_disable; bool has_rmii_ref_clk_sel; }; @@ -89,6 +91,7 @@ struct kszphy_priv { static const struct kszphy_type ksz8021_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, .has_broadcast_disable = true, + .has_nand_tree_disable = true, .has_rmii_ref_clk_sel = true, }; @@ -98,11 +101,13 @@ static const struct kszphy_type ksz8041_type = { static const struct kszphy_type ksz8051_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, + .has_nand_tree_disable = true, }; static const struct kszphy_type ksz8081_type = { .led_mode_reg = MII_KSZPHY_CTRL_2, .has_broadcast_disable = true, + .has_nand_tree_disable = true, .has_rmii_ref_clk_sel = true, }; @@ -231,6 +236,26 @@ out: return ret; } +static int kszphy_nand_tree_disable(struct phy_device *phydev) +{ + int ret; + + ret = phy_read(phydev, MII_KSZPHY_OMSO); + if (ret < 0) + goto out; + + if (!(ret & KSZPHY_OMSO_NAND_TREE_ON)) + return 0; + + ret = phy_write(phydev, MII_KSZPHY_OMSO, + ret & ~KSZPHY_OMSO_NAND_TREE_ON); +out: + if (ret) + dev_err(&phydev->dev, "failed to disable NAND tree mode\n"); + + return ret; +} + static int kszphy_config_init(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; @@ -245,6 +270,9 @@ static int kszphy_config_init(struct phy_device *phydev) if (type->has_broadcast_disable) kszphy_broadcast_disable(phydev); + if (type->has_nand_tree_disable) + kszphy_nand_tree_disable(phydev); + if (priv->rmii_ref_clk_sel) { ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); if (ret) { -- cgit v1.2.3 From 4a26e453d99a06e3f1548569d7d405ce38878b78 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 14 Feb 2015 22:26:34 +0900 Subject: net/core: Fix warning while make xmldocs caused by dev.c This patch fix following warning wile make xmldocs. Warning(.//net/core/dev.c:5345): No description found for parameter 'bonding_info' Warning(.//net/core/dev.c:5345): Excess function parameter 'netdev_bonding_info' description in 'netdev_bonding_info_change' This warning starts to appear after following patch was added into Linus's tree during merger period. commit 61bd3857ff2c7daf756d49b41e6277bbdaa8f789 net/core: Add event for a change in slave state Signed-off-by: Masanari Iida Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 48c6ecb18f3c..8f9710c62e20 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5336,7 +5336,7 @@ EXPORT_SYMBOL(netdev_upper_dev_unlink); /** * netdev_bonding_info_change - Dispatch event about slave change * @dev: device - * @netdev_bonding_info: info to dispatch + * @bonding_info: info to dispatch * * Send NETDEV_BONDING_INFO to netdev notifiers with info. * The caller must hold the RTNL lock. -- cgit v1.2.3 From ca9f1fd263e14765a4c213e46940876ad78fce28 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 14 Feb 2015 13:47:54 -0500 Subject: net: spelling fixes Spelling errors caught by codespell. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/core/filter.c | 2 +- net/core/pktgen.c | 2 +- net/ipv4/devinet.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/core/filter.c b/net/core/filter.c index ec9baea10c16..f6bdc2b1ba01 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -531,7 +531,7 @@ do_pass: *insn = BPF_LDX_MEM(BPF_W, BPF_REG_A, BPF_REG_CTX, fp->k); break; - /* Unkown instruction. */ + /* Unknown instruction. */ default: goto err; } diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 9fa25b0ea145..b4899f5b7388 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -97,7 +97,7 @@ * New xmit() return, do_div and misc clean up by Stephen Hemminger * 040923 * - * Randy Dunlap fixed u64 printk compiler waring + * Randy Dunlap fixed u64 printk compiler warning * * Remove FCS from BW calculation. Lennert Buytenhek * New time handling. Lennert Buytenhek 041213 diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index f0b4a31d7bd6..3a8985c94581 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1186,7 +1186,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) no_in_dev: /* Not loopback addresses on loopback should be preferred - in this case. It is importnat that lo is the first interface + in this case. It is important that lo is the first interface in dev_base list. */ for_each_netdev_rcu(net, dev) { -- cgit v1.2.3 From 0960b6417e9ed8e4b4aa3c54e257324a9352f40b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sun, 15 Feb 2015 16:35:17 +0800 Subject: vhost_net: fix wrong iter offset when setting number of buffers In commit ba7438aed924 ("vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()"), we advance iov iter fixup sizeof(struct virtio_net_hdr) bytes and fill the number of buffers after doing the socket recvmsg(). This work well but was broken after commit 6e03f896b52c ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net") which tries to advance sizeof(struct virtio_net_hdr_mrg_rxbuf). It will fill the number of buffers at the wrong place. This patch fixes this. Fixes 6e03f896b52c ("Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net") Cc: David S. Miller Cc: Al Viro Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/vhost/net.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 8dccca9013ed..afa06d28725d 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -528,9 +528,9 @@ static void handle_rx(struct vhost_net *net) .msg_controllen = 0, .msg_flags = MSG_DONTWAIT, }; - struct virtio_net_hdr_mrg_rxbuf hdr = { - .hdr.flags = 0, - .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE + struct virtio_net_hdr hdr = { + .flags = 0, + .gso_type = VIRTIO_NET_HDR_GSO_NONE }; size_t total_len = 0; int err, mergeable; @@ -539,6 +539,7 @@ static void handle_rx(struct vhost_net *net) size_t vhost_len, sock_len; struct socket *sock; struct iov_iter fixup; + __virtio16 num_buffers; mutex_lock(&vq->mutex); sock = vq->private_data; @@ -616,9 +617,9 @@ static void handle_rx(struct vhost_net *net) } /* TODO: Should check and handle checksum. */ - hdr.num_buffers = cpu_to_vhost16(vq, headcount); + num_buffers = cpu_to_vhost16(vq, headcount); if (likely(mergeable) && - copy_to_iter(&hdr.num_buffers, 2, &fixup) != 2) { + copy_to_iter(&num_buffers, 2, &fixup) != 2) { vq_err(vq, "Failed num_buffers write"); vhost_discard_vq_desc(vq, headcount); break; -- cgit v1.2.3 From d95e2fe0ffa3b4325ddd11095f46d0c0b96450f5 Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Fri, 13 Feb 2015 13:03:50 +0100 Subject: com20020-pci: add support for eae single card Signed-off-by: Michael Grzeschik Signed-off-by: David S. Miller --- drivers/net/arcnet/com20020-pci.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 945f532078e9..96edc1346124 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -214,8 +214,17 @@ static struct com20020_pci_card_info card_info_sohard = { .flags = ARC_CAN_10MBIT, }; -static struct com20020_pci_card_info card_info_eae = { - .name = "EAE PLX-PCI", +static struct com20020_pci_card_info card_info_eae_arc1 = { + .name = "EAE PLX-PCI ARC1", + .devcount = 1, + .chan_map_tbl = { + { 2, 0x00, 0x08 }, + }, + .flags = ARC_CAN_10MBIT, +}; + +static struct com20020_pci_card_info card_info_eae_ma1 = { + .name = "EAE PLX-PCI MA1", .devcount = 2, .chan_map_tbl = { { 2, 0x00, 0x08 }, @@ -357,11 +366,17 @@ static const struct pci_device_id com20020pci_id_table[] = { 0, 0, (kernel_ulong_t)&card_info_sohard }, + { + 0x10B5, 0x9050, + 0x10B5, 0x3263, + 0, 0, + (kernel_ulong_t)&card_info_eae_arc1 + }, { 0x10B5, 0x9050, 0x10B5, 0x3292, 0, 0, - (kernel_ulong_t)&card_info_eae + (kernel_ulong_t)&card_info_eae_ma1 }, { 0x14BA, 0x6000, -- cgit v1.2.3 From 7afb8886a05be68e376655539a064ec672de8a8e Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Fri, 13 Feb 2015 13:56:53 -0800 Subject: rtnetlink: call ->dellink on failure when ->newlink exists Ignacy reported that when eth0 is down and add a vlan device on top of it like: ip link add link eth0 name eth0.1 up type vlan id 1 We will get a refcount leak: unregister_netdevice: waiting for eth0.1 to become free. Usage count = 2 The problem is when rtnl_configure_link() fails in rtnl_newlink(), we simply call unregister_device(), but for stacked device like vlan, we almost do nothing when we unregister the upper device, more work is done when we unregister the lower device, so call its ->dellink(). Reported-by: Ignacy Gawedzki Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5be499b6a2d2..ab293a3066b3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -2162,7 +2162,14 @@ replay: } err = rtnl_configure_link(dev, ifm); if (err < 0) { - unregister_netdevice(dev); + if (ops->newlink) { + LIST_HEAD(list_kill); + + ops->dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + } else { + unregister_netdevice(dev); + } goto out; } -- cgit v1.2.3 From 19334920eaf7df3f69950b040ede6c7598425a5b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 16 Feb 2015 21:23:51 -0800 Subject: net: dsa: Set valid phy interface type If the phy interface mode is not found in devicetree, or if devicetree is not configured, of_get_phy_mode returns -ENODEV. The current code sets the phy interface mode to the return value from of_get_phy_mode without checking if it is valid. This invalid phy interface mode is passed as parameter to of_phy_connect or to phy_connect_direct. This sets the phy interface mode to the invalid value, which in turn causes problems for any code using phydev->interface. Fixes: b31f65fb4383 ("net: dsa: slave: Fix autoneg for phys on switch MDIO bus") Fixes: 0d8bcdd383b8 ("net: dsa: allow for more complex PHY setups") Cc: Florian Fainelli Cc: Andrew Lunn Signed-off-by: Guenter Roeck Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/slave.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/dsa/slave.c b/net/dsa/slave.c index d104ae15836f..f23deadf42a0 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -521,10 +521,13 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p, struct device_node *phy_dn, *port_dn; bool phy_is_fixed = false; u32 phy_flags = 0; - int ret; + int mode, ret; port_dn = cd->port_dn[p->port]; - p->phy_interface = of_get_phy_mode(port_dn); + mode = of_get_phy_mode(port_dn); + if (mode < 0) + mode = PHY_INTERFACE_MODE_NA; + p->phy_interface = mode; phy_dn = of_parse_phandle(port_dn, "phy-handle", 0); if (of_phy_is_fixed_link(port_dn)) { @@ -559,6 +562,8 @@ static int dsa_slave_phy_setup(struct dsa_slave_priv *p, if (!p->phy) return -ENODEV; + /* Use already configured phy mode */ + p->phy_interface = p->phy->interface; phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link, p->phy_interface); } else { -- cgit v1.2.3