/****************************************************************************** * Simple allocator for Xen. If larger than a page, simply use the * page-order allocator. * * Copyright (C) 2005 Rusty Russell IBM Corporation * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * TODO (Keir, 17/2/05): * 1. Use space in pfn_info to avoid xmalloc_hdr in allocated blocks. * 2. pfn_info points into free list to make xfree() O(1) complexity. * 3. Perhaps make this a sub-page buddy allocator? xmalloc() == O(1). * (Disadvantage is potentially greater internal fragmentation). */ #include #include #include #include #include #include static LIST_HEAD(freelist); static spinlock_t freelist_lock = SPIN_LOCK_UNLOCKED; struct xmalloc_hdr { /* Total including this hdr. */ size_t size; struct list_head freelist; } __cacheline_aligned; static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block) { struct xmalloc_hdr *extra; size_t leftover = block - size; /* If enough is left to make a block, put it on free list. */ if ( leftover >= (2 * sizeof(struct xmalloc_hdr)) ) { extra = (struct xmalloc_hdr *)((unsigned long)hdr + size); extra->size = leftover; list_add(&extra->freelist, &freelist); } else { size = block; } hdr->size = size; /* Debugging aid. */ hdr->freelist.next = hdr->freelist.prev = NULL; } static void *xmalloc_new_page(size_t size) { struct xmalloc_hdr *hdr; unsigned long flags; hdr = (struct xmalloc_hdr *)alloc_xenheap_pages(0); if ( hdr == NULL ) return NULL; spin_lock_irqsave(&freelist_lock, flags); maybe_split(hdr, size, PAGE_SIZE); spin_unlock_irqrestore(&freelist_lock, flags); return hdr+1; } /* Big object? Just use the page allocator. */ static void *xmalloc_whole_pages(size_t size) { struct xmalloc_hdr *hdr; unsigned int pageorder = get_order(size); hdr = (struct xmalloc_hdr *)alloc_xenheap_pages(pageorder); if ( hdr == NULL ) return NULL; hdr->size = (1 << (pageorder + PAGE_SHIFT)); /* Debugging aid. */ hdr->freelist.next = hdr->freelist.prev = NULL; return hdr+1; } /* Return size, increased to alignment with align. */ static inline size_t align_up(size_t size, size_t align) { return (size + align - 1) & ~(align - 1); } void *_xmalloc(size_t size, size_t align) { struct xmalloc_hdr *i; unsigned long flags; /* We currently always return cacheline aligned. */ BUG_ON(align > SMP_CACHE_BYTES); /* Add room for header, pad to align next header. */ size += sizeof(struct xmalloc_hdr); size = align_up(size, __alignof__(struct xmalloc_hdr)); /* For big allocs, give them whole pages. */ if ( size >= PAGE_SIZE ) return xmalloc_whole_pages(size); /* Search free list. */ spin_lock_irqsave(&freelist_lock, flags); list_for_each_entry( i, &freelist, freelist ) { if ( i->size < size ) continue; list_del(&i->freelist); maybe_split(i, size, i->size); spin_unlock_irqrestore(&freelist_lock, flags); return i+1; } spin_unlock_irqrestore(&freelist_lock, flags); /* Alloc a new page and return from that. */ return xmalloc_new_page(size); } void xfree(const void *p) { unsigned long flags; struct xmalloc_hdr *i, *tmp, *hdr; if ( p == NULL ) return; hdr = (struct xmalloc_hdr *)p - 1; /* We know hdr will be on same page. */ BUG_ON(((long)p & PAGE_MASK) != ((long)hdr & PAGE_MASK)); /* Not previously freed. */ BUG_ON(hdr->freelist.next || hdr->freelist.prev); /* Big allocs free directly. */ if ( hdr->size >= PAGE_SIZE ) { free_xenheap_pages((unsigned long)hdr, get_order(hdr->size)); return; } /* Merge with other free block, or put in list. */ spin_lock_irqsave(&freelist_lock, flags); list_for_each_entry_safe( i, tmp, &freelist, freelist ) { unsigned long _i = (unsigned long)i; unsigned long _hdr = (unsigned long)hdr; /* Do not merge across page boundaries. */ if ( ((_i ^ _hdr) & PAGE_MASK) != 0 ) continue; /* We follow this block? Swallow it. */ if ( (_i + i->size) == _hdr ) { list_del(&i->freelist); i->size += hdr->size; hdr = i; } /* We precede this block? Swallow it. */ if ( (_hdr + hdr->size) == _i ) { list_del(&i->freelist); hdr->size += i->size; } } /* Did we merge an entire page? */ if ( hdr->size == PAGE_SIZE ) { BUG_ON((((unsigned long)hdr) & (PAGE_SIZE-1)) != 0); free_xenheap_pages((unsigned long)hdr, 0); } else { list_add(&hdr->freelist, &freelist); } spin_unlock_irqrestore(&freelist_lock, flags); } /* * Local variables: * mode: C * c-set-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */ id='n55' href='#n55'>55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/*
 * netlink-local.h		Local Netlink Interface
 *
 *	This library is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU Lesser General Public
 *	License as published by the Free Software Foundation version 2.1
 *	of the License.
 *
 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
 */

