* [net-next v2 00/12][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2013-01-18 15:04 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
This series contains updates to e1000e and igb. Most notably is the
added timestamp support in e1000e and additional software timestamp
support in igb. As well as, the added thermal data support and SR-IOV
configuration support in igb.
v2- dropped the following patches from the previous 14 patch series
because changes were requested from the community:
e1000e: add support for IEEE-1588 PTP
igb: Report L4 Rx hash via skb->l4_rxhash
The following are changes since commit 887c95cc1da53f66a5890fdeab13414613010097:
ipv6: Complete neighbour entry removal from dst_entry.
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master
Bjorn Helgaas (1):
e1000e: Use standard #defines for PCIe Capability ASPM fields
Bruce Allan (2):
e1000e: add ethtool .get_eee/.set_eee
e1000e: add support for hardware timestamping on some devices
Carolyn Wyborny (3):
igb: Add i2c interface to igb.
igb: Add support functions to access thermal data.
igb: Enable hwmon data output for thermal sensors via I2C.
Greg Rose (1):
igb: Enable SR-IOV configuration via PCI sysfs interface
Matthew Vick (5):
igb: Add support for SW timestamping
igb: Add timeout for PTP Tx work item
igb: Add mechanism for detecting latched hardware Rx timestamp
igb: Free any held skb that should have been timestamped on remove
igb: Use in-kernel PTP_EV_PORT #define
drivers/net/ethernet/intel/Kconfig | 13 +
drivers/net/ethernet/intel/e1000e/82571.c | 2 +
drivers/net/ethernet/intel/e1000e/defines.h | 44 ++
drivers/net/ethernet/intel/e1000e/e1000.h | 47 +-
drivers/net/ethernet/intel/e1000e/ethtool.c | 159 ++++++-
drivers/net/ethernet/intel/e1000e/hw.h | 11 +
drivers/net/ethernet/intel/e1000e/ich8lan.c | 26 +-
drivers/net/ethernet/intel/e1000e/netdev.c | 382 ++++++++++++++-
drivers/net/ethernet/intel/igb/Makefile | 2 +-
drivers/net/ethernet/intel/igb/e1000_82575.c | 140 ++++++
drivers/net/ethernet/intel/igb/e1000_82575.h | 17 +-
drivers/net/ethernet/intel/igb/e1000_defines.h | 13 +
drivers/net/ethernet/intel/igb/e1000_hw.h | 20 +
drivers/net/ethernet/intel/igb/e1000_regs.h | 16 +
drivers/net/ethernet/intel/igb/igb.h | 46 +-
drivers/net/ethernet/intel/igb/igb_ethtool.c | 11 +
drivers/net/ethernet/intel/igb/igb_hwmon.c | 242 ++++++++++
drivers/net/ethernet/intel/igb/igb_main.c | 632 +++++++++++++++++++++----
drivers/net/ethernet/intel/igb/igb_ptp.c | 65 ++-
19 files changed, 1747 insertions(+), 141 deletions(-)
create mode 100644 drivers/net/ethernet/intel/igb/igb_hwmon.c
--
1.7.11.7
^ permalink raw reply
* [net-next 02/12] e1000e: Use standard #defines for PCIe Capability ASPM fields
From: Jeff Kirsher @ 2013-01-18 15:04 UTC (permalink / raw)
To: davem; +Cc: e1000-devel, netdev, gospo, Bjorn Helgaas, sassmann
In-Reply-To: <1358521487-28610-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Bjorn Helgaas <bhelgaas@google.com>
Use the standard #defines for PCIe Capability ASPM fields.
Previously we used PCIE_LINK_STATE_L0S and PCIE_LINK_STATE_L1 directly, but
these are defined for the Linux ASPM interfaces, e.g.,
pci_disable_link_state(), and only coincidentally match the actual register
bits. PCIE_LINK_STATE_CLKPM, also part of that interface, does not match
the register bit.
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: e1000-devel@lists.sourceforge.net
Acked-by: Bruce Allan <bruce.w.allan@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/netdev.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 05538e6..bf2c84cf 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -5548,14 +5548,21 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
#else
static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
{
+ u16 aspm_ctl = 0;
+
+ if (state & PCIE_LINK_STATE_L0S)
+ aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L0S;
+ if (state & PCIE_LINK_STATE_L1)
+ aspm_ctl |= PCI_EXP_LNKCTL_ASPM_L1;
+
/* Both device and parent should have the same ASPM setting.
* Disable ASPM in downstream component first and then upstream.
*/
- pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, state);
+ pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_ctl);
if (pdev->bus->self)
pcie_capability_clear_word(pdev->bus->self, PCI_EXP_LNKCTL,
- state);
+ aspm_ctl);
}
#endif
static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
--
1.7.11.7
------------------------------------------------------------------------------
Master HTML5, CSS3, ASP.NET, MVC, AJAX, Knockout.js, Web API and
much more. Get web development skills now with LearnDevNow -
350+ hours of step-by-step video tutorials by Microsoft MVPs and experts.
SALE $99.99 this month only -- learn more at:
http://p.sf.net/sfu/learnmore_122812
_______________________________________________
E1000-devel mailing list
E1000-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/e1000-devel
To learn more about Intel® Ethernet, visit http://communities.intel.com/community/wired
^ permalink raw reply related
* Re: Redefinition of struct in6_addr in <netinet/in.h> and <linux/in6.h>
From: Carlos O'Donell @ 2013-01-18 14:54 UTC (permalink / raw)
To: Pedro Alves
Cc: YOSHIFUJI Hideaki, Mike Frysinger, David Miller, libc-alpha,
bhutchings, amwang, tmb, eblake, netdev, linux-kernel,
libvirt-list, tgraf, schwab
In-Reply-To: <50F95DF3.7080602@redhat.com>
On Fri, Jan 18, 2013 at 9:36 AM, Pedro Alves <palves@redhat.com> wrote:
> On 01/18/2013 02:24 PM, YOSHIFUJI Hideaki wrote:
>
>>>>> It's simple enough to move all of the __GLIBC__ uses into libc-compat.h,
>>>>> then you control userspace libc coordination from one file.
>>>>
>>>> How about just deciding on a single macro/symbol both the
>>>> kernel and libc (any libc that needs this) define? Something
>>>> like both the kernel and userland doing:
>>>>
>>>> #ifndef __IPV6_BITS_DEFINED
>>>> #define __IPV6_BITS_DEFINED
>>>> ...
>>>> define in6_addr, sockaddr_in6, ipv6_mreq, whatnot
>>>> #endif
>>
>> Hmm, how should we handle future structs/enums then?
>> For example, if I want to have in6_flowlabel_req{} defined in
>> glibc, what should we do?
>
> Include the glibc header first? Or is this some other
> use case?
>
> The point wasn't that you'd have only one macro for all
> structs/enums (you could split into __IPV6_IN6_ADDR_DEFINED,
> __IPV6_SOCKADDR_IN6_DEFINED, etc.) but to have the kernel
> and libc agree on guard macros, instead of having the kernel
> do #ifdef __GLIBC__ and glibc doing #ifdef _NETINET_IN_H.
>
> But as Carlos says, the devil is in the details, and
> I sure am not qualified on the details here.
My plan is to have one _UAPI_DEF_xxx macro to guard each
problematic definition in the kernel UAPI headers.
Then userspace can check for those macros and act appropriately.
The kernel likewise when detecting glibc headers included first
can use the _UAPI_DEF_xxx macro guards to disable problematic
definitions knowing that glibc has identical ABI and API-compatible
versions that the program can use without breaking.
Cheers,
Carlos.
^ permalink raw reply
* Re: [PATCH net] ipv6: Fix addrconf_dst_alloc() failure check.
From: YOSHIFUJI Hideaki @ 2013-01-18 14:38 UTC (permalink / raw)
To: Eric Dumazet, David Miller; +Cc: netdev, YOSHIFUJI Hideaki
In-Reply-To: <1358519314.11051.111.camel@edumazet-glaptop>
Eric Dumazet wrote:
> On Fri, 2013-01-18 at 20:56 +0900, YOSHIFUJI Hideaki wrote:
>> The function returns NULL on error and it never return error code
>> embedded in pointer.
>>
>
> Which functions returns NULL ?
>
> addrconf_dst_alloc() returns ERR_PTR(-ENOMEM) in case of error in my net
> tree.
>
> Also, please consider adding the bug origin in your changelogs.
Oh, right. I probably looked into different dst_alloc variants
and was confused. Please ignore.
--yoshfuji
^ permalink raw reply
* Re: Redefinition of struct in6_addr in <netinet/in.h> and <linux/in6.h>
From: Pedro Alves @ 2013-01-18 14:36 UTC (permalink / raw)
To: YOSHIFUJI Hideaki
Cc: Carlos O'Donell, Mike Frysinger, David Miller, libc-alpha,
bhutchings, amwang, tmb, eblake, netdev, linux-kernel,
libvirt-list, tgraf, schwab
In-Reply-To: <50F95B0A.1090205@linux-ipv6.org>
On 01/18/2013 02:24 PM, YOSHIFUJI Hideaki wrote:
>>>> It's simple enough to move all of the __GLIBC__ uses into libc-compat.h,
>>>> then you control userspace libc coordination from one file.
>>>
>>> How about just deciding on a single macro/symbol both the
>>> kernel and libc (any libc that needs this) define? Something
>>> like both the kernel and userland doing:
>>>
>>> #ifndef __IPV6_BITS_DEFINED
>>> #define __IPV6_BITS_DEFINED
>>> ...
>>> define in6_addr, sockaddr_in6, ipv6_mreq, whatnot
>>> #endif
>
> Hmm, how should we handle future structs/enums then?
> For example, if I want to have in6_flowlabel_req{} defined in
> glibc, what should we do?
Include the glibc header first? Or is this some other
use case?
The point wasn't that you'd have only one macro for all
structs/enums (you could split into __IPV6_IN6_ADDR_DEFINED,
__IPV6_SOCKADDR_IN6_DEFINED, etc.) but to have the kernel
and libc agree on guard macros, instead of having the kernel
do #ifdef __GLIBC__ and glibc doing #ifdef _NETINET_IN_H.
But as Carlos says, the devil is in the details, and
I sure am not qualified on the details here.
--
Pedro Alves
^ permalink raw reply
* Re: [PATCH net] ipv6: Fix addrconf_dst_alloc() failure check.
From: Eric Dumazet @ 2013-01-18 14:28 UTC (permalink / raw)
To: YOSHIFUJI Hideaki; +Cc: David Miller, netdev
In-Reply-To: <50F93879.6010201@linux-ipv6.org>
On Fri, 2013-01-18 at 20:56 +0900, YOSHIFUJI Hideaki wrote:
> The function returns NULL on error and it never return error code
> embedded in pointer.
>
Which functions returns NULL ?
addrconf_dst_alloc() returns ERR_PTR(-ENOMEM) in case of error in my net
tree.
Also, please consider adding the bug origin in your changelogs.
Thanks !
> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> ---
> net/ipv6/addrconf.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 420e563..d0a2df2b 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -783,8 +783,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
> }
>
> rt = addrconf_dst_alloc(idev, addr, false);
> - if (IS_ERR(rt)) {
> - err = PTR_ERR(rt);
> + if (!rt) {
> + err = -ENOMEM;
> goto out;
> }
>
^ permalink raw reply
* Re: [RFC PATCH v4] cgroup: net_cls: traffic counter based on classification control cgroup
From: Eric Dumazet @ 2013-01-18 14:27 UTC (permalink / raw)
To: Alexey Perevalov
Cc: cgroups-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20130118135944.GA15062@aperevalov>
On Fri, 2013-01-18 at 17:59 +0400, Alexey Perevalov wrote:
> Traffic counter based on classification control group
>
> The main goal of this patch it's counting traffic for process placed to
> net_cls cgroup (ingress and egress).
> It's based on atomic and holds counter per network interfaces.
>
> It handles packets in net/core/dev.c for egress and in
> /net/ipv4/tcp.c|udp.c for ingress.
>
> Cgroup fs interface provides following files additional to existing
> net_cls files:
> net_cls.ifacename.usage_in_bytes
> Containing rcv/snd lines.
>
> Signed-off-by: Alexey Perevalov <a.perevalov-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
...
> index d1e8116..ffc9ec2 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -135,6 +135,7 @@
> #include <linux/net_tstamp.h>
> #include <linux/static_key.h>
> #include <net/flow_keys.h>
> +#include <net/cls_cgroup.h>
>
> #include "net-sysfs.h"
>
> @@ -2922,6 +2923,11 @@ int dev_queue_xmit(struct sk_buff *skb)
> */
> rcu_read_lock_bh();
>
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + if (dev)
How dev could be NULL here ?
> + count_cls_snd(skb_cls_classid(skb), skb->len, dev->name);
> +#endif
Why do you add these ugly ifdefs in the C files ?
As already said, you should not add new ifdef in C files, but properly
define empty functions in the header files
#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
...
#else
static inline void count_cls_snd( args ) { }
#endif
> +
> skb_update_prio(skb);
>
> txq = netdev_pick_tx(dev, skb);
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 1ca2536..dc4dc3a 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -276,6 +276,7 @@
> #include <net/ip.h>
> #include <net/netdma.h>
> #include <net/sock.h>
> +#include <net/cls_cgroup.h>
>
> #include <asm/uaccess.h>
> #include <asm/ioctls.h>
> @@ -1464,6 +1465,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
> u32 seq = tp->copied_seq;
> u32 offset;
> int copied = 0;
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + int ifindex = 0;
> +#endif
>
> if (sk->sk_state == TCP_LISTEN)
> return -ENOTCONN;
> @@ -1510,6 +1514,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
> ++seq;
> break;
> }
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + ifindex = get_ifindex_from_skb(skb);
> +#endif
> sk_eat_skb(sk, skb, false);
> if (!desc->count)
> break;
> @@ -1520,8 +1527,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
> tcp_rcv_space_adjust(sk);
>
> /* Clean up data we have read: This will do ACK frames. */
> - if (copied > 0)
> + if (copied > 0) {
> tcp_cleanup_rbuf(sk, copied);
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + count_cls_rcv(current, copied, ifindex);
> +#endif
> + }
> return copied;
> }
> EXPORT_SYMBOL(tcp_read_sock);
> @@ -1549,6 +1560,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
> bool copied_early = false;
> struct sk_buff *skb;
> u32 urg_hole = 0;
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + int ifindex = 0;
> +#endif
>
> lock_sock(sk);
>
> @@ -1873,6 +1887,9 @@ skip_copy:
> if (tcp_hdr(skb)->fin)
> goto found_fin_ok;
> if (!(flags & MSG_PEEK)) {
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + ifindex = get_ifindex_from_skb(skb);
> +#endif
> sk_eat_skb(sk, skb, copied_early);
> copied_early = false;
> }
> @@ -1882,6 +1899,9 @@ skip_copy:
> /* Process the FIN. */
> ++*seq;
> if (!(flags & MSG_PEEK)) {
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + ifindex = get_ifindex_from_skb(skb);
> +#endif
> sk_eat_skb(sk, skb, copied_early);
> copied_early = false;
> }
> @@ -1924,6 +1944,11 @@ skip_copy:
> /* Clean up data we have read: This will do ACK frames. */
> tcp_cleanup_rbuf(sk, copied);
>
> +#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
> + if (copied > 0)
> + count_cls_rcv(current, copied, ifindex);
> +#endif
> +
> release_sock(sk);
> return copied;
>
There is no need to add so much ugly code in tcp at least
For input packets, as soon as we identify a matching socket in IP/TCP
early demux, we are done. It permits to properly account packets, even
the retransmits and ACKS, and even packets dropped by netfilter or
sk_filter.
^ permalink raw reply
* [PATCH net] net: qmi_wwan: add ONDA MT8205 4G LTE
From: Bjørn Mork @ 2013-01-18 14:26 UTC (permalink / raw)
To: netdev; +Cc: linux-usb, Bjørn Mork
The driver description files gives these names to the vendor specific
functions on this modem:
Diag VID_19D2&PID_0265&MI_00
NMEA VID_19D2&PID_0265&MI_01
AT cmd VID_19D2&PID_0265&MI_02
Modem VID_19D2&PID_0265&MI_03
Net VID_19D2&PID_0265&MI_04
Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
drivers/net/usb/qmi_wwan.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index c434108..575a583 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -433,6 +433,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x19d2, 0x0199, 1)}, /* ZTE MF820S */
{QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
{QMI_FIXED_INTF(0x19d2, 0x0257, 3)}, /* ZTE MF821 */
+ {QMI_FIXED_INTF(0x19d2, 0x0265, 4)}, /* ONDA MT8205 4G LTE */
{QMI_FIXED_INTF(0x19d2, 0x0284, 4)}, /* ZTE MF880 */
{QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */
{QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */
--
1.7.10.4
^ permalink raw reply related
* [PATCH net] net: cdc_ncm: workaround for missing CDC Union
From: Bjørn Mork @ 2013-01-18 14:25 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: linux-usb-u79uwXL29TY76Z2rM5mHXA, Bjørn Mork, Greg Suarez,
Alexey Orishko
Adding support for the MBIM mode in some Sierra Wireless devices.
Some Sierra Wireless firmwares support CDC MBIM but have no CDC
Union funtional descriptor. This violates the MBIM specification,
but we can easily work around the bug by looking at the Interface
Association Descriptor instead. This is most likely what
Windows uses too, which explains how the firmware bug has gone
unnoticed until now.
This change will not affect any currently supported device
conforming to the NCM or MBIM specifications, as they must have
the CDC Union descriptor.
Cc: Greg Suarez <gsuarez-AKjrjAf1O7qe8kRwQpwjMg@public.gmane.org>
Cc: Alexey Orishko <alexey.orishko-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
Signed-off-by: Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
---
drivers/net/usb/cdc_ncm.c | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 71b6e92..5c1210f 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -344,6 +344,21 @@ static const struct ethtool_ops cdc_ncm_ethtool_ops = {
.nway_reset = usbnet_nway_reset,
};
+/* return first slave interface if an IAD matches the given master */
+static struct usb_interface *get_iad_slave(struct usb_device *udev,
+ struct usb_interface *master) {
+ int i;
+ struct usb_interface_assoc_descriptor *iad;
+ u8 mnum = master->cur_altsetting->desc.bInterfaceNumber;
+
+ for (i = 0; i < USB_MAXIADS; i++) {
+ iad = udev->actconfig->intf_assoc[i];
+ if (iad->bFirstInterface == mnum && iad->bInterfaceCount == 2)
+ return usb_ifnum_to_if(udev, mnum + 1);
+ }
+ return NULL;
+}
+
int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
{
struct cdc_ncm_ctx *ctx;
@@ -435,6 +450,16 @@ advance:
len -= temp;
}
+ /* some buggy devices have an IAD but no CDC Union */
+ if (!ctx->union_desc) {
+ dev_dbg(&intf->dev, "missing CDC Union descriptor\n");
+ ctx->data = get_iad_slave(dev->udev, intf);
+ if (ctx->data) {
+ ctx->control = intf;
+ dev_dbg(&intf->dev, "got slave from IAD\n");
+ }
+ }
+
/* check if we got everything */
if ((ctx->control == NULL) || (ctx->data == NULL) ||
((!ctx->mbim_desc) && ((ctx->ether_desc == NULL) || (ctx->control != intf))))
--
1.7.10.4
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: Redefinition of struct in6_addr in <netinet/in.h> and <linux/in6.h>
From: YOSHIFUJI Hideaki @ 2013-01-18 14:24 UTC (permalink / raw)
To: Carlos O'Donell
Cc: Pedro Alves, Mike Frysinger, David Miller, libc-alpha, bhutchings,
amwang, tmb, eblake, netdev, linux-kernel, libvirt-list, tgraf,
schwab, YOSHIFUJI Hideaki
In-Reply-To: <50F94FA6.6070005@systemhalted.org>
Carlos O'Donell wrote:
> On 01/18/2013 05:44 AM, Pedro Alves wrote:
>> On 01/18/2013 04:22 AM, Carlos O'Donell wrote:
>>> On Thu, Jan 17, 2013 at 11:20 PM, Mike Frysinger <vapier@gentoo.org> wrote:
>>>> On Wednesday 16 January 2013 22:15:38 David Miller wrote:
>>>>> From: Carlos O'Donell <carlos@systemhalted.org>
>>>>> Date: Wed, 16 Jan 2013 21:15:03 -0500
>>>>>
>>>>>> +/* If a glibc-based userspace has already included in.h, then we will
>>>>>> not + * define in6_addr (nor the defines), sockaddr_in6, or ipv6_mreq.
>>>>>> The + * ABI used by the kernel and by glibc match exactly. Neither the
>>>>>> kernel + * nor glibc should break this ABI without coordination.
>>>>>> + */
>>>>>> +#ifndef _NETINET_IN_H
>>>>>> +
>>>>>
>>>>> I think we should shoot for a non-glibc-centric solution.
>>>>>
>>>>> I can't imagine that other libc's won't have the same exact problem
>>>>> with their netinet/in.h conflicting with the kernel's, redefining
>>>>> structures like in6_addr, that we'd want to provide a protection
>>>>> scheme for here as well.
>>>>
>>>> yes, the kernel's use of __GLIBC__ in exported headers has already caused
>>>> problems in the past. fortunately, it's been reduced down to just one case
>>>> now (stat.h). let's not balloon it back up.
>>>> -mike
>>>
>>> I also see coda.h has grown a __GLIBC__ usage.
>>>
>>> In the next revision of the patch I created a single libc-compat.h header
>>> which encompasses the logic for any libc that wants to coordinate with
>>> the kernel headers.
>>
>>
>>> It's simple enough to move all of the __GLIBC__ uses into libc-compat.h,
>>> then you control userspace libc coordination from one file.
>>
>> How about just deciding on a single macro/symbol both the
>> kernel and libc (any libc that needs this) define? Something
>> like both the kernel and userland doing:
>>
>> #ifndef __IPV6_BITS_DEFINED
>> #define __IPV6_BITS_DEFINED
>> ...
>> define in6_addr, sockaddr_in6, ipv6_mreq, whatnot
>> #endif
Hmm, how should we handle future structs/enums then?
For example, if I want to have in6_flowlabel_req{} defined in
glibc, what should we do?
We probably want to have __LIBC_HAS_STRUCT_IN6_FLOWLABEL_REQ
defined.
--yoshfuji
^ permalink raw reply
* [RFC PATCH v4] cgroup: net_cls: traffic counter based on classification control cgroup
From: Alexey Perevalov @ 2013-01-18 13:59 UTC (permalink / raw)
To: cgroups-u79uwXL29TY76Z2rM5mHXA; +Cc: netdev-u79uwXL29TY76Z2rM5mHXA
Traffic counter based on classification control group
The main goal of this patch it's counting traffic for process placed to
net_cls cgroup (ingress and egress).
It's based on atomic and holds counter per network interfaces.
It handles packets in net/core/dev.c for egress and in
/net/ipv4/tcp.c|udp.c for ingress.
Cgroup fs interface provides following files additional to existing
net_cls files:
net_cls.ifacename.usage_in_bytes
Containing rcv/snd lines.
Signed-off-by: Alexey Perevalov <a.perevalov-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
---
Documentation/cgroups/net_cls.txt | 20 ++++
include/net/cls_cgroup.h | 200 +++++++++++++++++++++++++++++++++----
include/net/cls_counter_holder.h | 26 +++++
init/Kconfig | 25 +++++
kernel/cgroup.c | 2 +
kernel/res_counter.c | 4 +
net/core/dev.c | 6 ++
net/ipv4/tcp.c | 27 ++++-
net/ipv4/udp.c | 6 ++
net/sched/Kconfig | 11 --
net/sched/Makefile | 1 +
net/sched/cls_cgroup.c | 194 ++++++++++++++++++++++++++++++++++-
net/sched/cls_counter_holder.c | 144 ++++++++++++++++++++++++++
13 files changed, 631 insertions(+), 35 deletions(-)
create mode 100644 Documentation/cgroups/net_cls.txt
create mode 100644 include/net/cls_counter_holder.h
create mode 100644 net/sched/cls_counter_holder.c
diff --git a/Documentation/cgroups/net_cls.txt b/Documentation/cgroups/net_cls.txt
new file mode 100644
index 0000000..131fbf1
--- /dev/null
+++ b/Documentation/cgroups/net_cls.txt
@@ -0,0 +1,20 @@
+Network packet classification cgroup
+--------------------------------------
+
+The net_cls cgroup is attended to mark engress network packets with special
+identifier (classid). The main purpose of marking packets with classid is
+using it in linux QoS mechanism. It is needed to tweak TC rules for cgroup
+related processes.
+
+Cgroup net_cls marks engress packets in sk_alloc.
+
+Also this cgroup provides ability to count network traffic per network
+interface and provides it in according files.
+
+File system representation of cgroup consists of the standart for cgroupfs
+files like tasks, cgroup.procs, cgroup.clone_children, cgroup.event_control.
+
+Net_cls cgroup introduces they own net_cls.classid.
+Counting part contains counter file with the following names:
+net_cls.iface_name.usage_in_bytes
+consists of 2 lines with rcv and snd.
diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h
index 2581638..e3bfe6f 100644
--- a/include/net/cls_cgroup.h
+++ b/include/net/cls_cgroup.h
@@ -13,54 +13,197 @@
#ifndef _NET_CLS_CGROUP_H
#define _NET_CLS_CGROUP_H
+#include <linux/atomic.h>
#include <linux/cgroup.h>
#include <linux/hardirq.h>
#include <linux/rcupdate.h>
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+#include <linux/nsproxy.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/cls_counter_holder.h>
+#include <net/sock.h>
+
+/*TODO hide all it to separate file*/
+
+struct cls_iface_cntrs {
+ char *dev_name;
+ atomic64_t snd_counter;
+ atomic64_t rcv_counter;
+ struct list_head link;
+};
+
+#endif /*CONFIG_NET_CLS_COUNTER*/
+
+
#if IS_ENABLED(CONFIG_NET_CLS_CGROUP)
struct cgroup_cls_state
{
struct cgroup_subsys_state css;
u32 classid;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ struct cls_iface_cntrs iface_stats;
+#endif /*CONFIG_NET_CLS_COUNTER*/
};
extern void sock_update_classid(struct sock *sk, struct task_struct *task);
-#if IS_BUILTIN(CONFIG_NET_CLS_CGROUP)
-static inline u32 task_cls_classid(struct task_struct *p)
+#if IS_MODULE(CONFIG_NET_CLS_CGROUP)
+static inline struct cgroup_cls_state *get_cls_cgroup(struct task_struct *p)
{
- u32 classid;
+ struct cgroup_subsys_state *css = task_subsys_state(p,
+ net_cls_subsys_id);
+ if (css)
+ return container_of(css,
+ struct cgroup_cls_state, css);
+ return NULL;
+}
+#elif IS_BUILTIN(CONFIG_NET_CLS_CGROUP)
+static inline struct cgroup_cls_state *get_cls_cgroup(struct task_struct *p)
+{
+ return container_of(task_subsys_state(p, net_cls_subsys_id),
+ struct cgroup_cls_state, css);
+}
+#endif
- if (in_interrupt())
- return 0;
- rcu_read_lock();
- classid = container_of(task_subsys_state(p, net_cls_subsys_id),
- struct cgroup_cls_state, css)->classid;
- rcu_read_unlock();
+#endif /*CONFIG_NET_CLS_CGROUP*/
- return classid;
+#if IS_ENABLED(CONFIG_NET_CLS_CGROUP)
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+static inline u32 skb_cls_classid(const struct sk_buff *skb)
+{
+ return (skb && skb->sk) ? skb->sk->sk_classid : 0;
+}
+
+static inline int get_ifindex_from_skb(const struct sk_buff *skb)
+{
+ int ifindex = 0;
+ if (skb)
+ ifindex = skb->skb_iif;
+ return ifindex;
+}
+
+static struct cls_iface_cntrs *find_cls_counter(
+ struct cgroup_cls_state *cls_cgroup,
+ const char *dev_name,
+ bool create)
+{
+ /*TODO Add lock*/
+ struct cls_iface_cntrs *entry = NULL;
+
+ if (!dev_name) {
+ pr_err("cls please provide valid dev name");
+ return NULL;
+ }
+
+ list_for_each_entry(entry, &cls_cgroup->iface_stats.link, link)
+ if (!strcmp(entry->dev_name, dev_name))
+ return entry;
+
+ if (!create)
+ return entry;
+
+ /*not found, insert*/
+ entry = kmalloc(sizeof(struct cls_iface_cntrs), GFP_ATOMIC);
+ entry->dev_name = kstrdup(dev_name, GFP_ATOMIC);
+ atomic64_set(&entry->rcv_counter, 0);
+ atomic64_set(&entry->snd_counter, 0);
+ list_add_tail(&entry->link, &cls_cgroup->iface_stats.link);
+ return entry;
}
-#elif IS_MODULE(CONFIG_NET_CLS_CGROUP)
+
+static void charge_net_cls_snd(struct cgroup_cls_state *cls_cgroup,
+ const u32 copied, const char *dev_name)
+{
+ struct cls_iface_cntrs *cnt = find_cls_counter(cls_cgroup,
+ dev_name, true);
+
+ if (!cnt)
+ return;
+
+ atomic64_add(copied, &cnt->snd_counter);
+}
+
+static char *get_dev_name(const int ifindex)
+{
+ struct net *net = NULL;
+ struct nsproxy *nsproxy = NULL;
+ struct net_device *net_dev = NULL;
+
+ nsproxy = task_nsproxy(current);
+ if (!nsproxy) {
+ pr_debug("cls cant find task_nsproxy");
+ return NULL;
+ }
+
+ net = get_net(nsproxy->net_ns);
+ if (!net) {
+ pr_debug("cls cant find net");
+ return NULL;
+ }
+ net_dev = dev_get_by_index(net, ifindex);
+
+ return net_dev ? net_dev->name : NULL;
+}
+
+static void charge_net_cls_rcv(struct cgroup_cls_state *cls_cgroup,
+ const u32 copied, const int ifindex)
+{
+ char *dev_name = get_dev_name(ifindex);
+ struct cls_iface_cntrs *cnt = find_cls_counter(cls_cgroup,
+ dev_name, true);
+
+ if (!cnt)
+ return;
+
+ atomic64_add(copied, &cnt->rcv_counter);
+}
+
+static inline void count_cls_rcv(struct task_struct *p, const u32 copied,
+ const int ifindex)
+{
+ struct cgroup_cls_state *cls_cgroup;
+
+ cls_cgroup = get_cls_cgroup(p);
+
+ if (cls_cgroup)
+ charge_net_cls_rcv(cls_cgroup, copied, ifindex);
+}
+
+static inline void count_cls_snd(u32 classid, const u32 copied,
+ const char *dev_name)
+{
+ struct cgroup_cls_state *cls_cgroup;
+
+ cls_cgroup = find_cls_cgroup_by_classid(classid);
+
+ if (cls_cgroup)
+ charge_net_cls_snd(cls_cgroup, copied, dev_name);
+}
+#endif /*CONFIG_NET_CLS_COUNTER*/
+
static inline u32 task_cls_classid(struct task_struct *p)
{
- struct cgroup_subsys_state *css;
- u32 classid = 0;
+ int classid = 0;
+ struct cgroup_cls_state *cls_cgroup = NULL;
if (in_interrupt())
return 0;
rcu_read_lock();
- css = task_subsys_state(p, net_cls_subsys_id);
- if (css)
- classid = container_of(css,
- struct cgroup_cls_state, css)->classid;
+
+ cls_cgroup = get_cls_cgroup(p);
+ if (cls_cgroup)
+ classid = cls_cgroup->classid;
+
rcu_read_unlock();
return classid;
}
-#endif
-#else /* !CGROUP_NET_CLS_CGROUP */
+
+#else /* !CONFIG_NET_CLS_CGROUP */
static inline void sock_update_classid(struct sock *sk, struct task_struct *task)
{
}
@@ -69,5 +212,22 @@ static inline u32 task_cls_classid(struct task_struct *p)
{
return 0;
}
-#endif /* CGROUP_NET_CLS_CGROUP */
+#endif /* CONFIG_NET_CLS_CGROUP */
+
+#if !IS_ENABLED(CONFIG_NET_CLS_CGROUP) || !IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+static inline void count_cls_rcv(struct task_struct *p, const u32 copied,
+ const int ifindex)
+{
+}
+
+static inline void count_cls_snd(u32 classid, const u32 copied,
+ const char *dev_name)
+{
+}
+
+static inline u32 skb_cls_classid(const struct sk_buff *skb)
+{
+ return 0;
+}
+#endif
#endif /* _NET_CLS_CGROUP_H */
diff --git a/include/net/cls_counter_holder.h b/include/net/cls_counter_holder.h
new file mode 100644
index 0000000..a129baa
--- /dev/null
+++ b/include/net/cls_counter_holder.h
@@ -0,0 +1,26 @@
+/*
+ * cls_counter_holder.c Interface for holding references of the
+ * net cls cgroup instances.
+ *
+ * Authors: Alexey Perevalov, <a.perevalov-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ *
+ * Changes:
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _NET_CLS_COUNTER_HOLDER_H_
+#define _NET_CLS_COUNTER_HOLDER_H_
+
+#include <net/cls_cgroup.h>
+
+struct cgroup_cls_state;
+
+void insert_cls_cgroup_entry(struct cgroup_cls_state *obj);
+void delete_cls_cgroup_entry(const u32 classid);
+struct cgroup_cls_state *find_cls_cgroup_by_classid(const u32 classid);
+
+
+#endif /* _NET_CLS_COUNTER_HOLDER_H_ */
diff --git a/init/Kconfig b/init/Kconfig
index 7d30240..6e01fc2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -906,6 +906,31 @@ config CGROUP_HUGETLB
control group is tracked in the third page lru pointer. This means
that we cannot use the controller with huge page less than 3 pages.
+menuconfig NET_CLS_CGROUP
+ tristate "Control Group Classifier"
+ select NET_CLS
+ depends on CGROUPS
+ ---help---
+ Say Y here if you want to classify packets based on the control
+ cgroup of their process.
+
+ To compile this code as a module, choose M here: the
+ module will be called cls_cgroup.
+
+if NET_CLS_CGROUP
+config NET_CLS_COUNTER
+ bool "Network traffic counter for network Control Group Classifier"
+ select NET_CLS
+ default n
+ depends on NET_CLS_CGROUP && RESOURCE_COUNTERS
+ ---help---
+ Say Y here if you want to count traffic associate with the control
+ cgroup.
+
+ To add functionality to cls_cgroup select y.
+
+endif #NET_CLS_CGROUP
+
config CGROUP_PERF
bool "Enable perf_event per-cpu per-container group (cgroup) monitoring"
depends on PERF_EVENTS && CGROUPS
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 4855892..cd82a9e 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2897,6 +2897,8 @@ int cgroup_rm_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
cgroup_cfts_commit(ss, NULL, false);
return -ENOENT;
}
+EXPORT_SYMBOL_GPL(cgroup_rm_cftypes);
+
/**
* cgroup_task_count - count the number of tasks in a cgroup.
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
index ff55247..a51b501 100644
--- a/kernel/res_counter.c
+++ b/kernel/res_counter.c
@@ -13,6 +13,8 @@
#include <linux/res_counter.h>
#include <linux/uaccess.h>
#include <linux/mm.h>
+#include <linux/export.h>
+
void res_counter_init(struct res_counter *counter, struct res_counter *parent)
{
@@ -21,6 +23,7 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent)
counter->soft_limit = RESOURCE_MAX;
counter->parent = parent;
}
+EXPORT_SYMBOL(res_counter_init);
int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
bool force)
@@ -176,6 +179,7 @@ u64 res_counter_read_u64(struct res_counter *counter, int member)
return *res_counter_member(counter, member);
}
#endif
+EXPORT_SYMBOL(res_counter_read_u64);
int res_counter_memparse_write_strategy(const char *buf,
unsigned long long *res)
diff --git a/net/core/dev.c b/net/core/dev.c
index d1e8116..ffc9ec2 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -135,6 +135,7 @@
#include <linux/net_tstamp.h>
#include <linux/static_key.h>
#include <net/flow_keys.h>
+#include <net/cls_cgroup.h>
#include "net-sysfs.h"
@@ -2922,6 +2923,11 @@ int dev_queue_xmit(struct sk_buff *skb)
*/
rcu_read_lock_bh();
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ if (dev)
+ count_cls_snd(skb_cls_classid(skb), skb->len, dev->name);
+#endif
+
skb_update_prio(skb);
txq = netdev_pick_tx(dev, skb);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 1ca2536..dc4dc3a 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -276,6 +276,7 @@
#include <net/ip.h>
#include <net/netdma.h>
#include <net/sock.h>
+#include <net/cls_cgroup.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
@@ -1464,6 +1465,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
u32 seq = tp->copied_seq;
u32 offset;
int copied = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ int ifindex = 0;
+#endif
if (sk->sk_state == TCP_LISTEN)
return -ENOTCONN;
@@ -1510,6 +1514,9 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
++seq;
break;
}
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ ifindex = get_ifindex_from_skb(skb);
+#endif
sk_eat_skb(sk, skb, false);
if (!desc->count)
break;
@@ -1520,8 +1527,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
tcp_rcv_space_adjust(sk);
/* Clean up data we have read: This will do ACK frames. */
- if (copied > 0)
+ if (copied > 0) {
tcp_cleanup_rbuf(sk, copied);
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ count_cls_rcv(current, copied, ifindex);
+#endif
+ }
return copied;
}
EXPORT_SYMBOL(tcp_read_sock);
@@ -1549,6 +1560,9 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
bool copied_early = false;
struct sk_buff *skb;
u32 urg_hole = 0;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ int ifindex = 0;
+#endif
lock_sock(sk);
@@ -1873,6 +1887,9 @@ skip_copy:
if (tcp_hdr(skb)->fin)
goto found_fin_ok;
if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ ifindex = get_ifindex_from_skb(skb);
+#endif
sk_eat_skb(sk, skb, copied_early);
copied_early = false;
}
@@ -1882,6 +1899,9 @@ skip_copy:
/* Process the FIN. */
++*seq;
if (!(flags & MSG_PEEK)) {
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ ifindex = get_ifindex_from_skb(skb);
+#endif
sk_eat_skb(sk, skb, copied_early);
copied_early = false;
}
@@ -1924,6 +1944,11 @@ skip_copy:
/* Clean up data we have read: This will do ACK frames. */
tcp_cleanup_rbuf(sk, copied);
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ if (copied > 0)
+ count_cls_rcv(current, copied, ifindex);
+#endif
+
release_sock(sk);
return copied;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 79c8dbe..a143629 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -101,6 +101,7 @@
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <net/cls_cgroup.h>
#include <net/net_namespace.h>
#include <net/icmp.h>
#include <net/route.h>
@@ -1254,6 +1255,11 @@ try_again:
if (flags & MSG_TRUNC)
err = ulen;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ if (ulen > 0)
+ count_cls_rcv(current, ulen, get_ifindex_from_skb(skb));
+#endif
+
out_free:
skb_free_datagram_locked(sk, skb);
out:
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index 235e01a..ac7bcdb 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -418,17 +418,6 @@ config NET_CLS_FLOW
To compile this code as a module, choose M here: the
module will be called cls_flow.
-config NET_CLS_CGROUP
- tristate "Control Group Classifier"
- select NET_CLS
- depends on CGROUPS
- ---help---
- Say Y here if you want to classify packets based on the control
- cgroup of their process.
-
- To compile this code as a module, choose M here: the
- module will be called cls_cgroup.
-
config NET_EMATCH
bool "Extended Matches"
select NET_CLS
diff --git a/net/sched/Makefile b/net/sched/Makefile
index 978cbf0..95dbb12 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -49,6 +49,7 @@ obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o
obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o
obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o
obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o
+obj-$(CONFIG_NET_CLS_COUNTER) += cls_counter_holder.o
obj-$(CONFIG_NET_EMATCH) += ematch.o
obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o
obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c
index 3a294eb..1535a97 100644
--- a/net/sched/cls_cgroup.c
+++ b/net/sched/cls_cgroup.c
@@ -9,6 +9,7 @@
* Authors: Thomas Graf <tgraf-G/eBtMaohhA@public.gmane.org>
*/
+#include <linux/atomic.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -22,6 +23,15 @@
#include <net/pkt_cls.h>
#include <net/sock.h>
#include <net/cls_cgroup.h>
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+#include <linux/rbtree.h>
+#include <net/cls_counter_holder.h>
+
+static struct notifier_block counter_notifier;
+static const char *rcv_label = "rcv:";
+static const char *snd_label = "snd:";
+
+#endif
static inline struct cgroup_cls_state *cgrp_cls_state(struct cgroup *cgrp)
{
@@ -42,9 +52,38 @@ static struct cgroup_subsys_state *cgrp_css_alloc(struct cgroup *cgrp)
cs = kzalloc(sizeof(*cs), GFP_KERNEL);
if (!cs)
return ERR_PTR(-ENOMEM);
+
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ atomic64_set(&cs->iface_stats.snd_counter, 0);
+ atomic64_set(&cs->iface_stats.rcv_counter, 0);
+ cs->iface_stats.dev_name = 0;
+ INIT_LIST_HEAD(&cs->iface_stats.link);
+#endif
+
return &cs->css;
}
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+static inline void cgrp_counter_destroy(struct cgroup_cls_state *cs)
+{
+ struct list_head *pos, *q;
+ delete_cls_cgroup_entry(cs->classid);
+
+ list_for_each_safe(pos, q, &cs->iface_stats.link) {
+ struct cls_iface_cntrs *tmp = list_entry(
+ pos, struct cls_iface_cntrs, link);
+ list_del(pos);
+ if (!tmp)
+ continue;
+
+ if (!tmp->dev_name)
+ kfree(tmp->dev_name);
+ kfree(tmp);
+ }
+
+}
+#endif
+
static int cgrp_css_online(struct cgroup *cgrp)
{
if (cgrp->parent)
@@ -55,6 +94,14 @@ static int cgrp_css_online(struct cgroup *cgrp)
static void cgrp_css_free(struct cgroup *cgrp)
{
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+
+ struct cgroup_cls_state *cs = cgrp_cls_state(cgrp);
+
+ if (!cs)
+ return;
+ cgrp_counter_destroy(cs);
+#endif
kfree(cgrp_cls_state(cgrp));
}
@@ -85,9 +132,57 @@ static u64 read_classid(struct cgroup *cgrp, struct cftype *cft)
return cgrp_cls_state(cgrp)->classid;
}
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+static const char *extract_dev_name(const char *cgroup_file_name)
+{
+ const char *dot = strchr(cgroup_file_name, '.');
+ const size_t len = dot ?
+ dot - cgroup_file_name : strlen(cgroup_file_name);
+
+ return kstrndup(cgroup_file_name, len, GFP_KERNEL);
+}
+
+static int read_stat(struct cgroup *cgrp, struct cftype *cft,
+ struct cgroup_map_cb *cb)
+{
+ struct cgroup_cls_state *cs = cgrp_cls_state(cgrp);
+ const char *dev_name = extract_dev_name(cft->name);
+ struct cls_iface_cntrs *res = find_cls_counter(cs, dev_name, false);
+
+ if (!res) {
+ pr_debug("cls cant read for cls");
+ return -EINVAL;
+ }
+
+ cb->fill(cb, rcv_label,
+ atomic64_read(&res->rcv_counter));
+ cb->fill(cb, snd_label,
+ atomic64_read(&res->snd_counter));
+
+ kfree(dev_name);
+ return 0;
+}
+#endif /*CONFIG_NET_CLS_COUNTER*/
+
static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value)
{
- cgrp_cls_state(cgrp)->classid = (u32) value;
+ struct cgroup_cls_state *cgrp_cls = cgrp_cls_state(cgrp);
+ u32 *classid = &cgrp_cls->classid;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ u32 oldclassid = *classid;
+
+ if (find_cls_cgroup_by_classid(value)) {
+ pr_err("cls: classid %llu already exists\n", value);
+ return -EINVAL;
+ }
+
+ insert_cls_cgroup_entry(cgrp_cls);
+
+ if (oldclassid)
+ delete_cls_cgroup_entry(oldclassid);
+#endif /*CONFIG_NET_CLS_COUNTER*/
+ *classid = (u32) value;
+
return 0;
}
@@ -304,17 +399,107 @@ static struct tcf_proto_ops cls_cgroup_ops __read_mostly = {
.owner = THIS_MODULE,
};
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+static inline int add_cft_file_for_device(struct net_device *dev)
+{
+ struct cftype *cft;
+ int ret = 0;
+
+ if (!dev)
+ return ret;
+
+ cft = kmalloc(sizeof(struct cftype) * 2,
+ GFP_KERNEL);
+ /* *2 and last 0 fill for terminator */
+ memset(cft, 0, sizeof(struct cftype) * 2);
+
+ snprintf(cft->name, MAX_CFTYPE_NAME,
+ "%s.usage_in_bytes", dev->name);
+ cft->read_map = read_stat;
+ cft->private = RES_USAGE;
+ ret = cgroup_add_cftypes(&net_cls_subsys, cft);
+ if (ret)
+ pr_err("cls error adding cft for counting at cls_cgroup %d\n",
+ ret);
+ return ret;
+}
+
+static int device_state_cb(struct notifier_block *nb,
+ unsigned long state, void *arg)
+{
+ struct net_device *net = (struct net_device *)arg;
+ if (!nb || !net) {
+ pr_err("Not valid arguments for net_device notifier cb\n");
+ return 0;
+ }
+
+ if (state == NETDEV_REGISTER) {
+ pr_info("cls New device %s\n", net->name);
+ return add_cft_file_for_device(net);
+ }
+ return 0;
+}
+
+static inline int init_cgroup_counter(void)
+{
+ int ret = 0;
+ struct net_device *dev;
+ counter_notifier.notifier_call = device_state_cb;
+
+ ret = register_netdevice_notifier(&counter_notifier);
+ if (ret)
+ pr_err("cls Cant register nofier\n");
+
+ for_each_netdev(&init_net, dev) {
+ ret = add_cft_file_for_device(dev);
+ if (ret)
+ goto unregister_notifier;
+ }
+
+ return ret;
+unregister_notifier:
+
+ unregister_netdevice_notifier(&counter_notifier);
+ return ret;
+}
+
+static void release_cft(void)
+{
+ struct list_head *pos, *q;
+ list_for_each_safe(pos, q, &net_cls_subsys.cftsets) {
+ struct cftype_set *set =
+ list_entry(pos, struct cftype_set, node);
+ int ret = cgroup_rm_cftypes(&net_cls_subsys, set->cfts);
+ if (!ret) {
+ pr_err("cls cant remove cftypes\n");
+ break;
+ }
+
+ kfree(set->cfts);
+ }
+}
+#endif
+
static int __init init_cgroup_cls(void)
{
int ret;
-
ret = cgroup_load_subsys(&net_cls_subsys);
if (ret)
goto out;
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ ret = init_cgroup_counter();
+ if (ret)
+ goto unload;
+#endif
+
ret = register_tcf_proto_ops(&cls_cgroup_ops);
if (ret)
- cgroup_unload_subsys(&net_cls_subsys);
+ goto unload;
+
+ return 0;
+unload:
+ cgroup_unload_subsys(&net_cls_subsys);
out:
return ret;
@@ -324,6 +509,9 @@ static void __exit exit_cgroup_cls(void)
{
unregister_tcf_proto_ops(&cls_cgroup_ops);
+#if IS_ENABLED(CONFIG_NET_CLS_COUNTER)
+ release_cft();
+#endif
cgroup_unload_subsys(&net_cls_subsys);
}
diff --git a/net/sched/cls_counter_holder.c b/net/sched/cls_counter_holder.c
new file mode 100644
index 0000000..94ab285
--- /dev/null
+++ b/net/sched/cls_counter_holder.c
@@ -0,0 +1,144 @@
+/*
+ * net/sched/cls_counter_holder.c Interface for holding references of the
+ * net cls cgroup instances.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Perevalov <a.perevalov-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
+ */
+
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <net/cls_cgroup.h>
+#include <net/cls_counter_holder.h>
+
+static struct rb_root classid_tree = RB_ROOT;
+static DEFINE_SPINLOCK(classid_tree_lock);
+
+struct entry {
+ struct cgroup_cls_state *data;
+ struct rb_node node;
+};
+
+static struct entry *find_entry(struct rb_root *root, const u32 classid)
+{
+ struct rb_node *node = root->rb_node;
+
+ while (node) {
+ struct entry *cls_entry = rb_entry(node, struct entry, node);
+ int result = 0;
+ if (!cls_entry || !cls_entry->data)
+ break;
+ result = cls_entry->data->classid - classid;
+
+ if (result < 0)
+ node = node->rb_left;
+ else if (result > 0)
+ node = node->rb_right;
+ else
+ return cls_entry;
+ }
+ return NULL;
+}
+
+void insert_cls_cgroup_entry(struct cgroup_cls_state *obj)
+{
+ struct rb_node **new;
+ struct rb_node *parent = NULL;
+ struct entry *new_entry;
+ unsigned long irq_flags = 0;
+
+ struct rb_root *root = &classid_tree;
+
+ spin_lock_irqsave(&classid_tree_lock, irq_flags);
+
+ new = &root->rb_node;
+
+ while (*new) {
+ struct entry *this = rb_entry(*new, struct entry, node);
+ /* Sort by classid, then by ifindex */
+ int result =
+ (this->data->classid - obj->classid);
+ parent = *new;
+ if (result < 0)
+ new = &((*new)->rb_left);
+ else if (result > 0)
+ new = &((*new)->rb_right);
+ else
+ goto unlock;
+ }
+
+ /* If we here, we need to insert new entry into tree */
+ new_entry = kmalloc(sizeof(struct entry), GFP_ATOMIC);
+ if (!new_entry)
+ goto unlock;
+
+ new_entry->data = obj;
+ /* Add new node and rebalance tree */
+ rb_link_node(&new_entry->node, parent, new);
+ rb_insert_color(&new_entry->node, root);
+
+unlock:
+ spin_unlock_irqrestore(&classid_tree_lock, irq_flags);
+}
+EXPORT_SYMBOL(insert_cls_cgroup_entry);
+
+void delete_cls_cgroup_entry(const u32 classid)
+{
+ unsigned long irq_flags = 0;
+ struct entry *data = NULL;
+ struct rb_root *root = &classid_tree;
+ spin_lock_irqsave(&classid_tree_lock, irq_flags);
+
+ data = find_entry(root, classid);
+
+ if (data) {
+ rb_erase(&data->node, root);
+ kfree(data);
+ }
+ spin_unlock_irqrestore(&classid_tree_lock, irq_flags);
+}
+EXPORT_SYMBOL(delete_cls_cgroup_entry);
+
+static void free_node(struct rb_node *root)
+{
+ struct entry *cur_entry = rb_entry(root, struct entry, node);
+ if (root->rb_left)
+ free_node(root->rb_left);
+ if (root->rb_right)
+ free_node(root->rb_right);
+ kfree(cur_entry);
+}
+
+static void free_classid_tree(void)
+{
+ unsigned long irq_flags = 0;
+
+ spin_lock_irqsave(&classid_tree_lock, irq_flags);
+
+ free_node(classid_tree.rb_node);
+
+ spin_unlock_irqrestore(&classid_tree_lock, irq_flags);
+}
+
+struct cgroup_cls_state *find_cls_cgroup_by_classid(const u32 classid)
+{
+ struct entry *cls_entry = find_entry(&classid_tree, classid);
+ if (cls_entry)
+ return cls_entry->data;
+
+ return NULL;
+}
+EXPORT_SYMBOL(find_cls_cgroup_by_classid);
+
+static void __exit exit_cls_counter_holder(void)
+{
+ free_classid_tree();
+}
+
+module_exit(exit_cls_counter_holder);
+MODULE_LICENSE("GPL");
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH for 3.8] iproute2: Add "ip netns pids" and "ip netns identify"
From: Ben Hutchings @ 2013-01-18 13:53 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Stephen Hemminger, netdev, Serge E. Hallyn
In-Reply-To: <87mww71drv.fsf@xmission.com>
On Thu, 2013-01-17 at 17:27 -0800, Eric W. Biederman wrote:
> Ben Hutchings <bhutchings@solarflare.com> writes:
>
> > On Thu, 2013-01-17 at 16:23 -0800, Eric W. Biederman wrote:
> >> Ben Hutchings <bhutchings@solarflare.com> writes:
> >>
> >> > On Mon, 2012-11-26 at 17:16 -0600, Eric W. Biederman wrote:
> > [...]
> >> >> --- a/ip/ipnetns.c
> >> >> +++ b/ip/ipnetns.c
> > [...]
> >> >> +static int is_pid(const char *str)
> >> >> +{
> >> >> + int ch;
> >> >> + for (; (ch = *str); str++) {
> >> >> + if (!isdigit(ch))
> >> >
> >> > ch must be cast to unsigned char before passing to isdigit().
> >>
> >> isdigit is defined to take an int. A legacy of the implicit casts in
> >> the K&R C days. Casting to unsigned char would be pointless and silly.
> > [...]
> >
> > It's not pointless. This is explained in the very first line of the
> > description in the manual page...
>
> If it's not pointless it is an implementation bug.
You can either get in your time machine and go back to 1978 and fix it,
or add the cast like every C programmer who knows what the C standards
say about these functions.
> The conversion to of
> char to int happens implicitly whenever you pass a char. It is
> absolutely broken to have a function that takes a char converted to int
> and reject the automatic conversion of char to int.
It doesn't take a char... weird but that is how it is defined.
> I suspect much more strongly that it is a case of poor documentation.
>
> If isdigit can't deal with what I have passed it I will be much more
> interested in writing a patch for isdigit.
>
> That said I just dobule checked with the code below. Negative character
> values work correctly and don't cause any runtime errors.
[...]
Testing on one implementation doesn't prove anything. 'char' can be
signed or unsigned depending on the architecture, and some C libraries
work around buggy applications that . That's no reason to write another
buggy application.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* RE: [patch v2] b43: N-PHY: fix gain in b43_nphy_get_gain_ctl_workaround_ent()
From: David Laight @ 2013-01-18 13:53 UTC (permalink / raw)
To: Dan Carpenter, Stefano Brivio
Cc: John W. Linville, linux-wireless, b43-dev, netdev, linux-kernel,
kernel-janitors
In-Reply-To: <20130118133658.GA31186@elgon.mountain>
> + int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, 0x106c,
> + 0x1074, 0x107c, 0x207c};
static const int ...
David
^ permalink raw reply
* [patch v2] b43: N-PHY: fix gain in b43_nphy_get_gain_ctl_workaround_ent()
From: Dan Carpenter @ 2013-01-18 13:36 UTC (permalink / raw)
To: Stefano Brivio
Cc: linux-wireless-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
kernel-janitors-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
b43-dev-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <50F84AF3.5070901-fPG8STNUNVg@public.gmane.org>
There were no break statements in this switch statement so everything
used the default settings. Per Walter Harms's suggestion, I've replaced
the switch statement and done a little cleanup.
Signed-off-by: Dan Carpenter <dan.carpenter-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
---
v2: Additional cleanups.
diff --git a/drivers/net/wireless/b43/tables_nphy.c b/drivers/net/wireless/b43/tables_nphy.c
index 97d4e27..99567db 100644
--- a/drivers/net/wireless/b43/tables_nphy.c
+++ b/drivers/net/wireless/b43/tables_nphy.c
@@ -3226,8 +3226,6 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
{
struct nphy_gain_ctl_workaround_entry *e;
u8 phy_idx;
- u8 tr_iso = ghz5 ? dev->dev->bus_sprom->fem.ghz5.tr_iso :
- dev->dev->bus_sprom->fem.ghz2.tr_iso;
if (!ghz5 && dev->phy.rev >= 6 && dev->phy.radio_rev == 11)
return &nphy_gain_ctl_wa_phy6_radio11_ghz2;
@@ -3249,6 +3247,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
!b43_channel_type_is_40mhz(dev->phy.channel_type))
e->cliplo_gain = 0x2d;
} else if (!ghz5 && dev->phy.rev >= 5) {
+ int gain_data[] = {0x0062, 0x0064, 0x006a, 0x106a, 0x106c,
+ 0x1074, 0x107c, 0x207c};
+ u8 tr_iso = dev->dev->bus_sprom->fem.ghz2.tr_iso;
+
if (ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
@@ -3256,26 +3258,10 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
e->rfseq_init[3] &= ~0x4000;
e->init_gain &= ~0x4000;
}
- switch (tr_iso) {
- case 0:
- e->cliplo_gain = 0x0062;
- case 1:
- e->cliplo_gain = 0x0064;
- case 2:
- e->cliplo_gain = 0x006a;
- case 3:
- e->cliplo_gain = 0x106a;
- case 4:
- e->cliplo_gain = 0x106c;
- case 5:
- e->cliplo_gain = 0x1074;
- case 6:
- e->cliplo_gain = 0x107c;
- case 7:
- e->cliplo_gain = 0x207c;
- default:
- e->cliplo_gain = 0x106a;
- }
+ if (tr_iso > 7)
+ tr_iso = 3;
+ e->cliplo_gain = gain_data[tr_iso];
+
} else if (ghz5 && dev->phy.rev == 4 && ext_lna) {
e->rfseq_init[0] &= ~0x4000;
e->rfseq_init[1] &= ~0x4000;
^ permalink raw reply related
* Re: Redefinition of struct in6_addr in <netinet/in.h> and <linux/in6.h>
From: Carlos O'Donell @ 2013-01-18 13:35 UTC (permalink / raw)
To: Pedro Alves
Cc: Mike Frysinger, David Miller, libc-alpha, bhutchings, yoshfuji,
amwang, tmb, eblake, netdev, linux-kernel, libvirt-list, tgraf,
schwab
In-Reply-To: <50F927A5.5060409@redhat.com>
On 01/18/2013 05:44 AM, Pedro Alves wrote:
> On 01/18/2013 04:22 AM, Carlos O'Donell wrote:
>> On Thu, Jan 17, 2013 at 11:20 PM, Mike Frysinger <vapier@gentoo.org> wrote:
>>> On Wednesday 16 January 2013 22:15:38 David Miller wrote:
>>>> From: Carlos O'Donell <carlos@systemhalted.org>
>>>> Date: Wed, 16 Jan 2013 21:15:03 -0500
>>>>
>>>>> +/* If a glibc-based userspace has already included in.h, then we will
>>>>> not + * define in6_addr (nor the defines), sockaddr_in6, or ipv6_mreq.
>>>>> The + * ABI used by the kernel and by glibc match exactly. Neither the
>>>>> kernel + * nor glibc should break this ABI without coordination.
>>>>> + */
>>>>> +#ifndef _NETINET_IN_H
>>>>> +
>>>>
>>>> I think we should shoot for a non-glibc-centric solution.
>>>>
>>>> I can't imagine that other libc's won't have the same exact problem
>>>> with their netinet/in.h conflicting with the kernel's, redefining
>>>> structures like in6_addr, that we'd want to provide a protection
>>>> scheme for here as well.
>>>
>>> yes, the kernel's use of __GLIBC__ in exported headers has already caused
>>> problems in the past. fortunately, it's been reduced down to just one case
>>> now (stat.h). let's not balloon it back up.
>>> -mike
>>
>> I also see coda.h has grown a __GLIBC__ usage.
>>
>> In the next revision of the patch I created a single libc-compat.h header
>> which encompasses the logic for any libc that wants to coordinate with
>> the kernel headers.
>
>
>> It's simple enough to move all of the __GLIBC__ uses into libc-compat.h,
>> then you control userspace libc coordination from one file.
>
> How about just deciding on a single macro/symbol both the
> kernel and libc (any libc that needs this) define? Something
> like both the kernel and userland doing:
>
> #ifndef __IPV6_BITS_DEFINED
> #define __IPV6_BITS_DEFINED
> ...
> define in6_addr, sockaddr_in6, ipv6_mreq, whatnot
> #endif
>
> So whichever the application includes first, wins.
> Too naive? I didn't see this option being discarded, so
> not sure it was considered.
Too naive, but *close* to what my patch does :-)
The kernel definitions when included first, and in a
glibc userspace, must try to mimic the glibc userspace
headers and we need more than one guard macro to do
that effectively.
The reason I jumped into the code is because this kind of
problem is easy to talk about, but the devil is in the
details.
There are certainly some compromises on both sides, but
the solution promises to solve this problem.
Honestly without UAPI this would have been an impossible
task.
Cheers,
Carlos.
^ permalink raw reply
* Re: Wake on LAN for USB ethernet?
From: Ming Lei @ 2013-01-18 12:57 UTC (permalink / raw)
To: Petko Manolov
Cc: Sarah Sharp, linux-usb-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Petko Manolov, Alan Stern, Greg KH,
Oliver Neukum
In-Reply-To: <alpine.DEB.2.02.1301181047290.3637-dzx9CreErbMJK7zW1S5TsVaTQe2KTcn/@public.gmane.org>
On Fri, Jan 18, 2013 at 4:53 PM, Petko Manolov <petkan-nPnTwAqkgEqakBO8gow8eQ@public.gmane.org> wrote:
> The code in the driver is based on the specs from ADMTek (later, Infineon).
> Since i never suspend my machines this feature has not been tested by me.
>
> However, if the proposed patch is the right thing to do i'd be happy to see
> it applied.
I think it is the right thing, at least many network drivers do that, such as
smsc usbnet drivers and many of PCI ethernet drivers.
So I will prepare one formal version for merge.
Thanks,
--
Ming Lei
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: ip6_dst_lookup_tail oops
From: Neil Horman @ 2013-01-18 12:48 UTC (permalink / raw)
To: Dave Jones; +Cc: netdev
In-Reply-To: <20130117152504.GC32586@redhat.com>
On Thu, Jan 17, 2013 at 10:25:04AM -0500, Dave Jones wrote:
> On Wed, Jan 16, 2013 at 09:55:07AM -0500, Dave Jones wrote:
>
> > BUG: unable to handle kernel NULL pointer dereference at 000000000000017e
> > IP: [<ffffffff81626308>] ip6_dst_lookup_tail+0xe8/0x200
> > RIP: 0010:[<ffffffff81626308>] [<ffffffff81626308>] ip6_dst_lookup_tail+0xe8/0x200
> > RAX: 0000000000000011 RBX: 0000000000000000 RCX: 0000000000000000
> > ..
> > Call Trace:
> > [<ffffffff816266cb>] ip6_sk_dst_lookup_flow+0xcb/0x1b0
> > [<ffffffff8164803e>] udpv6_sendmsg+0x66e/0xb80
> > [<ffffffff815e6391>] inet_sendmsg+0x111/0x220
> > [<ffffffff81547220>] sock_sendmsg+0xb0/0xe0
> > [<ffffffff815486bc>] __sys_sendmsg+0x3ac/0x3c0
> > [<ffffffff8154afb9>] sys_sendmsg+0x49/0x90
> > [<ffffffff816a6802>] system_call_fastpath+0x16/0x1b
> >
> > 0: f6 80 6d 01 00 00 de testb $0xde,0x16d(%rax)
> > 7: 75 b9 jne 0xffffffffffffffc2
> > 9: 48 8b 56 18 mov 0x18(%rsi),%rdx
> > d: 49 8d 75 24 lea 0x24(%r13),%rsi
> > 11: b9 .byte 0xb9
> > 12: 01 00 add %eax,(%rax)
> > ...
> >
> > This looks like the GPF in this function I reported last September.
> > http://www.spinics.net/lists/netdev/msg211894.html
> >
> > In those reports, I ended up with an rt->n == 0x8000000000000011,
> > but this time, it's just 0x11.
>
> Now I've hit it with rt->n = 2000000000000010. So I'm starting to
> think this is getting passed in directly from userspace somehow, as
> these values look like the output of my 'set a few random bits' routine
> that sometimes gets called for params.
>
> I'm having trouble mapping a corrupt sendmsg parameter to a messed up rt->n though.
>
> Any clues ?
>
> Dave
>
Well, neighbor table entries for ipv6 get added over rtnetlink, but it seems you
would have to be able to memory map the socket to get a pointer like that into
place. Trinity doesn't record the syscalls it makes does it? That might be
helpful in tracking this down.
Neil
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [patch] isdn/gigaset: off by one check leading to oops
From: Dan Carpenter @ 2013-01-18 12:26 UTC (permalink / raw)
To: Tilman Schmidt
Cc: Hansjoerg Lipp, Karsten Keil, gigaset307x-common, netdev,
kernel-janitors
In-Reply-To: <50F93D78.5010903@imap.cc>
On Fri, Jan 18, 2013 at 01:18:00PM +0100, Tilman Schmidt wrote:
> I'll prepare a patch of my own, citing you as reporter, if that's
> ok with you.
>
That sounds great.
regards,
dan carpenter
^ permalink raw reply
* Re: [patch] isdn/gigaset: off by one check leading to oops
From: Tilman Schmidt @ 2013-01-18 12:18 UTC (permalink / raw)
To: Dan Carpenter
Cc: Hansjoerg Lipp, Karsten Keil, gigaset307x-common, netdev,
kernel-janitors
In-Reply-To: <20130117074405.GA26270@elgon.mountain>
[-- Attachment #1: Type: text/plain, Size: 1487 bytes --]
Hi Dan,
Am 17.01.2013 08:44, schrieb Dan Carpenter:
> If l == 12 then later we subtract 12 leaving zero. We do a zero size
> allocation, so "dbgline" points to the ZERO_SIZE_PTR. It leads to an
> oops when we set the NUL terminator:
> dbgline[3 * l - 1] = '\0';
thanks for finding that bug, but NAK to your fix.
> @@ -239,7 +239,7 @@ static inline void dump_rawmsg(enum debuglevel level, const char *tag,
> return;
>
> l = CAPIMSG_LEN(data);
> - if (l < 12) {
> + if (l <= 12) {
> gig_dbg(level, "%s: ??? LEN=%04d", tag, l);
> return;
> }
CAPI messages of exactly 12 bytes are legal, and should be decoded
with the regular gig_dbg() call immediately after that hunk. It's
just the hex dump part that should be skipped in that case.
So I'd prefer to have it fixed this way instead:
@@ -248,6 +248,8 @@ static inline void dump_rawmsg(enum debuglevel
level, const char *tag,
CAPIMSG_APPID(data), CAPIMSG_MSGID(data), l,
CAPIMSG_CONTROL(data));
l -= 12;
+ if (l <= 0)
+ return;
dbgline = kmalloc(3 * l, GFP_ATOMIC);
if (!dbgline)
return;
I'll prepare a patch of my own, citing you as reporter, if that's
ok with you.
Thanks,
Tilman
--
Tilman Schmidt E-Mail: tilman@imap.cc
Bonn, Germany
Diese Nachricht besteht zu 100% aus wiederverwerteten Bits.
Ungeöffnet mindestens haltbar bis: (siehe Rückseite)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 260 bytes --]
^ permalink raw reply
* [PATCH net-next] ndisc: Check NS message length before access.
From: YOSHIFUJI Hideaki @ 2013-01-18 12:05 UTC (permalink / raw)
To: David Miller, netdev; +Cc: YOSHIFUJI Hideaki
Check message length before accessing "target" field,
as we do for other types.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/ipv6/ndisc.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 429622d..350f860 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -671,6 +671,11 @@ static void ndisc_recv_ns(struct sk_buff *skb)
bool inc;
int is_router = -1;
+ if (skb->len < sizeof(struct nd_msg)) {
+ ND_PRINTK(2, warn, "NS: packet too short\n");
+ return;
+ }
+
if (ipv6_addr_is_multicast(&msg->target)) {
ND_PRINTK(2, warn, "NS: multicast target address\n");
return;
--
1.7.9.5
^ permalink raw reply related
* [PATCH net-next] ipv6: Remove unused neigh argument for icmp6_dst_alloc() and its callers.
From: YOSHIFUJI Hideaki @ 2013-01-18 12:00 UTC (permalink / raw)
To: David Miller, netdev, YOSHIFUJI Hideaki
Because of rt->n removal, we do not need neigh argument any more.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
include/net/ip6_route.h | 1 -
net/ipv6/mcast.c | 4 ++--
net/ipv6/ndisc.c | 15 +++++----------
net/ipv6/route.c | 1 -
4 files changed, 7 insertions(+), 14 deletions(-)
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 30cbb15..260f83f 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -103,7 +103,6 @@ extern struct rt6_info *rt6_lookup(struct net *net,
int oif, int flags);
extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
- struct neighbour *neigh,
struct flowi6 *fl6);
extern int icmp6_dst_gc(void);
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 8237ee1..587a845 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1391,7 +1391,7 @@ static void mld_sendpack(struct sk_buff *skb)
icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
skb->dev->ifindex);
- dst = icmp6_dst_alloc(skb->dev, NULL, &fl6);
+ dst = icmp6_dst_alloc(skb->dev, &fl6);
err = 0;
if (IS_ERR(dst)) {
@@ -1759,7 +1759,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
icmpv6_flow_init(sk, &fl6, type,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
skb->dev->ifindex);
- dst = icmp6_dst_alloc(skb->dev, NULL, &fl6);
+ dst = icmp6_dst_alloc(skb->dev, &fl6);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
goto err_out;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 5733cd2..429622d 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -432,7 +432,6 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
}
static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
- struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *saddr,
struct icmp6hdr *icmp6h)
@@ -448,7 +447,7 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
type = icmp6h->icmp6_type;
icmpv6_flow_init(sk, &fl6, type, saddr, daddr, dev->ifindex);
- dst = icmp6_dst_alloc(dev, neigh, &fl6);
+ dst = icmp6_dst_alloc(dev, &fl6);
if (IS_ERR(dst)) {
kfree_skb(skb);
return;
@@ -474,7 +473,6 @@ static void ndisc_send_skb(struct sk_buff *skb, struct net_device *dev,
* Send a Neighbour Discover packet
*/
static void __ndisc_send(struct net_device *dev,
- struct neighbour *neigh,
const struct in6_addr *daddr,
const struct in6_addr *saddr,
struct icmp6hdr *icmp6h, const struct in6_addr *target,
@@ -486,7 +484,7 @@ static void __ndisc_send(struct net_device *dev,
if (!skb)
return;
- ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h);
+ ndisc_send_skb(skb, dev, daddr, saddr, icmp6h);
}
static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
@@ -521,8 +519,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
icmp6h.icmp6_solicited = solicited;
icmp6h.icmp6_override = override;
- __ndisc_send(dev, neigh, daddr, src_addr,
- &icmp6h, solicited_addr,
+ __ndisc_send(dev, daddr, src_addr, &icmp6h, solicited_addr,
inc_opt ? ND_OPT_TARGET_LL_ADDR : 0);
}
@@ -563,8 +560,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
saddr = &addr_buf;
}
- __ndisc_send(dev, neigh, daddr, saddr,
- &icmp6h, solicit,
+ __ndisc_send(dev, daddr, saddr, &icmp6h, solicit,
!ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0);
}
@@ -598,8 +594,7 @@ void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr,
}
}
#endif
- __ndisc_send(dev, NULL, daddr, saddr,
- &icmp6h, NULL,
+ __ndisc_send(dev, daddr, saddr, &icmp6h, NULL,
send_sllao ? ND_OPT_SOURCE_LL_ADDR : 0);
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 3a562a1..2d94d5a 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1203,7 +1203,6 @@ static struct dst_entry *icmp6_dst_gc_list;
static DEFINE_SPINLOCK(icmp6_dst_lock);
struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
- struct neighbour *neigh,
struct flowi6 *fl6)
{
struct dst_entry *dst;
--
1.7.9.5
^ permalink raw reply related
* [PATCH net] ipv6: Fix addrconf_dst_alloc() failure check.
From: YOSHIFUJI Hideaki @ 2013-01-18 11:56 UTC (permalink / raw)
To: David Miller, netdev; +Cc: YOSHIFUJI Hideaki
The function returns NULL on error and it never return error code
embedded in pointer.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
---
net/ipv6/addrconf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 420e563..d0a2df2b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -783,8 +783,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
}
rt = addrconf_dst_alloc(idev, addr, false);
- if (IS_ERR(rt)) {
- err = PTR_ERR(rt);
+ if (!rt) {
+ err = -ENOMEM;
goto out;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH] ping doc: Fix typo.
From: Jan Synacek @ 2013-01-18 11:21 UTC (permalink / raw)
To: yoshfuji; +Cc: netdev, Jan Synacek
Signed-off-by: Jan Synacek <jsynacek@redhat.com>
---
doc/ping.sgml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/doc/ping.sgml b/doc/ping.sgml
index 4e0e65f..eec92a2 100644
--- a/doc/ping.sgml
+++ b/doc/ping.sgml
@@ -600,7 +600,7 @@ Many Hosts and Gateways ignore the RECORD_ROUTE option.
<listitem><para>
The maximum IP header length is too small for options like
RECORD_ROUTE to be completely useful.
-There's not much that that can be done about this, however.
+There's not much that can be done about this, however.
</para></listitem>
<listitem><para>
Flood pinging is not recommended in general, and flood pinging the
--
1.8.0.2
^ permalink raw reply related
* Re: [PATCH v3 2/2] virtio-net: introduce a new control to set macaddr
From: Stefan Hajnoczi @ 2013-01-18 11:00 UTC (permalink / raw)
To: akong; +Cc: mst, kvm, netdev, qemu-devel, virtualization, davem
In-Reply-To: <1358419212-32356-3-git-send-email-akong@redhat.com>
On Thu, Jan 17, 2013 at 06:40:12PM +0800, akong@redhat.com wrote:
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 395ab4f..837c978 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -802,14 +802,32 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
> struct virtnet_info *vi = netdev_priv(dev);
> struct virtio_device *vdev = vi->vdev;
> int ret;
> + struct scatterlist sg;
> + char save_addr[ETH_ALEN];
> + unsigned char save_aatype;
> +
> + memcpy(save_addr, dev->dev_addr, ETH_ALEN);
> + save_aatype = dev->addr_assign_type;
>
> ret = eth_mac_addr(dev, p);
> if (ret)
> return ret;
>
> - if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC))
> + if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
> + sg_init_one(&sg, dev->dev_addr, dev->addr_len);
> + if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
> + VIRTIO_NET_CTRL_MAC_ADDR_SET,
> + &sg, 1, 0)) {
> + dev_warn(&vdev->dev,
> + "Failed to set mac address by vq command.\n");
> + memcpy(dev->dev_addr, save_addr, ETH_ALEN);
> + dev->addr_assign_type = save_aatype;
> + return -EINVAL;
> + }
eth_mac_addr() doesn't allow callers to implement error handling nicely.
Although you didn't duplicate it's code directly, this patch still leaks
internals of eth_mac_addr().
How about splitting eth_mac_addr() in a separate patch:
int eth_prepare_mac_addr_change(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev))
return -EBUSY;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
return 0;
}
void eth_commit_mac_addr_change(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
/* if device marked as NET_ADDR_RANDOM, reset it */
dev->addr_assign_type &= ~NET_ADDR_RANDOM;
}
/* Default implementation of MAC address changing */
int eth_mac_addr(struct net_device *dev, void *p)
{
int ret;
ret = eth_prepare_mac_addr_change(dev, p);
if (ret < 0)
return ret;
eth_commit_mac_addr_change(dev, p);
return 0;
}
Now virtio_net.c does:
ret = eth_prepare_mac_addr_change(dev, p);
if (ret < 0)
return ret;
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
sg_init_one(&sg, dev->dev_addr, dev->addr_len);
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC,
VIRTIO_NET_CTRL_MAC_ADDR_SET,
&sg, 1, 0)) {
dev_warn(&vdev->dev,
"Failed to set mac address by vq command.\n");
return -EINVAL;
}
} ...
eth_commit_mac_addr_change(dev, p);
return 0;
Stefan
^ permalink raw reply
* Re: Redefinition of struct in6_addr in <netinet/in.h> and <linux/in6.h>
From: Pedro Alves @ 2013-01-18 10:44 UTC (permalink / raw)
To: Carlos O'Donell
Cc: Mike Frysinger, David Miller, libc-alpha, bhutchings, yoshfuji,
amwang, tmb, eblake, netdev, linux-kernel, libvirt-list, tgraf,
schwab
In-Reply-To: <CAE2sS1jMhnRcoo1oe7wQ+SP=40u9mkps6vXua8TQQ4Tbf2qKOQ@mail.gmail.com>
On 01/18/2013 04:22 AM, Carlos O'Donell wrote:
> On Thu, Jan 17, 2013 at 11:20 PM, Mike Frysinger <vapier@gentoo.org> wrote:
>> On Wednesday 16 January 2013 22:15:38 David Miller wrote:
>>> From: Carlos O'Donell <carlos@systemhalted.org>
>>> Date: Wed, 16 Jan 2013 21:15:03 -0500
>>>
>>>> +/* If a glibc-based userspace has already included in.h, then we will
>>>> not + * define in6_addr (nor the defines), sockaddr_in6, or ipv6_mreq.
>>>> The + * ABI used by the kernel and by glibc match exactly. Neither the
>>>> kernel + * nor glibc should break this ABI without coordination.
>>>> + */
>>>> +#ifndef _NETINET_IN_H
>>>> +
>>>
>>> I think we should shoot for a non-glibc-centric solution.
>>>
>>> I can't imagine that other libc's won't have the same exact problem
>>> with their netinet/in.h conflicting with the kernel's, redefining
>>> structures like in6_addr, that we'd want to provide a protection
>>> scheme for here as well.
>>
>> yes, the kernel's use of __GLIBC__ in exported headers has already caused
>> problems in the past. fortunately, it's been reduced down to just one case
>> now (stat.h). let's not balloon it back up.
>> -mike
>
> I also see coda.h has grown a __GLIBC__ usage.
>
> In the next revision of the patch I created a single libc-compat.h header
> which encompasses the logic for any libc that wants to coordinate with
> the kernel headers.
> It's simple enough to move all of the __GLIBC__ uses into libc-compat.h,
> then you control userspace libc coordination from one file.
How about just deciding on a single macro/symbol both the
kernel and libc (any libc that needs this) define? Something
like both the kernel and userland doing:
#ifndef __IPV6_BITS_DEFINED
#define __IPV6_BITS_DEFINED
...
define in6_addr, sockaddr_in6, ipv6_mreq, whatnot
#endif
So whichever the application includes first, wins.
Too naive? I didn't see this option being discarded, so
not sure it was considered.
--
Pedro Alves
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox