Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6b72b62 authored by David S. Miller's avatar David S. Miller
Browse files

net: Embed hh_cache inside of struct neighbour.



Now that there is a one-to-one correspondance between neighbour
and hh_cache entries, we no longer need:

1) dynamic allocation
2) attachment to dst->hh
3) refcounting

Initialization of the hh_cache entry is indicated by hh_len
being non-zero, and such initialization is always done with
the neighbour's lock held as a writer.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 390fd0b3
Loading
Loading
Loading
Loading
+1 −14
Original line number Diff line number Diff line
@@ -252,14 +252,7 @@ struct netdev_hw_addr_list {
	netdev_hw_addr_list_for_each(ha, &(dev)->mc)

struct hh_cache {
	atomic_t	hh_refcnt;	/* number of users                   */
/*
 * 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.
 */
	u16		hh_len ____cacheline_aligned_in_smp;
	u16		hh_len;
	u16		__pad;
	int		(*hh_output)(struct sk_buff *skb);
	seqlock_t	hh_lock;
@@ -273,12 +266,6 @@ struct hh_cache {
	unsigned long	hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)];
};

static inline void hh_cache_put(struct hh_cache *hh)
{
	if (atomic_dec_and_test(&hh->hh_refcnt))
		kfree(hh);
}

/* Reserve HH_DATA_MOD byte aligned hard_header_len, but at least that much.
 * Alternative is:
 *   dev->hard_header_len ? (dev->hard_header_len +
+9 −9
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ struct dst_entry {
	unsigned long		expires;
	struct dst_entry	*path;
	struct neighbour	*neighbour;
	struct hh_cache		*hh;
#ifdef CONFIG_XFRM
	struct xfrm_state	*xfrm;
#else
@@ -47,6 +46,14 @@ struct dst_entry {
	int			(*input)(struct sk_buff*);
	int			(*output)(struct sk_buff*);

	int			flags;
#define DST_HOST		0x0001
#define DST_NOXFRM		0x0002
#define DST_NOPOLICY		0x0004
#define DST_NOHASH		0x0008
#define DST_NOCACHE		0x0010
#define DST_NOCOUNT		0x0020

	short			error;
	short			obsolete;
	unsigned short		header_len;	/* more space at head required */
@@ -62,7 +69,7 @@ struct dst_entry {
	 * (L1_CACHE_SIZE would be too much)
	 */
#ifdef CONFIG_64BIT
	long			__pad_to_align_refcnt[1];
	long			__pad_to_align_refcnt[2];
#endif
	/*
	 * __refcnt wants to be on a different cache line from
@@ -71,13 +78,6 @@ struct dst_entry {
	atomic_t		__refcnt;	/* client references	*/
	int			__use;
	unsigned long		lastuse;
	int			flags;
#define DST_HOST		0x0001
#define DST_NOXFRM		0x0002
#define DST_NOPOLICY		0x0004
#define DST_NOHASH		0x0008
#define DST_NOCACHE		0x0010
#define DST_NOCOUNT		0x0020
	union {
		struct dst_entry	*next;
		struct rtable __rcu	*rt_next;
+1 −1
Original line number Diff line number Diff line
@@ -108,7 +108,7 @@ struct neighbour {
	__u8			dead;
	seqlock_t		ha_lock;
	unsigned char		ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
	struct hh_cache		*hh;
	struct hh_cache		hh;
	int			(*output)(struct sk_buff *skb);
	const struct neigh_ops	*ops;
	struct rcu_head		rcu;
+4 −2
Original line number Diff line number Diff line
@@ -343,14 +343,16 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb)
static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb)
{
	struct nf_bridge_info *nf_bridge = skb->nf_bridge;
	struct neighbour *neigh;
	struct dst_entry *dst;

	skb->dev = bridge_parent(skb->dev);
	if (!skb->dev)
		goto free_skb;
	dst = skb_dst(skb);
	if (dst->hh) {
		neigh_hh_bridge(dst->hh, skb);
	neigh = dst->neighbour;
	if (neigh->hh.hh_len) {
		neigh_hh_bridge(&neigh->hh, skb);
		skb->dev = nf_bridge->physindev;
		return br_handle_frame_finish(skb);
	} else if (dst->neighbour) {
+0 −7
Original line number Diff line number Diff line
@@ -172,7 +172,6 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
	dst->expires = 0UL;
	dst->path = dst;
	dst->neighbour = NULL;
	dst->hh = NULL;
#ifdef CONFIG_XFRM
	dst->xfrm = NULL;
#endif
@@ -226,19 +225,13 @@ struct dst_entry *dst_destroy(struct dst_entry * dst)
{
	struct dst_entry *child;
	struct neighbour *neigh;
	struct hh_cache *hh;

	smp_rmb();

again:
	neigh = dst->neighbour;
	hh = dst->hh;
	child = dst->child;

	dst->hh = NULL;
	if (hh)
		hh_cache_put(hh);

	if (neigh) {
		dst->neighbour = NULL;
		neigh_release(neigh);
Loading