#ifndef NETLINK_LOCAL_H_
#define NETLINK_LOCAL_H_
#define _GNU_SOURCE

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <inttypes.h>
#include <assert.h>
#include <limits.h>

#include <arpa/inet.h>
#include <netdb.h>

#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif

#include <linux/types.h>

/* local header copies */
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/pkt_sched.h>
#include <linux/pkt_cls.h>
#include <linux/gen_stats.h>

#include <netlink/netlink.h>
#include <netlink/handlers.h>
#include <netlink/cache.h>
#include <netlink/object-api.h>
#include <netlink/cache-api.h>
#include <netlink-types.h>

struct trans_tbl {
	int i;
	const char *a;
};

#define __ADD(id, name) { .i = id, .a = #name },

struct trans_list {
	int i;
	char *a;
	struct nl_list_head list;
};

#define NL_DEBUG	1

#define NL_DBG(LVL,FMT,ARG...) \
	do {} while (0)

#define BUG()                            \
	do {                                 \
		fprintf(stderr, "BUG: %s:%d\n",  \
			__FILE__, __LINE__);         \
		assert(0);	\
	} while (0)

extern int __nl_read_num_str_file(const char *path,
				  int (*cb)(long, const char *));

extern int __trans_list_add(int, const char *, struct nl_list_head *);
extern void __trans_list_clear(struct nl_list_head *);

extern char *__type2str(int, char *, size_t, struct trans_tbl *, size_t);
extern int __str2type(const char *, struct trans_tbl *, size_t);

extern char *__list_type2str(int, char *, size_t, struct nl_list_head *);
extern int __list_str2type(const char *, struct nl_list_head *);

extern char *__flags2str(int, char *, size_t, struct trans_tbl *, size_t);
extern int __str2flags(const char *, struct trans_tbl *, size_t);

extern void dump_from_ops(struct nl_object *, struct nl_dump_params *);

static inline struct nl_cache *dp_cache(struct nl_object *obj)
{
	if (obj->ce_cache == NULL)
		return nl_cache_mngt_require(obj->ce_ops->oo_name);

	return obj->ce_cache;
}

static inline int nl_cb_call(struct nl_cb *cb, int type, struct nl_msg *msg)
{
	return cb->cb_set[type](msg, cb->cb_args[type]);
}

#define ARRAY_SIZE(X) (sizeof(X) / sizeof((X)[0]))
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#define __init __attribute__ ((constructor))
#define __exit __attribute__ ((destructor))
#undef __deprecated
#define __deprecated __attribute__ ((deprecated))

#define min(x,y) ({ \
	typeof(x) _x = (x);	\
	typeof(y) _y = (y);	\
	(void) (&_x == &_y);		\
	_x < _y ? _x : _y; })

#define max(x,y) ({ \
	typeof(x) _x = (x);	\
	typeof(y) _y = (y);	\
	(void) (&_x == &_y);		\
	_x > _y ? _x : _y; })

extern int nl_cache_parse(struct nl_cache_ops *, struct sockaddr_nl *,
			  struct nlmsghdr *, struct nl_parser_param *);


static inline char *nl_cache_name(struct nl_cache *cache)
{
	return cache->c_ops ? cache->c_ops->co_name : "unknown";
}

#define GENL_FAMILY(id, name) \
	{ \
		{ id, NL_ACT_UNSPEC, name }, \
		END_OF_MSGTYPES_LIST, \
	}

static inline int wait_for_ack(struct nl_sock *sk)
{
	if (sk->s_flags & NL_NO_AUTO_ACK)
		return 0;
	else
		return nl_wait_for_ack(sk);
}

#endif