From 3644f0cee77494190452de132e82245107939284 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 7 Dec 2006 15:08:17 -0800 Subject: [NET]: Convert hh_lock to seqlock. The hard header cache is in the main output path, so using seqlock instead of reader/writer lock should reduce overhead. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- include/net/neighbour.h | 18 ++++++++++++++++++ net/core/neighbour.c | 11 ++++++----- net/ipv4/ip_output.c | 14 +++----------- net/ipv6/ip6_output.c | 17 ++++------------- 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c57088f..631cec4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -199,7 +199,7 @@ struct hh_cache */ u16 hh_len; /* length of header */ int (*hh_output)(struct sk_buff *skb); - rwlock_t hh_lock; + seqlock_t hh_lock; /* cached hardware header; allow for machine alignment needs. */ #define HH_DATA_MOD 16 diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 2396703..3725b93 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -309,6 +309,24 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) return 0; } +static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb) +{ + unsigned seq; + int hh_len; + + do { + int hh_alen; + + seq = read_seqbegin(&hh->hh_lock); + hh_len = hh->hh_len; + hh_alen = HH_DATA_ALIGN(hh_len); + memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); + } while (read_seqretry(&hh->hh_lock, seq)); + + skb_push(skb, hh_len); + return hh->hh_output(skb); +} + static inline struct neighbour * __neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) { diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 0ab1987..e7300b6 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh) while ((hh = neigh->hh) != NULL) { neigh->hh = hh->hh_next; hh->hh_next = NULL; - write_lock_bh(&hh->hh_lock); + + write_seqlock_bh(&hh->hh_lock); hh->hh_output = neigh_blackhole; - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); if (atomic_dec_and_test(&hh->hh_refcnt)) kfree(hh); } @@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh) if (update) { for (hh = neigh->hh; hh; hh = hh->hh_next) { - write_lock_bh(&hh->hh_lock); + write_seqlock_bh(&hh->hh_lock); update(hh, neigh->dev, neigh->ha); - write_unlock_bh(&hh->hh_lock); + write_sequnlock_bh(&hh->hh_lock); } } } @@ -1089,7 +1090,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, break; if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { - rwlock_init(&hh->hh_lock); + seqlock_init(&hh->hh_lock); hh->hh_type = protocol; atomic_set(&hh->hh_refcnt, 0); hh->hh_next = NULL; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a35209d..f071f84 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); static inline int ip_finish_output2(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; struct net_device *dev = dst->dev; int hh_len = LL_RESERVED_SPACE(dev); @@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); if (net_ratelimit()) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e9212c7..7b7bd44 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f static inline int ip6_output_finish(struct sk_buff *skb) { - struct dst_entry *dst = skb->dst; - struct hh_cache *hh = dst->hh; - - if (hh) { - int hh_alen; - - read_lock_bh(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(hh->hh_len); - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - read_unlock_bh(&hh->hh_lock); - skb_push(skb, hh->hh_len); - return hh->hh_output(skb); - } else if (dst->neighbour) + + if (dst->hh) + return neigh_hh_output(dst->hh, skb); + else if (dst->neighbour) return dst->neighbour->output(skb); IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); -- cgit v1.1 From 6c1bbcc8836358294c431e0c09e85e3480895659 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 7 Dec 2006 15:10:06 -0800 Subject: [BNX2]: Add an error check. This patch adds a missing error check spotted by the Coverity checker. Signed-off-by: Adrian Bunk Acked-by: Jeff Garzik Acked-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 5bacb75..7d824cf 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -2510,7 +2510,7 @@ bnx2_init_cpus(struct bnx2 *bp) if (CHIP_NUM(bp) == CHIP_NUM_5709) { fw = &bnx2_cp_fw_09; - load_cpu_fw(bp, &cpu_reg, fw); + rc = load_cpu_fw(bp, &cpu_reg, fw); if (rc) goto init_cpu_err; } -- cgit v1.1 From e8cc49bb0fdb9e18a99e6780073d1400ba2b0d1f Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 7 Dec 2006 15:43:13 -0800 Subject: [AX.25]: Constify ax25 utility functions Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- include/net/ax25.h | 18 ++++++++++-------- net/ax25/ax25_addr.c | 19 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/net/ax25.h b/include/net/ax25.h index 69374cd..41acb09 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -283,14 +283,16 @@ extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); /* ax25_addr.c */ extern ax25_address null_ax25_address; -extern char *ax2asc(char *buf, ax25_address *); -extern void asc2ax(ax25_address *addr, char *callsign); -extern int ax25cmp(ax25_address *, ax25_address *); -extern int ax25digicmp(ax25_digi *, ax25_digi *); -extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *); -extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int); -extern int ax25_addr_size(ax25_digi *); -extern void ax25_digi_invert(ax25_digi *, ax25_digi *); +extern char *ax2asc(char *buf, const ax25_address *); +extern void asc2ax(ax25_address *addr, const char *callsign); +extern int ax25cmp(const ax25_address *, const ax25_address *); +extern int ax25digicmp(const ax25_digi *, const ax25_digi *); +extern const unsigned char *ax25_addr_parse(const unsigned char *, int, + ax25_address *, ax25_address *, ax25_digi *, int *, int *); +extern int ax25_addr_build(unsigned char *, const ax25_address *, + const ax25_address *, const ax25_digi *, int, int); +extern int ax25_addr_size(const ax25_digi *); +extern void ax25_digi_invert(const ax25_digi *, ax25_digi *); /* ax25_dev.c */ extern ax25_dev *ax25_dev_list; diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 5f0896a..5524f9c 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -39,7 +39,7 @@ EXPORT_SYMBOL(null_ax25_address); /* * ax25 -> ascii conversion */ -char *ax2asc(char *buf, ax25_address *a) +char *ax2asc(char *buf, const ax25_address *a) { char c, *s; int n; @@ -72,7 +72,7 @@ EXPORT_SYMBOL(ax2asc); /* * ascii -> ax25 conversion */ -void asc2ax(ax25_address *addr, char *callsign) +void asc2ax(ax25_address *addr, const char *callsign) { char *s; int n; @@ -107,7 +107,7 @@ EXPORT_SYMBOL(asc2ax); /* * Compare two ax.25 addresses */ -int ax25cmp(ax25_address *a, ax25_address *b) +int ax25cmp(const ax25_address *a, const ax25_address *b) { int ct = 0; @@ -128,7 +128,7 @@ EXPORT_SYMBOL(ax25cmp); /* * Compare two AX.25 digipeater paths. */ -int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) +int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2) { int i; @@ -149,7 +149,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) * Given an AX.25 address pull of to, from, digi list, command/response and the start of data * */ -unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) +const unsigned char *ax25_addr_parse(const unsigned char *buf, int len, + ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, + int *dama) { int d = 0; @@ -204,7 +206,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a /* * Assemble an AX.25 header from the bits */ -int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) +int ax25_addr_build(unsigned char *buf, const ax25_address *src, + const ax25_address *dest, const ax25_digi *d, int flag, int modulus) { int len = 0; int ct = 0; @@ -261,7 +264,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a return len; } -int ax25_addr_size(ax25_digi *dp) +int ax25_addr_size(const ax25_digi *dp) { if (dp == NULL) return 2 * AX25_ADDR_LEN; @@ -272,7 +275,7 @@ int ax25_addr_size(ax25_digi *dp) /* * Reverse Digipeat List. May not pass both parameters as same struct */ -void ax25_digi_invert(ax25_digi *in, ax25_digi *out) +void ax25_digi_invert(const ax25_digi *in, ax25_digi *out) { int ct; -- cgit v1.1 From 15b1c0e822f578306332d4f4c449250db5c5dceb Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 7 Dec 2006 15:47:08 -0800 Subject: [AX.25]: Fix default address and broadcast address initialization. Only the callsign but not the SSID part of an AX.25 address is ASCII based but Linux by initializes the SSID which should be just a 4-bit number from ASCII anyway. Fix that and convert the code to use a shared constant for both default addresses. While at it, use the same style for null_ax25_address also. Signed-off-by: Ralf Baechle Signed-off-by: David S. Miller --- drivers/net/hamradio/6pack.c | 9 ++------- drivers/net/hamradio/baycom_epp.c | 10 ++-------- drivers/net/hamradio/bpqether.c | 9 ++------- drivers/net/hamradio/dmascc.c | 10 ++-------- drivers/net/hamradio/hdlcdrv.c | 16 ++-------------- drivers/net/hamradio/mkiss.c | 9 ++------- drivers/net/hamradio/scc.c | 9 ++------- drivers/net/hamradio/yam.c | 9 ++------- include/net/ax25.h | 6 +++--- net/ax25/ax25_addr.c | 15 ++++++++++++--- 10 files changed, 31 insertions(+), 71 deletions(-) diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 92420f0..760d04a6 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -325,11 +325,6 @@ static int sp_rebuild_header(struct sk_buff *skb) static void sp_setup(struct net_device *dev) { - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; - /* Finish setting up the DEVICE info. */ dev->mtu = SIXP_MTU; dev->hard_start_xmit = sp_xmit; @@ -347,8 +342,8 @@ static void sp_setup(struct net_device *dev) dev->tx_timeout = NULL; /* Only activated in AX.25 mode */ - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); SET_MODULE_OWNER(dev); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 3c33d6f..8a83db0 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -1141,12 +1141,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) */ static void baycom_probe(struct net_device *dev) { - static char ax25_bcast[AX25_ADDR_LEN] = { - 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1 - }; - static char ax25_nocall[AX25_ADDR_LEN] = { - 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1 - }; const struct hdlcdrv_channel_params dflt_ch_params = { 20, 2, 10, 40, 0 }; @@ -1182,8 +1176,8 @@ static void baycom_probe(struct net_device *dev) dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_nocall, AX25_ADDR_LEN); dev->tx_queue_len = 16; /* New style flags */ diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 889f338..5b788d8 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -88,11 +88,6 @@ static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n"; -static unsigned char ax25_bcast[AX25_ADDR_LEN] = - {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static unsigned char ax25_defaddr[AX25_ADDR_LEN] = - {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; static char bpq_eth_addr[6]; @@ -487,8 +482,8 @@ static void bpq_setup(struct net_device *dev) dev->do_ioctl = bpq_ioctl; dev->destructor = free_netdev; - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); dev->flags = 0; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index e6e721a..0fbb414 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -264,12 +264,6 @@ static int io[MAX_NUM_DEVS] __initdata = { 0, }; /* Beware! hw[] is also used in cleanup_module(). */ static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; -static char ax25_broadcast[7] __initdata = - { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, -'0' << 1 }; -static char ax25_test[7] __initdata = - { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, -'1' << 1 }; /* Global variables */ @@ -443,8 +437,8 @@ static void __init dev_setup(struct net_device *dev) dev->mtu = 1500; dev->addr_len = AX25_ADDR_LEN; dev->tx_queue_len = 64; - memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); } static int __init setup_adapter(int card_base, int type, int n) diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index dacc768..452873e 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -63,18 +63,6 @@ /* --------------------------------------------------------------------- */ -/* - * The name of the card. Is used for messages and in the requests for - * io regions, irqs and dma channels - */ - -static char ax25_bcast[AX25_ADDR_LEN] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_nocall[AX25_ADDR_LEN] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - -/* --------------------------------------------------------------------- */ - #define KISS_VERBOSE /* --------------------------------------------------------------------- */ @@ -709,8 +697,8 @@ static void hdlcdrv_setup(struct net_device *dev) dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); dev->tx_queue_len = 16; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index d8715b2..d08fbc3 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -672,11 +672,6 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev) static void ax_setup(struct net_device *dev) { - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; - /* Finish setting up the DEVICE info. */ dev->mtu = AX_MTU; dev->hard_start_xmit = ax_xmit; @@ -691,8 +686,8 @@ static void ax_setup(struct net_device *dev) dev->hard_header = ax_header; dev->rebuild_header = ax_rebuild_header; - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); dev->flags = IFF_BROADCAST | IFF_MULTICAST; } diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index ec9b6d9..2ce047e 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1540,11 +1540,6 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc) /* * Network driver methods * */ /* ******************************************************************** */ -static unsigned char ax25_bcast[AX25_ADDR_LEN] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static unsigned char ax25_nocall[AX25_ADDR_LEN] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - /* ----> Initialize device <----- */ static void scc_net_setup(struct net_device *dev) @@ -1562,8 +1557,8 @@ static void scc_net_setup(struct net_device *dev) dev->do_ioctl = scc_net_ioctl; dev->tx_timeout = NULL; - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); dev->flags = 0; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 3c4455b..6d74f08 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -156,11 +156,6 @@ static struct net_device *yam_devs[NR_PORTS]; static struct yam_mcs *yam_data; -static char ax25_bcast[7] = -{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1}; -static char ax25_test[7] = -{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1}; - static DEFINE_TIMER(yam_timer, NULL, 0, 0); /* --------------------------------------------------------------------- */ @@ -1115,8 +1110,8 @@ static void yam_setup(struct net_device *dev) dev->hard_header_len = AX25_MAX_HEADER_LEN; dev->mtu = AX25_MTU; dev->addr_len = AX25_ADDR_LEN; - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN); } static int __init yam_init_driver(void) diff --git a/include/net/ax25.h b/include/net/ax25.h index 41acb09..e1d116f 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -282,9 +282,9 @@ extern void ax25_fillin_cb(ax25_cb *, ax25_dev *); extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); /* ax25_addr.c */ -extern ax25_address null_ax25_address; -extern char *ax2asc(char *buf, const ax25_address *); -extern void asc2ax(ax25_address *addr, const char *callsign); +extern const ax25_address ax25_bcast; +extern const ax25_address ax25_defaddr; +extern const ax25_address null_ax25_address; extern int ax25cmp(const ax25_address *, const ax25_address *); extern int ax25digicmp(const ax25_digi *, const ax25_digi *); extern const unsigned char *ax25_addr_parse(const unsigned char *, int, diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c index 5524f9c..21a0616 100644 --- a/net/ax25/ax25_addr.c +++ b/net/ax25/ax25_addr.c @@ -29,11 +29,20 @@ #include /* - * The null address is defined as a callsign of all spaces with an - * SSID of zero. + * The default broadcast address of an interface is QST-0; the default address + * is LINUX-1. The null address is defined as a callsign of all spaces with + * an SSID of zero. */ -ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; +const ax25_address ax25_bcast = + {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; +const ax25_address ax25_defaddr = + {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}}; +const ax25_address null_ax25_address = + {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}}; + +EXPORT_SYMBOL_GPL(ax25_bcast); +EXPORT_SYMBOL_GPL(ax25_defaddr); EXPORT_SYMBOL(null_ax25_address); /* -- cgit v1.1 From e07bca84cd9d31f76ed655d51e68b6a0ca15f162 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 7 Dec 2006 23:49:45 -0800 Subject: [NETLINK]: Restore API compatibility of address and neighbour bits Restore API compatibility due to bits moved from rtnetlink.h to separate headers. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 493297a..4a629ea 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -3,6 +3,8 @@ #include #include +#include +#include /**** * Routing/neighbour discovery messages. -- cgit v1.1 From 47bbec0282cce900f16a8dd6397260e076400edb Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 8 Dec 2006 00:05:55 -0800 Subject: [NETPOLL]: make arp replies through netpoll use mac address of sender Back in 2.4 arp requests that were recevied by netpoll were processed in netconsole_receive_skb, where they were responded to using the src mac of the request sender. In the 2.6 kernel arp_reply is responsible for this function, but instead of using the src mac address of the incomming request, the stored mac address that was registered for the netconsole application is used. While this is usually ok, it can lead to failures in netpoll in some situations (specifically situations where a network may have two gateways, as arp requests from one may be responded to using the mac address of the other). This patch reverts the behavior to what we had in 2.4, in which all arp requests are sent back using the src address of the request sender. Signed-off-by: Neil Horman Acked-by: Chris Lalancette Signed-off-by: David S. Miller --- net/core/netpoll.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index b3c559b..8a27128 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -330,6 +330,7 @@ static void arp_reply(struct sk_buff *skb) unsigned char *arp_ptr; int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; __be32 sip, tip; + unsigned char *sha; struct sk_buff *send_skb; struct netpoll *np = NULL; @@ -356,9 +357,14 @@ static void arp_reply(struct sk_buff *skb) arp->ar_op != htons(ARPOP_REQUEST)) return; - arp_ptr = (unsigned char *)(arp+1) + skb->dev->addr_len; + arp_ptr = (unsigned char *)(arp+1); + /* save the location of the src hw addr */ + sha = arp_ptr; + arp_ptr += skb->dev->addr_len; memcpy(&sip, arp_ptr, 4); - arp_ptr += 4 + skb->dev->addr_len; + arp_ptr += 4; + /* if we actually cared about dst hw addr, it would get copied here */ + arp_ptr += skb->dev->addr_len; memcpy(&tip, arp_ptr, 4); /* Should we ignore arp? */ @@ -381,7 +387,7 @@ static void arp_reply(struct sk_buff *skb) if (np->dev->hard_header && np->dev->hard_header(send_skb, skb->dev, ptype, - np->remote_mac, np->local_mac, + sha, np->local_mac, send_skb->len) < 0) { kfree_skb(send_skb); return; @@ -405,7 +411,7 @@ static void arp_reply(struct sk_buff *skb) arp_ptr += np->dev->addr_len; memcpy(arp_ptr, &tip, 4); arp_ptr += 4; - memcpy(arp_ptr, np->remote_mac, np->dev->addr_len); + memcpy(arp_ptr, sha, np->dev->addr_len); arp_ptr += np->dev->addr_len; memcpy(arp_ptr, &sip, 4); -- cgit v1.1 From f0490980a152958d25ce9762bfb296d8fd4c5512 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 8 Dec 2006 00:08:43 -0800 Subject: [NET]: Force a cache line split in hh_cache in SMP. hh_lock was converted from rwlock to seqlock by Stephen. To have a 100% benefit of this change, I suggest to place read mostly fields of hh_cache in a separate cache line, because hh_refcnt may be changed quite frequently on some busy machines. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 631cec4..6be767c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -193,7 +193,14 @@ struct hh_cache { struct hh_cache *hh_next; /* Next entry */ atomic_t hh_refcnt; /* number of users */ - __be16 hh_type; /* protocol identifier, f.e ETH_P_IP +/* + * We want hh_output, hh_len, hh_lock and hh_data be a in a separate + * cache line on SMP. + * They are mostly read, but hh_refcnt may be changed quite frequently, + * incurring cache line ping pongs. + */ + __be16 hh_type ____cacheline_aligned_in_smp; + /* protocol identifier, f.e ETH_P_IP * NOTE: For VLANs, this will be the * encapuslated type. --BLG */ -- cgit v1.1 From 93366c537b3426261cac4db27acc10a99cd91b06 Mon Sep 17 00:00:00 2001 From: J Hadi Salim Date: Fri, 8 Dec 2006 00:12:15 -0800 Subject: [XFRM]: Fix XFRMGRP_REPORT to use correct multicast group. XFRMGRP_REPORT uses 0x10 which is a group that belongs to events. The correct value is 0x20. We should really be using xfrm_nlgroups going forward; it was tempting to delete the definition of XFRMGRP_REPORT but it would break at least iproute2. Signed-off-by: J Hadi Salim Signed-off-by: David S. Miller --- include/linux/xfrm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 088ba81..9529ea1 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -357,7 +357,7 @@ struct xfrm_user_report { #define XFRMGRP_EXPIRE 2 #define XFRMGRP_SA 4 #define XFRMGRP_POLICY 8 -#define XFRMGRP_REPORT 0x10 +#define XFRMGRP_REPORT 0x20 #endif enum xfrm_nlgroups { -- cgit v1.1 From a37ef2e3258d65e43ec876233bba0b288a9d3260 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 8 Dec 2006 00:25:55 -0800 Subject: [NET_SCHED] sch_cbq: deactivating when grafting, purging etc. - deactivating of active classes when q.qlen drops to zero (cbq_drop) - a redundant instruction removed from cbq_deactivate_class PS: probably htb_deactivate in htb_delete and cbq_deactivate_class in cbq_delete are also redundant now. Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/sch_cbq.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index ba82dfa..f79a4f3 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -371,8 +371,6 @@ static void cbq_deactivate_class(struct cbq_class *this) return; } } - - cl = cl_prev->next_alive; return; } } while ((cl_prev = cl) != q->active[prio]); @@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch) do { if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) { sch->q.qlen--; + if (!cl->q->q.qlen) + cbq_deactivate_class(cl); return len; } } while ((cl = cl->next_alive) != cl_head); @@ -1685,8 +1685,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, #endif } sch_tree_lock(sch); - *old = cl->q; - cl->q = new; + *old = xchg(&cl->q, new); qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg) return cl ? cl->q : NULL; } +static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg) +{ + struct cbq_class *cl = (struct cbq_class *)arg; + + if (cl->q->q.qlen == 0) + cbq_deactivate_class(cl); +} + static unsigned long cbq_get(struct Qdisc *sch, u32 classid) { struct cbq_sched_data *q = qdisc_priv(sch); @@ -1988,12 +1995,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg) { struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_class *cl = (struct cbq_class*)arg; + unsigned int qlen; if (cl->filters || cl->children || cl == &q->link) return -EBUSY; sch_tree_lock(sch); + qlen = cl->q->q.qlen; + qdisc_reset(cl->q); + qdisc_tree_decrease_qlen(cl->q, qlen); + if (cl->next_alive) cbq_deactivate_class(cl); @@ -2084,6 +2096,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg) static struct Qdisc_class_ops cbq_class_ops = { .graft = cbq_graft, .leaf = cbq_leaf, + .qlen_notify = cbq_qlen_notify, .get = cbq_get, .put = cbq_put, .change = cbq_change_class, -- cgit v1.1 From 160d5e10f87b1dc88fd9b84b31b1718e0fd76398 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Fri, 8 Dec 2006 00:26:56 -0800 Subject: [NET_SCHED] sch_htb: turn intermediate classes into leaves - turn intermediate classes into leaves again when their last child is deleted (struct htb_class changed) Signed-off-by: Jarek Poplawski Signed-off-by: David S. Miller --- net/sched/sch_htb.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index 215e68c..15f23c5 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -147,6 +147,10 @@ struct htb_class { psched_tdiff_t mbuffer; /* max wait time */ long tokens, ctokens; /* current number of tokens */ psched_time_t t_c; /* checkpoint time */ + + int prio; /* For parent to leaf return possible here */ + int quantum; /* we do backup. Finally full replacement */ + /* of un.leaf originals should be done. */ }; /* TODO: maybe compute rate when size is too large .. or drop ? */ @@ -1271,6 +1275,38 @@ static void htb_destroy_filters(struct tcf_proto **fl) } } +static inline int htb_parent_last_child(struct htb_class *cl) +{ + if (!cl->parent) + /* the root class */ + return 0; + + if (!(cl->parent->children.next == &cl->sibling && + cl->parent->children.prev == &cl->sibling)) + /* not the last child */ + return 0; + + return 1; +} + +static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q) +{ + struct htb_class *parent = cl->parent; + + BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity); + + parent->level = 0; + memset(&parent->un.inner, 0, sizeof(parent->un.inner)); + INIT_LIST_HEAD(&parent->un.leaf.drop_list); + parent->un.leaf.q = new_q ? new_q : &noop_qdisc; + parent->un.leaf.quantum = parent->quantum; + parent->un.leaf.prio = parent->prio; + parent->tokens = parent->buffer; + parent->ctokens = parent->cbuffer; + PSCHED_GET_TIME(parent->t_c); + parent->cmode = HTB_CAN_SEND; +} + static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) { struct htb_sched *q = qdisc_priv(sch); @@ -1328,6 +1364,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = (struct htb_class *)arg; unsigned int qlen; + struct Qdisc *new_q = NULL; + int last_child = 0; // TODO: why don't allow to delete subtree ? references ? does // tc subsys quarantee us that in htb_destroy it holds no class @@ -1335,6 +1373,12 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) if (!list_empty(&cl->children) || cl->filter_cnt) return -EBUSY; + if (!cl->level && htb_parent_last_child(cl)) { + new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops, + cl->parent->classid); + last_child = 1; + } + sch_tree_lock(sch); /* delete from hash and active; remainder in destroy_class */ @@ -1349,6 +1393,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg) if (cl->prio_activity) htb_deactivate(q, cl); + if (last_child) + htb_parent_to_leaf(cl, new_q); + if (--cl->refcnt == 0) htb_destroy_class(sch, cl); @@ -1483,6 +1530,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, cl->un.leaf.quantum = hopt->quantum; if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO) cl->un.leaf.prio = TC_HTB_NUMPRIO - 1; + + /* backup for htb_parent_to_leaf */ + cl->quantum = cl->un.leaf.quantum; + cl->prio = cl->un.leaf.prio; } cl->buffer = hopt->buffer; -- cgit v1.1 From d3dcc077bf88806201093f86325ec656e4dbfbce Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 8 Dec 2006 17:05:13 -0800 Subject: [NETLINK]: Put {IFA,IFLA}_{RTA,PAYLOAD} macros back for userspace. GLIBC uses them etc. They are guarded by ifndef __KERNEL__ so nobody will start accidently using them in the kernel again, it's just for userspace. Signed-off-by: David S. Miller --- include/linux/if_addr.h | 6 ++++++ include/linux/if_link.h | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h index dbe8f61..d557e4c 100644 --- a/include/linux/if_addr.h +++ b/include/linux/if_addr.h @@ -52,4 +52,10 @@ struct ifa_cacheinfo __u32 tstamp; /* updated timestamp, hundredths of seconds */ }; +/* backwards compatibility for userspace */ +#ifndef __KERNEL__ +#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) +#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) +#endif + #endif diff --git a/include/linux/if_link.h b/include/linux/if_link.h index e963a07..35ed3b5 100644 --- a/include/linux/if_link.h +++ b/include/linux/if_link.h @@ -82,6 +82,12 @@ enum #define IFLA_MAX (__IFLA_MAX - 1) +/* backwards compatibility for userspace */ +#ifndef __KERNEL__ +#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) +#endif + /* ifi_flags. IFF_* flags. -- cgit v1.1