View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0000039 | Freifunk Franken Firmware | General | public | 2017-03-12 15:57 | 2019-10-02 12:49 |
Reporter | ChristianD | Assigned To | |||
Priority | normal | Severity | minor | Reproducibility | have not tried |
Status | closed | Resolution | fixed | ||
Product Version | 20170218-alpha | ||||
Summary | 0000039: l2tp Traffic overflow | ||||
Description | https://github.com/FreifunkFranken/firmware/commit/fce5b0ceefa9fdddd3f1b690416659785df4e2fc#diff-055d355e728cddb080887618826715a5 Der Bug scheint im LEDE wieder aufzutreten. Vermutlich brauchen wir das Patch auch im LEDE | ||||
Tags | No tags attached. | ||||
Attached Files | |||||
|
Ich habe versucht den alten Patch https://github.com/FreifunkFranken/firmware/commit/fce5b0ceefa9fdddd3f1b690416659785df4e2fc#diff-055d355e728cddb080887618826715a5 auf das Verzeichnis target/linux/ar71xx/patches-4.4/fix-l2tp-stats-couter-on-32-Bit-Systems.patch umzubiegen damit es für den aktuellen Kernel gebaut wird. Leider bootet dann der Router nicht mehr, ich gehe mal davon aus, dass das Patch nicht mit dem 4.4er Kernel funktioniert. Aufgrund mangelnder C-Kenntnisse komm ich da auch nicht weiter. |
|
B Zeile 109 bis 130. Zumindest das Patch scheint richtig drinnen zu sein. Warum der Router nicht bootet keine Ahnung. l2tp_eth.c (9,072 bytes)
/* * L2TPv3 ethernet pseudowire driver * * Copyright (c) 2008,2009,2010 Katalix Systems Ltd * * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/socket.h> #include <linux/hash.h> #include <linux/l2tp.h> #include <linux/in.h> #include <linux/etherdevice.h> #include <linux/spinlock.h> #include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> #include <net/udp.h> #include <net/inet_common.h> #include <net/inet_hashtables.h> #include <net/tcp_states.h> #include <net/protocol.h> #include <net/xfrm.h> #include <net/net_namespace.h> #include <net/netns/generic.h> #include "l2tp_core.h" /* Default device name. May be overridden by name specified by user */ #define L2TP_ETH_DEV_NAME "l2tpeth%d" /* via netdev_priv() */ struct l2tp_eth { struct net_device *dev; struct sock *tunnel_sock; struct l2tp_session *session; struct list_head list; atomic_long_t tx_bytes; atomic_long_t tx_packets; atomic_long_t tx_dropped; atomic_long_t rx_bytes; atomic_long_t rx_packets; atomic_long_t rx_errors; }; /* via l2tp_session_priv() */ struct l2tp_eth_sess { struct net_device *dev; }; /* per-net private data for this module */ static unsigned int l2tp_eth_net_id; struct l2tp_eth_net { struct list_head l2tp_eth_dev_list; spinlock_t l2tp_eth_lock; }; static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net) { return net_generic(net, l2tp_eth_net_id); } static struct lock_class_key l2tp_eth_tx_busylock; static int l2tp_eth_dev_init(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); priv->dev = dev; eth_hw_addr_random(dev); eth_broadcast_addr(dev->broadcast); dev->qdisc_tx_busylock = &l2tp_eth_tx_busylock; return 0; } static void l2tp_eth_dev_uninit(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); struct l2tp_eth_net *pn = l2tp_eth_pernet(dev_net(dev)); spin_lock(&pn->l2tp_eth_lock); list_del_init(&priv->list); spin_unlock(&pn->l2tp_eth_lock); dev_put(dev); } static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); struct l2tp_session *session = priv->session; unsigned int len = skb->len; int ret = l2tp_xmit_skb(session, skb, session->hdr_len); if (likely(ret == NET_XMIT_SUCCESS)) { atomic_long_add(len, &priv->tx_bytes); atomic_long_inc(&priv->tx_packets); } else { atomic_long_inc(&priv->tx_dropped); } return NETDEV_TX_OK; } static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct l2tp_eth *priv = netdev_priv(dev); #if BITS_PER_LONG == 64 stats->tx_bytes = atomic_long_read(&priv->tx_bytes); stats->tx_packets = atomic_long_read(&priv->tx_packets); stats->tx_dropped = atomic_long_read(&priv->tx_dropped); stats->rx_bytes = atomic_long_read(&priv->rx_bytes); stats->rx_packets = atomic_long_read(&priv->rx_packets); stats->rx_errors = atomic_long_read(&priv->rx_errors); #else stats->tx_bytes = (unsigned long) atomic_long_read(&priv->tx_bytes); stats->tx_packets = (unsigned long) atomic_long_read(&priv->tx_packets); stats->tx_dropped = (unsigned long) atomic_long_read(&priv->tx_dropped); stats->rx_bytes = (unsigned long) atomic_long_read(&priv->rx_bytes); stats->rx_packets = (unsigned long) atomic_long_read(&priv->rx_packets); stats->rx_errors = (unsigned long) atomic_long_read(&priv->rx_errors); #endif return stats; } static struct net_device_ops l2tp_eth_netdev_ops = { .ndo_init = l2tp_eth_dev_init, .ndo_uninit = l2tp_eth_dev_uninit, .ndo_start_xmit = l2tp_eth_dev_xmit, .ndo_get_stats64 = l2tp_eth_get_stats64, .ndo_set_mac_address = eth_mac_addr, }; static void l2tp_eth_dev_setup(struct net_device *dev) { ether_setup(dev); dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->features |= NETIF_F_LLTX; dev->netdev_ops = &l2tp_eth_netdev_ops; dev->destructor = free_netdev; } static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) { struct l2tp_eth_sess *spriv = l2tp_session_priv(session); struct net_device *dev = spriv->dev; struct l2tp_eth *priv = netdev_priv(dev); if (session->debug & L2TP_MSG_DATA) { unsigned int length; length = min(32u, skb->len); if (!pskb_may_pull(skb, length)) goto error; pr_debug("%s: eth recv\n", session->name); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length); } if (!pskb_may_pull(skb, ETH_HLEN)) goto error; secpath_reset(skb); /* checksums verified by L2TP */ skb->ip_summed = CHECKSUM_NONE; skb_dst_drop(skb); nf_reset(skb); if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { atomic_long_inc(&priv->rx_packets); atomic_long_add(data_len, &priv->rx_bytes); } else { atomic_long_inc(&priv->rx_errors); } return; error: atomic_long_inc(&priv->rx_errors); kfree_skb(skb); } static void l2tp_eth_delete(struct l2tp_session *session) { struct l2tp_eth_sess *spriv; struct net_device *dev; if (session) { spriv = l2tp_session_priv(session); dev = spriv->dev; if (dev) { unregister_netdev(dev); spriv->dev = NULL; module_put(THIS_MODULE); } } } #if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE) static void l2tp_eth_show(struct seq_file *m, void *arg) { struct l2tp_session *session = arg; struct l2tp_eth_sess *spriv = l2tp_session_priv(session); struct net_device *dev = spriv->dev; seq_printf(m, " interface %s\n", dev->name); } #endif static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) { struct net_device *dev; char name[IFNAMSIZ]; struct l2tp_tunnel *tunnel; struct l2tp_session *session; struct l2tp_eth *priv; struct l2tp_eth_sess *spriv; int rc; struct l2tp_eth_net *pn; tunnel = l2tp_tunnel_find(net, tunnel_id); if (!tunnel) { rc = -ENODEV; goto out; } session = l2tp_session_find(net, tunnel, session_id); if (session) { rc = -EEXIST; goto out; } if (cfg->ifname) { dev = dev_get_by_name(net, cfg->ifname); if (dev) { dev_put(dev); rc = -EEXIST; goto out; } strlcpy(name, cfg->ifname, IFNAMSIZ); } else strcpy(name, L2TP_ETH_DEV_NAME); session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, peer_session_id, cfg); if (!session) { rc = -ENOMEM; goto out; } dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, l2tp_eth_dev_setup); if (!dev) { rc = -ENOMEM; goto out_del_session; } dev_net_set(dev, net); if (session->mtu == 0) session->mtu = dev->mtu - session->hdr_len; dev->mtu = session->mtu; dev->needed_headroom += session->hdr_len; priv = netdev_priv(dev); priv->dev = dev; priv->session = session; INIT_LIST_HEAD(&priv->list); priv->tunnel_sock = tunnel->sock; session->recv_skb = l2tp_eth_dev_recv; session->session_close = l2tp_eth_delete; #if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE) session->show = l2tp_eth_show; #endif spriv = l2tp_session_priv(session); spriv->dev = dev; rc = register_netdev(dev); if (rc < 0) goto out_del_dev; __module_get(THIS_MODULE); /* Must be done after register_netdev() */ strlcpy(session->ifname, dev->name, IFNAMSIZ); dev_hold(dev); pn = l2tp_eth_pernet(dev_net(dev)); spin_lock(&pn->l2tp_eth_lock); list_add(&priv->list, &pn->l2tp_eth_dev_list); spin_unlock(&pn->l2tp_eth_lock); return 0; out_del_dev: free_netdev(dev); spriv->dev = NULL; out_del_session: l2tp_session_delete(session); out: return rc; } static __net_init int l2tp_eth_init_net(struct net *net) { struct l2tp_eth_net *pn = net_generic(net, l2tp_eth_net_id); INIT_LIST_HEAD(&pn->l2tp_eth_dev_list); spin_lock_init(&pn->l2tp_eth_lock); return 0; } static struct pernet_operations l2tp_eth_net_ops = { .init = l2tp_eth_init_net, .id = &l2tp_eth_net_id, .size = sizeof(struct l2tp_eth_net), }; static const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = { .session_create = l2tp_eth_create, .session_delete = l2tp_session_delete, }; static int __init l2tp_eth_init(void) { int err = 0; err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops); if (err) goto out; err = register_pernet_device(&l2tp_eth_net_ops); if (err) goto out_unreg; pr_info("L2TP ethernet pseudowire support (L2TPv3)\n"); return 0; out_unreg: l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH); out: return err; } static void __exit l2tp_eth_exit(void) { unregister_pernet_device(&l2tp_eth_net_ops); l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH); } module_init(l2tp_eth_init); module_exit(l2tp_eth_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("L2TP ethernet pseudowire driver"); MODULE_VERSION("1.0"); MODULE_ALIAS_L2TP_PWTYPE(5); |
|
Hab mir das mal im Code angesehen; was ich nicht verstehe: Die Funktion atomic_long_read gibt immer long zurück. Die Member im struct rtnl_link_stats64 haben aber immer Typ __u64. Es müsste also eigtl. doch auch _immer_ eine Conversion von long nach __u64 (ist ja unsigned) stattfinden, oder? |
|
Und während u64 immer die gleiche Größe hat, müsste "unsigned long" ja compilerspezifisch sein, also unterschiedliche Größen haben können. Das heißt, gerade wenn z.B. BITS_PER_LONG=32 würde ja dann ggf. eine 32-bit lange unsigned long in eine 64-bit lange __u64 variable gespeichert?! Aber wahrscheinlich müsste man dazu mit dem Ersteller des Patches sprechen, vll. versteh ich da ja auch was falsch. |
|
Was mir gerade auch noch aufgefallen ist: In der Funktion atomic_long_read kann es unter bestimmten Umständen zu einer Conversion long long nach long kommen, was auch einen Integer Overflow an der selben Stelle auslösen könnte. |
|
Bei welcher Firmware-Version tritt der Overflow denn definitiv nicht auf? Kann ich mir einfach den letzten Commit der 20170110 ziehen, bauen und dann die entsprechenden Stellen mit der LEDE-Variante vergleichen? |
|
Alles vor LEDE da war bereits ein Patch mit drinnen. https://github.com/FreifunkFranken/firmware/commit/fce5b0ceefa9fdddd3f1b690416659785df4e2fc#diff-055d355e728cddb080887618826715a5 Das Patch wurde beim Update auf LEDE rausgenommen, ich hab es dann wieder in LEDE mit eingebaut aber seitdem bootet der Router nicht mehr, warum? Keine Ahnung mfg Christian |
|
Okay, short version: Bei mir läuft es mit dem alten patch, wenn man nur das Patch-Verzeichnis ändert (3.3.irgendwas nach 4.4, siehe Anhang). Long version: 1. Ich hab die Firmware mit dem Stand benutzt, die ich für den v12 committed habe (also etwas neuer als die alpha, aber LEDE stable branch). Verwendet zum Testen habe ich einen WR841N v10. 2. Ich hab zur Referenz auch einmal den Overflow mit der standard-alpha reproduziert. Dabei hatte ich beim Upgraden nen Bootloop und musste mit TFTP recovern. Danach lief es wieder, aber vll. ist das dasselbe, was ChristianD passiert ist. (=es war "Zufall") 3. Der Code ist so geschrieben, dass auf 32-bit Geräten auch nur eine 32-bit int als Zwischenvariable verwendet wird. D.h. der Traffic kann keine Werte höher als 4 GB (unsigned int) annehmen, danach läuft er wieder von Null. 4. Ich habe den Code von 20170110 und der alpha näher angesehen, die Routinen sind hier effektiv gleich, sodass der Patch auch den gleichen Effekt haben sollte. 5. Vor dem Test hab ich jeweils fastd über SSH deaktiviert und dann per Download genügend Traffic produziert (mir ist keine einfachere Methode eingefallen) ... Mehr fällt mir grade nicht ein 0004-ar71xx-3.18-l2tp-stats.patch (1,729 bytes)
--- target/linux/ar71xx/patches-4.4/fix-l2tp-stats-couter-on-32-Bit-Systems.patch 1970-01-01 01:00:00.000000000 +0100 +++ target/linux/ar71xx/patches-4.4/fix-l2tp-stats-couter-on-32-Bit-Systems.patch 2016-03-12 18:41:32.818602442 +0100 @@ -0,0 +1,38 @@ +From 19b1c8733b99f13005f2d8918bce588f0b2556f8 Mon Sep 17 00:00:00 2001 +From: Dominik Heidler <dominik@heidler.eu> +Date: Sat, 12 Mar 2016 18:37:42 +0100 +Subject: [PATCH] Fix l2tp stats couter on 32 Bit Systems + +--- + net/l2tp/l2tp_eth.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/net/l2tp/l2tp_eth.c b/net/l2tp/l2tp_eth.c +index e253c26..a18c2ff 100644 +--- a/net/l2tp/l2tp_eth.c ++++ b/net/l2tp/l2tp_eth.c +@@ -111,12 +111,21 @@ static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, + { + struct l2tp_eth *priv = netdev_priv(dev); + ++ #if BITS_PER_LONG == 64 + stats->tx_bytes = atomic_long_read(&priv->tx_bytes); + stats->tx_packets = atomic_long_read(&priv->tx_packets); + stats->tx_dropped = atomic_long_read(&priv->tx_dropped); + stats->rx_bytes = atomic_long_read(&priv->rx_bytes); + stats->rx_packets = atomic_long_read(&priv->rx_packets); + stats->rx_errors = atomic_long_read(&priv->rx_errors); ++ #else ++ stats->tx_bytes = (unsigned long) atomic_long_read(&priv->tx_bytes); ++ stats->tx_packets = (unsigned long) atomic_long_read(&priv->tx_packets); ++ stats->tx_dropped = (unsigned long) atomic_long_read(&priv->tx_dropped); ++ stats->rx_bytes = (unsigned long) atomic_long_read(&priv->rx_bytes); ++ stats->rx_packets = (unsigned long) atomic_long_read(&priv->rx_packets); ++ stats->rx_errors = (unsigned long) atomic_long_read(&priv->rx_errors); ++ #endif + return stats; + } + +-- +2.7.2 + |
|
ich hab es auf einen wdr3600 geflasht. Leider keine UART dran zum gucken was passiert. Aber er bootet ein paar Sekunden, dann leuchten alle LEDs auf, dann wieder nur Power und nach etwa. 10-15Sekunden wieder alle LEDs dann nur Power usw... in einer Endlosschleife. Sieht mir nach ner bootloop aus. Ich hab bei mir auch nur das Kernelverzeichnis geändert (wie du sagtest von 3.xirgendwas auf 4.4irgendwas) damit das Problem entstand tftp&kram hab ich noch nicht probiert. |
|
Genau das Verhalten hatte ich auch, als ich nur die offizielle alpha geflasht habe (was aber vorher schon mal funktioniert hat). Danach ging es auch wieder (20170110 factory per TFTP, dann Upgrade auf alpha), k.A. was hier der Grund war. Entsprechend würde ich es an deiner Stelle auf einen zweiten Versuch ankommen lassen. |
|
Hab das ganze jetzt mal als Patch geschickt, der nach meinen drei anderen applied werden kann. Hab gestern auch noch einen Router (WR841N v11) im "Produktiv-Einsatz" geflasht (WebUI per Remote), der seitdem auch problemlos läuft: https://monitoring.freifunk-franken.de/routers/58d662e49369c34df4bd7081 |
|
Status -> fixed. |
Date Modified | Username | Field | Change |
---|---|---|---|
2017-03-12 15:57 | ChristianD | New Issue | |
2017-05-26 14:15 | ChristianD | Note Added: 0000083 | |
2017-05-26 14:24 | ChristianD | File Added: l2tp_eth.c | |
2017-05-26 14:24 | ChristianD | Note Added: 0000084 | |
2017-05-26 15:06 | Adrian Schmutzler | Note Added: 0000085 | |
2017-05-26 16:28 | Adrian Schmutzler | Note Added: 0000086 | |
2017-05-26 17:02 | Adrian Schmutzler | Note Added: 0000087 | |
2017-05-27 18:15 | Adrian Schmutzler | Note Added: 0000088 | |
2017-05-27 19:18 | ChristianD | Note Added: 0000089 | |
2017-05-27 19:19 | ChristianD | Note Edited: 0000089 | |
2017-05-28 19:54 | Adrian Schmutzler | File Added: 0004-ar71xx-3.18-l2tp-stats.patch | |
2017-05-28 19:54 | Adrian Schmutzler | Note Added: 0000090 | |
2017-05-28 21:05 | ChristianD | Note Added: 0000091 | |
2017-05-28 21:06 | ChristianD | Note Edited: 0000091 | |
2017-05-28 21:11 | Adrian Schmutzler | Note Added: 0000092 | |
2017-05-29 15:21 | Adrian Schmutzler | Note Added: 0000094 | |
2017-06-03 00:01 | Adrian Schmutzler | Note Added: 0000100 | |
2017-06-04 08:36 | ChristianD | Status | new => resolved |
2017-06-04 08:36 | ChristianD | Resolution | open => fixed |
2017-06-04 08:37 | ChristianD | Status | resolved => closed |
2019-10-02 12:48 | fbl | Category | Freifunk Franken Firmware => General |
2019-10-02 12:48 | fbl | Category | General => General2 |
2019-10-02 12:49 | fbl | Category | General2 => General |