This commit is contained in:
emellor@leeni.uk.xensource.com committed 2005-12-09 10:51:35 +00:00
commit 53dcf75ccb
26 files changed
+1097 -700

No files matched your search

+262 -260
View File
@@ -12,6 +12,8 @@
*/
#include <linux/spinlock.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <asm-xen/balloon.h>
#include <asm/hypervisor.h>
#include "common.h"
@@ -21,26 +23,26 @@
* pulled from a communication ring are quite likely to end up being part of
* the same scatter/gather request at the disc.
*
* ** TRY INCREASING 'MAX_PENDING_REQS' IF WRITE SPEEDS SEEM TOO LOW **
* ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
*
* This will increase the chances of being able to write whole tracks.
* 64 should be enough to keep us competitive with Linux.
*/
#define MAX_PENDING_REQS 64
#define BATCH_PER_DOMAIN 16
static int blkif_reqs = 64;
static int mmap_pages;
static unsigned long mmap_vstart;
#define MMAP_PAGES \
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
#ifdef __ia64__
static void *pending_vaddrs[MMAP_PAGES];
#define MMAP_VADDR(_idx, _i) \
(unsigned long)(pending_vaddrs[((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)])
#else
#define MMAP_VADDR(_req,_seg) \
(mmap_vstart + \
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) + \
((_seg) * PAGE_SIZE))
#endif
static int __init set_blkif_reqs(char *str)
{
get_option(&str, &blkif_reqs);
return 1;
}
__setup("blkif_reqs=", set_blkif_reqs);
/* Run-time switchable: /sys/module/blkback/parameters/ */
static unsigned int log_stats = 0;
static unsigned int debug_lvl = 0;
module_param(log_stats, int, 0644);
module_param(debug_lvl, int, 0644);
/*
* Each outstanding request that we've passed to the lower device layers has a
@@ -55,43 +57,33 @@ typedef struct {
atomic_t pendcnt;
unsigned short operation;
int status;
struct list_head free_list;
} pending_req_t;
/*
* We can't allocate pending_req's in order, since they may complete out of
* order. We therefore maintain an allocation ring. This ring also indicates
* when enough work has been passed down -- at that point the allocation ring
* will be empty.
*/
static pending_req_t pending_reqs[MAX_PENDING_REQS];
static unsigned char pending_ring[MAX_PENDING_REQS];
static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
/* NB. We use a different index type to differentiate from shared blk rings. */
typedef unsigned int PEND_RING_IDX;
#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
static PEND_RING_IDX pending_prod, pending_cons;
#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
static pending_req_t *pending_reqs;
static struct list_head pending_free;
static spinlock_t pending_free_lock = SPIN_LOCK_UNLOCKED;
static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
static request_queue_t *plugged_queue;
static inline void flush_plugged_queue(void)
#define BLKBACK_INVALID_HANDLE (~0)
static unsigned long mmap_vstart;
static unsigned long *pending_vaddrs;
static grant_handle_t *pending_grant_handles;
static inline int vaddr_pagenr(pending_req_t *req, int seg)
{
request_queue_t *q = plugged_queue;
if (q != NULL) {
if ( q->unplug_fn != NULL )
q->unplug_fn(q);
blk_put_queue(q);
plugged_queue = NULL;
}
return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
}
/* When using grant tables to map a frame for device access then the
* handle returned must be used to unmap the frame. This is needed to
* drop the ref count on the frame.
*/
static grant_handle_t pending_grant_handles[MMAP_PAGES];
#define pending_handle(_idx, _i) \
(pending_grant_handles[((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) + (_i)])
#define BLKBACK_INVALID_HANDLE (~0)
static inline unsigned long vaddr(pending_req_t *req, int seg)
{
return pending_vaddrs[vaddr_pagenr(req, seg)];
}
#define pending_handle(_req, _seg) \
(pending_grant_handles[vaddr_pagenr(_req, _seg)])
#ifdef CONFIG_XEN_BLKDEV_TAP_BE
/*
@@ -105,26 +97,79 @@ static grant_handle_t pending_grant_handles[MMAP_PAGES];
static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
#endif
static int do_block_io_op(blkif_t *blkif, int max_to_do);
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
static int do_block_io_op(blkif_t *blkif);
static void dispatch_rw_block_io(blkif_t *blkif,
blkif_request_t *req,
pending_req_t *pending_req);
static void make_response(blkif_t *blkif, unsigned long id,
unsigned short op, int st);
static void fast_flush_area(int idx, int nr_pages)
/******************************************************************
* misc small helpers
*/
static pending_req_t* alloc_req(void)
{
pending_req_t *req = NULL;
unsigned long flags;
spin_lock_irqsave(&pending_free_lock, flags);
if (!list_empty(&pending_free)) {
req = list_entry(pending_free.next, pending_req_t, free_list);
list_del(&req->free_list);
}
spin_unlock_irqrestore(&pending_free_lock, flags);
return req;
}
static void free_req(pending_req_t *req)
{
unsigned long flags;
int was_empty;
spin_lock_irqsave(&pending_free_lock, flags);
was_empty = list_empty(&pending_free);
list_add(&req->free_list, &pending_free);
spin_unlock_irqrestore(&pending_free_lock, flags);
if (was_empty)
wake_up(&pending_free_wq);
}
static void unplug_queue(blkif_t *blkif)
{
if (blkif->plug == NULL)
return;
if (blkif->plug->unplug_fn)
blkif->plug->unplug_fn(blkif->plug);
blk_put_queue(blkif->plug);
blkif->plug = NULL;
}
static void plug_queue(blkif_t *blkif, struct bio *bio)
{
request_queue_t *q = bdev_get_queue(bio->bi_bdev);
if (q == blkif->plug)
return;
unplug_queue(blkif);
blk_get_queue(q);
blkif->plug = q;
}
static void fast_flush_area(pending_req_t *req)
{
struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned int i, invcount = 0;
grant_handle_t handle;
int ret;
for (i = 0; i < nr_pages; i++) {
handle = pending_handle(idx, i);
for (i = 0; i < req->nr_pages; i++) {
handle = pending_handle(req, i);
if (handle == BLKBACK_INVALID_HANDLE)
continue;
unmap[invcount].host_addr = MMAP_VADDR(idx, i);
unmap[invcount].host_addr = vaddr(req, i);
unmap[invcount].dev_bus_addr = 0;
unmap[invcount].handle = handle;
pending_handle(idx, i) = BLKBACK_INVALID_HANDLE;
pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
invcount++;
}
@@ -133,118 +178,90 @@ static void fast_flush_area(int idx, int nr_pages)
BUG_ON(ret);
}
/******************************************************************
* BLOCK-DEVICE SCHEDULER LIST MAINTENANCE
*/
static struct list_head blkio_schedule_list;
static spinlock_t blkio_schedule_list_lock;
static int __on_blkdev_list(blkif_t *blkif)
{
return blkif->blkdev_list.next != NULL;
}
static void remove_from_blkdev_list(blkif_t *blkif)
{
unsigned long flags;
if (!__on_blkdev_list(blkif))
return;
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
if (__on_blkdev_list(blkif)) {
list_del(&blkif->blkdev_list);
blkif->blkdev_list.next = NULL;
blkif_put(blkif);
}
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
}
static void add_to_blkdev_list_tail(blkif_t *blkif)
{
unsigned long flags;
if (__on_blkdev_list(blkif))
return;
spin_lock_irqsave(&blkio_schedule_list_lock, flags);
if (!__on_blkdev_list(blkif) && (blkif->status == CONNECTED)) {
list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
blkif_get(blkif);
}
spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
}
/******************************************************************
* SCHEDULER FUNCTIONS
*/
static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait);
static int blkio_schedule(void *arg)
static void print_stats(blkif_t *blkif)
{
DECLARE_WAITQUEUE(wq, current);
printk(KERN_DEBUG "%s: oo %3d | rd %4d | wr %4d\n",
current->comm, blkif->st_oo_req,
blkif->st_rd_req, blkif->st_wr_req);
blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
blkif->st_rd_req = 0;
blkif->st_wr_req = 0;
blkif->st_oo_req = 0;
}
blkif_t *blkif;
struct list_head *ent;
daemonize("xenblkd");
int blkif_schedule(void *arg)
{
blkif_t *blkif = arg;
blkif_get(blkif);
if (debug_lvl)
printk(KERN_DEBUG "%s: started\n", current->comm);
for (;;) {
/* Wait for work to do. */
add_wait_queue(&blkio_schedule_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
if ( (NR_PENDING_REQS == MAX_PENDING_REQS) ||
list_empty(&blkio_schedule_list) )
schedule();
__set_current_state(TASK_RUNNING);
remove_wait_queue(&blkio_schedule_wait, &wq);
/* Queue up a batch of requests. */
while ((NR_PENDING_REQS < MAX_PENDING_REQS) &&
!list_empty(&blkio_schedule_list)) {
ent = blkio_schedule_list.next;
blkif = list_entry(ent, blkif_t, blkdev_list);
blkif_get(blkif);
remove_from_blkdev_list(blkif);
if (do_block_io_op(blkif, BATCH_PER_DOMAIN))
add_to_blkdev_list_tail(blkif);
blkif_put(blkif);
if (kthread_should_stop()) {
/* asked to quit? */
if (!atomic_read(&blkif->io_pending))
break;
if (debug_lvl)
printk(KERN_DEBUG "%s: I/O pending, "
"delaying exit\n", current->comm);
}
/* Push the batch through to disc. */
flush_plugged_queue();
if (!atomic_read(&blkif->io_pending)) {
/* Wait for work to do. */
wait_event_interruptible(
blkif->wq,
(atomic_read(&blkif->io_pending) ||
kthread_should_stop()));
} else if (list_empty(&pending_free)) {
/* Wait for pending_req becoming available. */
wait_event_interruptible(
pending_free_wq,
!list_empty(&pending_free));
}
if (blkif->status != CONNECTED) {
/* make sure we are connected */
if (debug_lvl)
printk(KERN_DEBUG "%s: not connected "
"(%d pending)\n",
current->comm,
atomic_read(&blkif->io_pending));
wait_event_interruptible(
blkif->wq,
(blkif->status == CONNECTED ||
kthread_should_stop()));
continue;
}
/* Schedule I/O */
atomic_set(&blkif->io_pending, 0);
if (do_block_io_op(blkif))
atomic_inc(&blkif->io_pending);
unplug_queue(blkif);
if (log_stats && time_after(jiffies, blkif->st_print))
print_stats(blkif);
}
if (log_stats)
print_stats(blkif);
if (debug_lvl)
printk(KERN_DEBUG "%s: exiting\n", current->comm);
blkif->xenblkd = NULL;
blkif_put(blkif);
return 0;
}
static void maybe_trigger_blkio_schedule(void)
{
/*
* Needed so that two processes, which together make the following
* predicate true, don't both read stale values and evaluate the
* predicate incorrectly. Incredibly unlikely to stall the scheduler
* on x86, but...
*/
smp_mb();
if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
!list_empty(&blkio_schedule_list))
wake_up(&blkio_schedule_wait);
}
/******************************************************************
* COMPLETION CALLBACK -- Called as bh->b_end_io()
*/
static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
{
unsigned long flags;
/* An error fails the entire request. */
if (!uptodate) {
DPRINTK("Buffer not up-to-date at end of operation\n");
@@ -252,15 +269,11 @@ static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
}
if (atomic_dec_and_test(&pending_req->pendcnt)) {
int pending_idx = pending_req - pending_reqs;
fast_flush_area(pending_idx, pending_req->nr_pages);
fast_flush_area(pending_req);
make_response(pending_req->blkif, pending_req->id,
pending_req->operation, pending_req->status);
blkif_put(pending_req->blkif);
spin_lock_irqsave(&pend_prod_lock, flags);
pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
spin_unlock_irqrestore(&pend_prod_lock, flags);
maybe_trigger_blkio_schedule();
free_req(pending_req);
}
}
@@ -281,8 +294,9 @@ static int end_block_io_op(struct bio *bio, unsigned int done, int error)
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
{
blkif_t *blkif = dev_id;
add_to_blkdev_list_tail(blkif);
maybe_trigger_blkio_schedule();
atomic_inc(&blkif->io_pending);
wake_up(&blkif->wq);
return IRQ_HANDLED;
}
@@ -292,10 +306,11 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
* DOWNWARD CALLS -- These interface with the block-device layer proper.
*/
static int do_block_io_op(blkif_t *blkif, int max_to_do)
static int do_block_io_op(blkif_t *blkif)
{
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
blkif_request_t *req;
pending_req_t *pending_req;
RING_IDX rc, rp;
int more_to_do = 0;
@@ -304,8 +319,10 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
rmb(); /* Ensure we see queued requests up to 'rp'. */
while ((rc != rp) && !RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
if ((max_to_do-- == 0) ||
(NR_PENDING_REQS == MAX_PENDING_REQS)) {
pending_req = alloc_req();
if (NULL == pending_req) {
blkif->st_oo_req++;
more_to_do = 1;
break;
}
@@ -315,28 +332,31 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
switch (req->operation) {
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
dispatch_rw_block_io(blkif, req);
blkif->st_rd_req++;
dispatch_rw_block_io(blkif, req, pending_req);
break;
case BLKIF_OP_WRITE:
blkif->st_wr_req++;
dispatch_rw_block_io(blkif, req, pending_req);
break;
default:
DPRINTK("error: unknown block io operation [%d]\n",
req->operation);
make_response(blkif, req->id, req->operation,
BLKIF_RSP_ERROR);
free_req(pending_req);
break;
}
}
return more_to_do;
}
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
static void dispatch_rw_block_io(blkif_t *blkif,
blkif_request_t *req,
pending_req_t *pending_req)
{
extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
int operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
int i, pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
pending_req_t *pending_req;
struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct phys_req preq;
struct {
@@ -344,32 +364,36 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
} seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned int nseg;
struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int nbio = 0;
request_queue_t *q;
int ret, errors = 0;
int ret, i, nbio = 0;
/* Check that number of segments is sane. */
nseg = req->nr_segments;
if (unlikely(nseg == 0) ||
unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
DPRINTK("Bad number of segments in request (%d)\n", nseg);
goto bad_descriptor;
goto fail_response;
}
preq.dev = req->handle;
preq.sector_number = req->sector_number;
preq.nr_sects = 0;
pending_req->blkif = blkif;
pending_req->id = req->id;
pending_req->operation = operation;
pending_req->status = BLKIF_RSP_OKAY;
pending_req->nr_pages = nseg;
for (i = 0; i < nseg; i++) {
seg[i].nsec = req->seg[i].last_sect -
req->seg[i].first_sect + 1;
if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
(seg[i].nsec <= 0))
goto bad_descriptor;
goto fail_response;
preq.nr_sects += seg[i].nsec;
map[i].host_addr = MMAP_VADDR(pending_idx, i);
map[i].host_addr = vaddr(pending_req, i);
map[i].dom = blkif->domid;
map[i].ref = req->seg[i].gref;
map[i].flags = GNTMAP_host_map;
@@ -381,26 +405,22 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
BUG_ON(ret);
for (i = 0; i < nseg; i++) {
if (likely(map[i].status == 0)) {
pending_handle(pending_idx, i) = map[i].handle;
#ifdef __ia64__
MMAP_VADDR(pending_idx,i) = gnttab_map_vaddr(map[i]);
#else
set_phys_to_machine(__pa(MMAP_VADDR(
pending_idx, i)) >> PAGE_SHIFT,
FOREIGN_FRAME(map[i].dev_bus_addr>>PAGE_SHIFT));
#endif
seg[i].buf = map[i].dev_bus_addr |
(req->seg[i].first_sect << 9);
} else {
errors++;
if (unlikely(map[i].status != 0)) {
DPRINTK("invalid buffer -- could not remap it\n");
goto fail_flush;
}
}
if (errors) {
DPRINTK("invalid buffer -- could not remap it\n");
fast_flush_area(pending_idx, nseg);
goto bad_descriptor;
pending_handle(pending_req, i) = map[i].handle;
#ifdef __ia64__
pending_vaddrs[vaddr_pagenr(pending_req, i)] =
= gnttab_map_vaddr(map[i]);
#else
set_phys_to_machine(__pa(vaddr(
pending_req, i)) >> PAGE_SHIFT,
FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
#endif
seg[i].buf = map[i].dev_bus_addr |
(req->seg[i].first_sect << 9);
}
if (vbd_translate(&preq, blkif, operation) != 0) {
@@ -408,37 +428,25 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
operation == READ ? "read" : "write",
preq.sector_number,
preq.sector_number + preq.nr_sects, preq.dev);
goto bad_descriptor;
goto fail_flush;
}
pending_req = &pending_reqs[pending_idx];
pending_req->blkif = blkif;
pending_req->id = req->id;
pending_req->operation = operation;
pending_req->status = BLKIF_RSP_OKAY;
pending_req->nr_pages = nseg;
for (i = 0; i < nseg; i++) {
if (((int)preq.sector_number|(int)seg[i].nsec) &
((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
DPRINTK("Misaligned I/O request from domain %d",
blkif->domid);
goto cleanup_and_fail;
goto fail_put_bio;
}
while ((bio == NULL) ||
(bio_add_page(bio,
virt_to_page(MMAP_VADDR(pending_idx, i)),
virt_to_page(vaddr(pending_req, i)),
seg[i].nsec << 9,
seg[i].buf & ~PAGE_MASK) == 0)) {
bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
if (unlikely(bio == NULL)) {
cleanup_and_fail:
for (i = 0; i < (nbio-1); i++)
bio_put(biolist[i]);
fast_flush_area(pending_idx, nseg);
goto bad_descriptor;
}
if (unlikely(bio == NULL))
goto fail_put_bio;
bio->bi_bdev = preq.bdev;
bio->bi_private = pending_req;
@@ -449,14 +457,8 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
preq.sector_number += seg[i].nsec;
}
if ((q = bdev_get_queue(bio->bi_bdev)) != plugged_queue) {
flush_plugged_queue();
blk_get_queue(q);
plugged_queue = q;
}
plug_queue(blkif, bio);
atomic_set(&pending_req->pendcnt, nbio);
pending_cons++;
blkif_get(blkif);
for (i = 0; i < nbio; i++)
@@ -464,8 +466,14 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
return;
bad_descriptor:
fail_put_bio:
for (i = 0; i < (nbio-1); i++)
bio_put(biolist[i]);
fail_flush:
fast_flush_area(pending_req);
fail_response:
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
free_req(pending_req);
}
@@ -481,6 +489,7 @@ static void make_response(blkif_t *blkif, unsigned long id,
blkif_response_t *resp;
unsigned long flags;
blkif_back_ring_t *blk_ring = &blkif->blk_ring;
int more_to_do = 0;
int notify;
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
@@ -499,76 +508,69 @@ static void make_response(blkif_t *blkif, unsigned long id,
* notifications if requests are already in flight (lower
* overheads and promotes batching).
*/
int more_to_do;
RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
if (more_to_do) {
add_to_blkdev_list_tail(blkif);
maybe_trigger_blkio_schedule();
}
}
else if (!__on_blkdev_list(blkif)
&& RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
/* Keep pulling requests as they become available... */
add_to_blkdev_list_tail(blkif);
maybe_trigger_blkio_schedule();
}
} else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
more_to_do = 1;
}
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
if (more_to_do) {
atomic_inc(&blkif->io_pending);
wake_up(&blkif->wq);
}
if (notify)
notify_remote_via_irq(blkif->irq);
}
void blkif_deschedule(blkif_t *blkif)
{
remove_from_blkdev_list(blkif);
}
static int __init blkif_init(void)
{
int i;
struct page *page;
int ret;
for (i = 0; i < MMAP_PAGES; i++)
pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
int i;
if (xen_init() < 0)
return -ENODEV;
mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
pending_reqs = kmalloc(sizeof(pending_reqs[0]) *
blkif_reqs, GFP_KERNEL);
pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
mmap_pages, GFP_KERNEL);
pending_vaddrs = kmalloc(sizeof(pending_vaddrs[0]) *
mmap_pages, GFP_KERNEL);
if (!pending_reqs || !pending_grant_handles || !pending_vaddrs) {
printk("%s: out of memory\n", __FUNCTION__);
return -1;
}
blkif_interface_init();
#ifdef __ia64__
{
extern unsigned long alloc_empty_foreign_map_page_range(unsigned long pages);
int i;
mmap_vstart = alloc_empty_foreign_map_page_range(MMAP_PAGES);
printk("Allocated mmap_vstart: 0x%lx\n", mmap_vstart);
for(i = 0; i < MMAP_PAGES; i++)
pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT);
BUG_ON(mmap_vstart == NULL);
}
#else
page = balloon_alloc_empty_page_range(MMAP_PAGES);
extern unsigned long alloc_empty_foreign_map_page_range(
unsigned long pages);
mmap_vstart = (unsigned long)
alloc_empty_foreign_map_page_range(mmap_pages);
#else /* ! ia64 */
page = balloon_alloc_empty_page_range(mmap_pages);
BUG_ON(page == NULL);
mmap_vstart = (unsigned long)pfn_to_kaddr(page_to_pfn(page));
#endif
printk("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
__FUNCTION__, blkif_reqs, mmap_pages, mmap_vstart);
BUG_ON(mmap_vstart == 0);
for (i = 0; i < mmap_pages; i++) {
pending_vaddrs[i] = mmap_vstart + (i << PAGE_SHIFT);
pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
}
pending_cons = 0;
pending_prod = MAX_PENDING_REQS;
memset(pending_reqs, 0, sizeof(pending_reqs));
for (i = 0; i < MAX_PENDING_REQS; i++)
pending_ring[i] = i;
INIT_LIST_HEAD(&pending_free);
for (i = 0; i < blkif_reqs; i++)
list_add_tail(&pending_reqs[i].free_list, &pending_free);
spin_lock_init(&blkio_schedule_list_lock);
INIT_LIST_HEAD(&blkio_schedule_list);
ret = kernel_thread(blkio_schedule, NULL, CLONE_FS | CLONE_FILES);
BUG_ON(ret < 0);
blkif_xenbus_init();
return 0;
}
@@ -60,10 +60,20 @@ typedef struct blkif_st {
/* Is this a blktap frontend */
unsigned int is_blktap;
#endif
struct list_head blkdev_list;
spinlock_t blk_ring_lock;
atomic_t refcnt;
wait_queue_head_t wq;
struct task_struct *xenblkd;
atomic_t io_pending;
request_queue_t *plug;
/* statistics */
unsigned long st_print;
int st_rd_req;
int st_wr_req;
int st_oo_req;
struct work_struct free_work;
grant_handle_t shmem_handle;
@@ -101,11 +111,10 @@ int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
void blkif_interface_init(void);
void blkif_deschedule(blkif_t *blkif);
void blkif_xenbus_init(void);
irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
int blkif_schedule(void *arg);
void update_blkif_status(blkif_t *blkif);
@@ -24,6 +24,8 @@ blkif_t *alloc_blkif(domid_t domid)
blkif->status = DISCONNECTED;
spin_lock_init(&blkif->blk_ring_lock);
atomic_set(&blkif->refcnt, 1);
init_waitqueue_head(&blkif->wq);
blkif->st_print = jiffies;
return blkif;
}
@@ -20,6 +20,7 @@
#include <stdarg.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <asm-xen/xenbus.h>
#include "common.h"
@@ -92,6 +93,8 @@ static int blkback_remove(struct xenbus_device *dev)
}
if (be->blkif) {
be->blkif->status = DISCONNECTED;
if (be->blkif->xenblkd)
kthread_stop(be->blkif->xenblkd);
blkif_put(be->blkif);
be->blkif = NULL;
}
@@ -220,6 +223,17 @@ static void backend_changed(struct xenbus_watch *watch,
return;
}
be->blkif->xenblkd = kthread_run(blkif_schedule, be->blkif,
"xvd %d %02x:%02x",
be->blkif->domid,
be->major, be->minor);
if (IS_ERR(be->blkif->xenblkd)) {
err = PTR_ERR(be->blkif->xenblkd);
be->blkif->xenblkd = NULL;
xenbus_dev_error(dev, err, "start xenblkd");
return;
}
device_create_file(&dev->dev, &dev_attr_physical_device);
device_create_file(&dev->dev, &dev_attr_mode);
@@ -55,7 +55,8 @@ typedef struct netif_st {
/* The shared rings and indexes. */
netif_tx_back_ring_t tx;
netif_rx_back_ring_t rx;
struct vm_struct *comms_area;
struct vm_struct *tx_comms_area;
struct vm_struct *rx_comms_area;
/* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
RING_IDX rx_req_cons_peek;
@@ -117,14 +117,14 @@ static int map_frontend_pages(
struct gnttab_map_grant_ref op;
int ret;
op.host_addr = (unsigned long)netif->comms_area->addr;
op.host_addr = (unsigned long)netif->tx_comms_area->addr;
op.flags = GNTMAP_host_map;
op.ref = tx_ring_ref;
op.dom = netif->domid;
lock_vm_area(netif->comms_area);
lock_vm_area(netif->tx_comms_area);
ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
unlock_vm_area(netif->comms_area);
unlock_vm_area(netif->tx_comms_area);
BUG_ON(ret);
if (op.status) {
@@ -135,14 +135,14 @@ static int map_frontend_pages(
netif->tx_shmem_ref = tx_ring_ref;
netif->tx_shmem_handle = op.handle;
op.host_addr = (unsigned long)netif->comms_area->addr + PAGE_SIZE;
op.host_addr = (unsigned long)netif->rx_comms_area->addr;
op.flags = GNTMAP_host_map;
op.ref = rx_ring_ref;
op.dom = netif->domid;
lock_vm_area(netif->comms_area);
lock_vm_area(netif->rx_comms_area);
ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
unlock_vm_area(netif->comms_area);
unlock_vm_area(netif->rx_comms_area);
BUG_ON(ret);
if (op.status) {
@@ -161,22 +161,22 @@ static void unmap_frontend_pages(netif_t *netif)
struct gnttab_unmap_grant_ref op;
int ret;
op.host_addr = (unsigned long)netif->comms_area->addr;
op.host_addr = (unsigned long)netif->tx_comms_area->addr;
op.handle = netif->tx_shmem_handle;
op.dev_bus_addr = 0;
lock_vm_area(netif->comms_area);
lock_vm_area(netif->tx_comms_area);
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
unlock_vm_area(netif->comms_area);
unlock_vm_area(netif->tx_comms_area);
BUG_ON(ret);
op.host_addr = (unsigned long)netif->comms_area->addr + PAGE_SIZE;
op.host_addr = (unsigned long)netif->rx_comms_area->addr;
op.handle = netif->rx_shmem_handle;
op.dev_bus_addr = 0;
lock_vm_area(netif->comms_area);
lock_vm_area(netif->rx_comms_area);
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
unlock_vm_area(netif->comms_area);
unlock_vm_area(netif->rx_comms_area);
BUG_ON(ret);
}
@@ -195,20 +195,23 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
if (netif->irq)
return 0;
netif->comms_area = alloc_vm_area(2*PAGE_SIZE);
if (netif->comms_area == NULL)
netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
if (netif->tx_comms_area == NULL || netif->rx_comms_area == NULL)
return -ENOMEM;
err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
if (err) {
free_vm_area(netif->comms_area);
free_vm_area(netif->tx_comms_area);
free_vm_area(netif->rx_comms_area);
return err;
}
err = HYPERVISOR_event_channel_op(&op);
if (err) {
unmap_frontend_pages(netif);
free_vm_area(netif->comms_area);
free_vm_area(netif->tx_comms_area);
free_vm_area(netif->rx_comms_area);
return err;
}
@@ -218,11 +221,11 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
netif->evtchn, netif_be_int, 0, netif->dev->name, netif);
disable_irq(netif->irq);
txs = (netif_tx_sring_t *)netif->comms_area->addr;
txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
rxs = (netif_rx_sring_t *)
((char *)netif->comms_area->addr + PAGE_SIZE);
((char *)netif->rx_comms_area->addr);
BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
netif->rx_req_cons_peek = 0;
@@ -255,7 +258,8 @@ static void free_netif_callback(void *arg)
if (netif->tx.sring) {
unmap_frontend_pages(netif);
free_vm_area(netif->comms_area);
free_vm_area(netif->tx_comms_area);
free_vm_area(netif->rx_comms_area);
}
free_netdev(netif->dev);
+5 -5
View File
@@ -1171,11 +1171,6 @@ class XendDomainInfo:
xc.domain_setcpuweight(self.domid, self.info['cpu_weight'])
m = self.image.getDomainMemory(self.info['memory'] * 1024)
balloon.free(m)
xc.domain_setmaxmem(self.domid, m)
xc.domain_memory_increase_reservation(self.domid, m, 0, 0)
# repin domain vcpus if a restricted cpus list is provided
# this is done prior to memory allocation to aide in memory
# distribution for NUMA systems.
@@ -1186,6 +1181,11 @@ class XendDomainInfo:
cpu = [ int( cpus[v % len(cpus)] ) ]
xc.domain_pincpu(self.domid, v, cpu)
m = self.image.getDomainMemory(self.info['memory'] * 1024)
balloon.free(m)
xc.domain_setmaxmem(self.domid, m)
xc.domain_memory_increase_reservation(self.domid, m, 0, 0)
self.createChannels()
channel_details = self.image.createImage()
+7 -3
View File
@@ -38,10 +38,14 @@ class TPMifController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
devid = int(sxp.child_value(config, 'pref_instance', '0'))
log.info("The domain has a TPM with instance %d." % devid)
devid = self.allocateDeviceID()
inst = int(sxp.child_value(config, 'pref_instance', '-1'))
if inst == -1:
inst = int(sxp.child_value(config, 'instance' , '0'))
back = { 'pref_instance' : "%i" % devid }
log.info("The domain has a TPM with instance %d and devid %d.",
inst, devid)
back = { 'pref_instance' : "%i" % inst }
front = { 'handle' : "%i" % devid }
return (devid, back, front)
+59 -33
View File
@@ -1,16 +1,19 @@
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Rules.mk
SRCS = secpol_tool.c
CFLAGS += -Wall
CFLAGS += -Werror
CFLAGS += -O3
CFLAGS += -fno-strict-aliasing
CFLAGS += -I. -I/usr/include/libxml2
CFLAGS_XML2BIN += $(shell xml2-config --cflags --libs )
#if above does not work, try -L/usr/lib -lxml2 -lz -lpthread -lm
CFLAGS += -I.
CPPFLAGS += -MMD -MF .$*.d
PROG_DEPS = .*.d
XML2VERSION = $(shell xml2-config --version )
VALIDATE_SCHEMA=$(shell if [[ $(XML2VERSION) < 2.6.20 ]]; then echo ""; else echo "-DVALIDATE_SCHEMA"; fi; )
CFLAGS += $(shell xml2-config --cflags )
CFLAGS += $(shell if [[ $(XML2VERSION) < 2.6.20 ]]; then echo ""; else echo "-DVALIDATE_SCHEMA"; fi )
LDFLAGS += $(shell xml2-config --libs ) # if this does not work, try -L/usr/lib -lxml2 -lz -lpthread -lm
ifeq ($(ACM_DEFAULT_SECURITY_POLICY),ACM_NULL_POLICY)
POLICY=null
@@ -24,48 +27,71 @@ endif
ifeq ($(ACM_DEFAULT_SECURITY_POLICY),ACM_CHINESE_WALL_AND_SIMPLE_TYPE_ENFORCEMENT_POLICY)
POLICY=chwall_ste
endif
POLICYFILE=./policies/$(POLICY)/$(POLICY).bin
SRCS_TOOL = secpol_tool.c
OBJS_TOOL := $(patsubst %.c,%.o,$(filter %.c,$(SRCS_TOOL)))
SRCS_XML2BIN = secpol_xml2bin.c secpol_xml2bin.h
OBJS_XML2BIN := $(patsubst %.c,%.o,$(filter %.c,$(SRCS_XML2BIN)))
SRCS_GETD = get_decision.c
OBJS_GETD := $(patsubst %.c,%.o,$(filter %.c,$(SRCS_GETD)))
ACM_INST_TOOLS = xensec_tool xensec_xml2bin
ACM_NOINST_TOOLS = get_decision
ACM_OBJS = $(OBJS_TOOL) $(OBJS_XML2BIN) $(OBJS_GETD)
ACM_SCRIPTS = getlabel.sh setlabel.sh updategrub.sh labelfuncs.sh
ACM_CONFIG_DIR = /etc/xen/acm-security
ACM_POLICY_DIR = $(ACM_CONFIG_DIR)/policies
ACM_SCRIPT_DIR = $(ACM_CONFIG_DIR)/scripts
ACM_SCHEMA = security_policy.xsd
ACM_EXAMPLES = null chwall ste chwall_ste
ACM_POLICY_SUFFIX = security_policy.xml
ACM_LABEL_SUFFIX = security_label_template.xml
ifeq ($(ACM_SECURITY),y)
all: build
install:all
default:all
install: all $(ACM_CONFIG_FILE)
$(INSTALL_DIR) -p $(DESTDIR)/usr/sbin
$(INSTALL_PROG) -p $(ACM_INST_TOOLS) $(DESTDIR)/usr/sbin
$(INSTALL_DIR) -p $(DESTDIR)$(ACM_CONFIG_DIR)
$(INSTALL_DIR) -p $(DESTDIR)$(ACM_POLICY_DIR)
$(INSTALL_DATA) -p policies/$(ACM_SCHEMA) $(DESTDIR)$(ACM_POLICY_DIR)
for i in $(ACM_EXAMPLES); do \
$(INSTALL_DIR) -p $(DESTDIR)$(ACM_POLICY_DIR)/$$i; \
$(INSTALL_DATA) -p policies/$$i/$$i-$(ACM_POLICY_SUFFIX) $(DESTDIR)$(ACM_POLICY_DIR)/$$i; \
$(INSTALL_DATA) -p policies/$$i/$$i-$(ACM_LABEL_SUFFIX) $(DESTDIR)$(ACM_POLICY_DIR)/$$i; \
done
$(INSTALL_DIR) -p $(DESTDIR)$(ACM_SCRIPT_DIR)
$(INSTALL_PROG) -p $(ACM_SCRIPTS) $(DESTDIR)$(ACM_SCRIPT_DIR)
else
all:
install:
default:
endif
build: mk-symlinks
$(MAKE) secpol_tool
$(MAKE) secpol_xml2bin
$(MAKE) get_decision
chmod 700 ./setlabel.sh
chmod 700 ./updategrub.sh
chmod 700 ./getlabel.sh
build: mk-symlinks $(ACM_INST_TOOLS) $(ACM_NOINST_TOOLS)
chmod 700 $(ACM_SCRIPTS)
secpol_tool : secpol_tool.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $<
xensec_tool: $(OBJS_TOOL)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
secpol_xml2bin : secpol_xml2bin.c secpol_xml2bin.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_XML2BIN) $(VALIDATE_SCHEMA) -o $@ $<
xensec_xml2bin: $(OBJS_XML2BIN)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
get_decision: $(OBJS_GETD)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $<
clean:
rm -rf secpol_tool secpol_xml2bin xen get_decision
$(RM) $(ACM_INST_TOOLS) $(ACM_NOINST_TOOLS)
$(RM) $(ACM_OBJS)
$(RM) $(PROG_DEPS)
$(RM) -r xen
policy_clean:
rm -rf policies/*/*.bin policies/*/*.map
mrproper: clean
mrproper: clean policy_clean
boot_install: install
$(ACM_SCRIPT_DIR)/updategrub.sh $(POLICY) $(KERNEL_VERSION)
$(POLICYFILE) : build
@./secpol_xml2bin $(POLICY) > /dev/null
boot_install: $(POLICYFILE)
@cp $(POLICYFILE) /boot
@./updategrub.sh $(POLICY) $(PWD)/$(XEN_ROOT)
-include $(PROG_DEPS)
+43 -39
View File
@@ -9,23 +9,23 @@
# and to label domains and resources.
##
We will show how to install and use the chwall_ste policy.
We will show how to install and use the example chwall_ste policy.
Other policies work similarly. Feedback welcome!
1. Using secpol_xml2bin to translate the chwall_ste policy:
1. Using xensec_xml2bin to translate the chwall_ste policy:
===========================================================
#tools/security/secpol_xml2bin chwall_ste
#xensec_xml2bin chwall_ste
Successful execution should print:
[root@laptopxn security]# ./secpol_xml2bin chwall_ste
Validating label file policies/chwall_ste/chwall_ste-security_label_template.xml...
XML Schema policies/security_policy.xsd valid.
Validating policy file policies/chwall_ste/chwall_ste-security_policy.xml...
XML Schema policies/security_policy.xsd valid.
[root@laptopxn security]# xensec_xml2bin chwall_ste
Validating label file /etc/xen/acm-security/policies/chwall_ste/chwall_ste-security_label_template.xml...
XML Schema /etc/xen/acm-security/policies/security_policy.xsd valid.
Validating policy file /etc/xen/acm-security/policies/chwall_ste/chwall_ste-security_policy.xml...
XML Schema /etc/xen/acm-security/policies/security_policy.xsd valid.
Creating ssid mappings ...
Creating label mappings ...
Max chwall labels: 7
@@ -35,10 +35,15 @@ Successful execution should print:
Max ste-types: 6
Max ste-ssids: 10
The tool looks in directory policies/chwall_ste for
By default, the tool looks in directory /etc/xen/acm-security/policies
for a directory that matches the policy name (i.e. chwall_ste) to find
the label and policy files.
The '-d' option can be used to override the /etc/xen/acm-security/policies
directory, for example if running the tool in the Xen security tool build
directory.
The default policy directory structure under tools/security looks like:
The default policy directory structure under /etc/xen/acm-security (and
the Xen security tool build directory - tools/security) looks like:
policies
|-- security_policy.xsd
@@ -55,25 +60,25 @@ policies
|-- ste-security_label_template.xml
`-- ste-security_policy.xml
policies/security_policy.xsd contains the schema against which both the
The security_policy.xsd file contains the schema against which both the
label-template and the policy files must validate during translation.
policies/chwall_ste/chwall_ste-security_policy.xml defines the
policies and the types known to the policies.
The files ending in -security_policy.xml define the policies and the
types known to the policies.
policies/chwall_ste/chwall_ste-security_label_template.xml contains
label definitions that group chwall and ste types together and make
them easier to use for users
The files ending in -security_label_template.xml contain the label
definitions that group types together and make them easier to use for
users.
After executing the above secpol_xml2bin command, you will find 2 new
files in the policies/chwall_ste sub-directory:
After executing the above xensec_xml2bin command, you will find 2 new
files in the /etc/xen/acm-security/policies/chwall_ste sub-directory:
policies/chwall_ste/chwall_ste.map ... this file includes the mapping
of names from the xml files into their binary code representation.
chwall_ste.map ... this file includes the mapping
of names from the xml files into their binary code representation.
policies/chwall_ste/chwall_ste.bin ... this is the binary policy file,
the result of parsing the xml files and using the mapping to extract a
binary version that can be loaded into the hypervisor.
chwall_ste.bin ... this is the binary policy file,
the result of parsing the xml files and using the mapping to extract a
binary version that can be loaded into the hypervisor.
@@ -85,13 +90,13 @@ please refer to install.txt for instructions.
To activate the policy from the command line (assuming that the
currently established policy is the minimal boot-policy that is
hard-coded into the hypervisor:
hard-coded into the hypervisor):
# ./secpol_tool loadpolicy policies/chwall_ste/chwall_ste.bin
# xensec_tool loadpolicy /etc/xen/acm-security/policies/chwall_ste/chwall_ste.bin
To activate the policy at next reboot:
# cp policies/chwall_ste/chwall_ste.bin /boot
# cp /etc/xen/acm-security/policies/chwall_ste/chwall_ste.bin /boot
Add a module line to your /boot/grub/grub.conf Xen entry.
My boot entry with chwall_ste enabled looks like this:
@@ -129,12 +134,12 @@ assign labels to user domains.
To show available labels for the chwall_ste policy:
#tools/security/setlabel.sh -l
# /etc/xen/acm-security/scripts/setlabel.sh -l
lists all available labels. For the default chwall_ste it should print
the following:
[root@laptopxn security]# ./setlabel.sh -l chwall_ste
[root@laptopxn security]# /etc/xen/acm-security/scripts/setlabel.sh -l chwall_ste
The following labels are available:
dom_SystemManagement
dom_HomeBanking
@@ -156,8 +161,8 @@ Setlabel.sh only prints VM labels (which we have prefixed with "dom_")
since only those are used at this time.
If you would like to assign the dom_HomeBanking label to one of your
user domains (which you hopefully keep clean), look at an example
domain configuration homebanking.xm:
user domains (which you hopefully keep clean), look at the hypothetical
domain configuration contained in /etc/xen/homebanking.xm:
#------HOMEBANKING---------
kernel = "/boot/vmlinuz-2.6.12-xenU"
@@ -172,7 +177,7 @@ domain configuration homebanking.xm:
Now we label this domain
[root@laptopxn security]# ./setlabel.sh homebanking.xm dom_HomeBanking chwall_ste
[root@laptopxn security]# /etc/xen/acm-securit/scripts/setlabel.sh /etc/xen/homebanking.xm dom_HomeBanking chwall_ste
Mapped label 'dom_HomeBanking' to ssidref '0x00020002'.
The domain configuration my look now like:
@@ -223,9 +228,8 @@ because of the defined conflict set
<type>cw_Distrusted</type>
</conflictset>
(in policies/chwall_ste/chwall_ste-security_policy.xml), which says
that only one of the types cw_sensitive and cw_Distrusted can run at a
time.
(in chwall_ste-security_policy.xml), which says that only one of the
types cw_Sensitive and cw_Distrusted can run at a time.
If you save or shutdown the HomeBanking domain, you will be able to
start the "Fun" domain. You can look into the Xen log to see if a
@@ -255,15 +259,15 @@ a) the policy definition (types etc.) file
b) the label template definition (labels etc.) file
If your policy name is "mypolicy", you need to create a
subdirectory mypolicy in tools/security/policies.
subdirectory mypolicy in /etc/xen/acm-security/policies.
Then you create
tools/security/policies/mypolicy/mypolicy-security_policy.xml and
tools/security/policies/mypolicy/mypolicy-security_label_template.xml.
/etc/xen/acm-security/policies/mypolicy/mypolicy-security_policy.xml and
/etc/xen/acm-security/policies/mypolicy/mypolicy-security_label_template.xml.
You need to keep to the schema as defined in
tools/security/security_policy.xsd since the translation tool
secpol_xml2bin is written against this schema.
/etc/xen/acm-security/security_policy.xsd since the translation tool
xensec_xml2bin is written against this schema.
If you keep to the security policy schema, then you can use all the
tools described above. Refer to install.txt to install it.
+29 -68
View File
@@ -32,20 +32,24 @@ fi
export PATH=$PATH:.
source labelfuncs.sh
dir=`dirname $0`
source $dir/labelfuncs.sh
usage ()
{
prg=`basename $0`
echo "Use this tool to display the label of a domain or the label that is
corresponding to an ssidref given the name of the running policy.
Usage: $0 -sid <ssidref> [<policy name>] or
$0 -dom <domid> [<policy name>]
Usage: $prg -sid <ssidref> [<policy name> [<policy dir>]] or
$prg -dom <domid> [<policy name> [<policy dir>]]
policy name : the name of the policy, i.e. 'chwall'
If the policy name is omitted, the grub.conf
entry of the running system is tried to be read
and the policy name determined from there.
policy dir : the directory where the <policy name> policy is located
The default location is '/etc/xen/acm-security/policies'
ssidref : an ssidref in hex or decimal format, i.e., '0x00010002'
or '65538'
domid : id of the domain, i.e., '1'; Use numbers from the 2nd
@@ -55,79 +59,36 @@ domid : id of the domain, i.e., '1'; Use numbers from the 2nd
if [ "$1" == "-?" ]; then
mode="usage"
if [ "$1" == "-h" ]; then
usage
exit 0
elif [ "$1" == "-dom" ]; then
mode="domid"
shift
elif [ "$1" == "-sid" ]; then
mode="sid"
shift
elif [ "$1" == "" ]; then
else
usage
exit -1
fi
if [ "$mode" == "usage" ]; then
usage
elif [ "$mode" == "domid" ]; then
if [ "$2" == "" ]; then
findGrubConf
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf"
exit -1;
fi
findPolicyInGrub $grubconf
if [ "$policy" != "" ]; then
echo "Assuming policy to be '$policy'.";
else
echo "Could not find policy."
exit -1;
fi
else
policy=$2
fi
findMapFile $policy
res=$?
if [ "$res" != "0" ]; then
getSSIDUsingSecpolTool $1
res=$?
if [ "$res" != "0" ]; then
translateSSIDREF $ssid $mapfile
else
echo "Could not determine the SSID of the domain."
fi
else
echo "Could not find map file for policy '$policy'."
fi
elif [ "$mode" == "sid" ]; then
if [ "$2" == "" ]; then
findGrubConf
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf"
exit -1;
fi
findPolicyInGrub $grubconf
if [ "$policy" != "" ]; then
echo "Assuming policy to be '$policy'.";
else
echo "Could not find policy."
exit -1;
fi
else
policy=$2
fi
findMapFile $policy
res=$?
if [ "$res" != "0" ]; then
translateSSIDREF $1 $mapfile
else
echo "Could not find map file for policy '$policy'."
fi
else
usage
setPolicyVars $2 $3
findMapFile $policy $policydir
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find map file for policy '$policy'."
exit -1
fi
if [ "$mode" == "domid" ]; then
getSSIDUsingSecpolTool $1
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not determine the SSID of the domain."
exit -1
fi
translateSSIDREF $ssid $mapfile
else # mode == sid
translateSSIDREF $1 $mapfile
fi
+6 -6
View File
@@ -41,11 +41,11 @@ exclusively (chwall_ste --> {chwall, ste}).
# make
manual steps (alternative to make boot_install):
#./secpol_xml2bin chwall_ste
#cp policies/chwall_ste/chwall_ste.bin /boot
#edit /boot/grub/grub.conf
# ./xensec_xml2bin -d policies/ chwall_ste
# cp policies/chwall_ste/chwall_ste.bin /boot
# edit /boot/grub/grub.conf
add the follwoing line to your xen boot entry:
"module chwall_ste.bin"
"module /boot/chwall_ste.bin"
alternatively, you can try our automatic translation and
installation of the policy:
@@ -61,9 +61,9 @@ exclusively (chwall_ste --> {chwall, ste}).
3. reboot into the newly compiled hypervisor
after boot
#xm dmesg should show an entry about the policy being loaded
# xm dmesg should show an entry about the policy being loaded
during the boot process
#tools/security/secpol_tool getpolicy
# xensec_tool getpolicy
should print the new chwall_ste binary policy representation
+158 -34
View File
@@ -17,10 +17,53 @@
#
#Some global variables for tools using this module
ACM_DEFAULT_ROOT="/etc/xen/acm-security"
# Set the policy and policydir variables
# Parameters:
# 1st : possible policy name
# 2nd : possible policy directory
# Results:
# The variables policy and policydir will hold the values for locating
# policy information
# If there are no errors, the functions returns a '1',
# a '0' otherwise.
setPolicyVars ()
{
local ret
# Set default values
policydir="$ACM_DEFAULT_ROOT/policies"
policy=""
if [ "$1" == "" ]; then
findGrubConf
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf."
return 0;
fi
findPolicyInGrub $grubconf
if [ "$policy" == "" ]; then
echo "Could not find policy in grub.conf. Looked for entry using kernel $linux."
return 0;
fi
echo "Assuming policy to be '$policy'.";
else
policy=$1
if [ "$2" != "" ]; then
policydir=$2
fi
fi
return 1
}
# Find the mapfile given a policy nmame
# Parameters:
# 1st : the name of the policy whose map file is to be found, i.e.,
# chwall
# 2nd : the policy directory for locating the map file
# Results:
# The variable mapfile will hold the realtive path to the mapfile
# for the given policy.
@@ -28,16 +71,10 @@
# a '0' otherwise.
findMapFile ()
{
mapfile="./$1.map"
mapfile="$2/$1/$1.map"
if [ -r "$mapfile" ]; then
return 1
fi
mapfile="./policies/$1/$1.map"
if [ -r "$mapfile" ]; then
return 1
fi
return 0
}
@@ -50,7 +87,7 @@ findMapFile ()
# The variable primary will hold the name of the primary policy
getPrimaryPolicy ()
{
mapfile=$1
local mapfile=$1
primary=`cat $mapfile | \
awk ' \
{ \
@@ -71,7 +108,7 @@ getPrimaryPolicy ()
# The variable secondary will hold the name of the secondary policy
getSecondaryPolicy ()
{
mapfile=$1
local mapfile=$1
secondary=`cat $mapfile | \
awk ' \
{ \
@@ -86,6 +123,10 @@ getSecondaryPolicy ()
#Return where the grub.conf file is.
#I only know of one place it can be.
#Returns:
# 1 : if the file is writeable and readable
# 2 : if the file is only readable
# 0 : if the file does not exist
findGrubConf()
{
grubconf="/boot/grub/grub.conf"
@@ -112,16 +153,37 @@ findGrubConf()
# kernel, i.e., 'vmlinuz-2.6.12-xen0'
getLinuxVersion ()
{
path=$1
local path
local versionfile
local lnx
if [ "$1" == "" ]; then
path="/lib/modules/*-xen0"
else
path="/lib/modules/$1"
fi
linux=""
for f in $path/linux-*-xen0 ; do
versionfile=$f/include/linux/version.h
versionfile=$f/build/include/linux/version.h
if [ -r $versionfile ]; then
lnx=`cat $versionfile | \
grep UTS_RELEASE | \
awk '{ \
len=length($3); \
print substr($3,2,len-2) }'`
version=substr($3,2,len-2); \
split(version,numbers,"."); \
if (numbers[4]=="") { \
printf("%s.%s.%s", \
numbers[1], \
numbers[2], \
numbers[3]); \
} else { \
printf("%s.%s.%s[.0-9]*-xen0",\
numbers[1], \
numbers[2], \
numbers[3]); \
} \
}'`
fi
if [ "$lnx" != "" ]; then
linux="[./0-9a-zA-z]*$lnx"
@@ -137,11 +199,12 @@ getLinuxVersion ()
# Find out with which policy the hypervisor was booted with.
# Parameters
# 1st : The complete path to grub.conf, i.e., /boot/grub/grub.conf
#
# Result:
# Sets the variable 'policy' to the name of the policy
findPolicyInGrub ()
{
grubconf=$1
linux=`uname -r`
local grubconf=$1
local linux=`uname -r`
policy=`cat $grubconf | \
awk -vlinux=$linux '{ \
if ( $1 == "title" ) { \
@@ -184,9 +247,9 @@ findPolicyInGrub ()
# The funtion returns '1' on success, '0' on failure
getSSIDUsingSecpolTool ()
{
domid=$1
local domid=$1
export PATH=$PATH:.
ssid=`secpol_tool getssid -d $domid -f | \
ssid=`xensec_tool getssid -d $domid -f | \
grep -E "SSID:" | \
awk '{ print $4 }'`
@@ -206,7 +269,7 @@ getSSIDUsingSecpolTool ()
# high ssid values as integers.
getSSIDLOHI ()
{
ssid=$1
local ssid=$1
ssidlo_int=`echo $ssid | awk \
'{ \
len=length($0); \
@@ -289,11 +352,11 @@ getSSIDLOHI ()
#
updateGrub ()
{
grubconf=$1
policyfile=$2
linux=$3
local grubconf=$1
local policyfile=$2
local linux=$3
tmpfile="/tmp/new_grub.conf"
local tmpfile="/tmp/new_grub.conf"
cat $grubconf | \
awk -vpolicy=$policyfile \
@@ -343,7 +406,59 @@ updateGrub ()
echo "Could not create temporary file! Aborting."
exit -1
fi
mv -f $tmpfile $grubconf
diff $tmpfile $grubconf > /dev/null
RES=$?
if [ "$RES" == "0" ]; then
echo "No changes were made to $grubconf."
else
echo "Successfully updated $grubconf."
mv -f $tmpfile $grubconf
fi
}
#Compile a policy into its binary representation
# Parameters:
# 1st: The directory where the ./policies directory is located at
# 2nd: The name of the policy
genBinPolicy ()
{
local root=$1
local policy=$2
pushd $root > /dev/null
xensec_xml2bin -d policies $policy > /dev/null
popd > /dev/null
}
# Copy the bootpolicy into the destination directory
# Generate the policy's .bin and .map files if necessary
# Parameters:
# 1st: Destination directory
# 2nd: The root directory of the security tools; this is where the
# policies directory is located at
# 3rd: The policy name
# Returns '1' on success, '0' on failure.
cpBootPolicy ()
{
local dest=$1
local root=$2
local policy=$3
local binfile=$root/policies/$policy/$policy.bin
local dstfile=$dest/$policy.bin
if [ ! -e $binfile ]; then
genBinPolicy $root $policy
if [ ! -e $binfile ]; then
echo "Could not compile policy '$policy'."
return 0
fi
fi
if [ ! -e $dstfile -o \
$binfile -nt $dstfile ]; then
cp -f $binfile $dstfile
fi
return 1
}
@@ -352,7 +467,11 @@ updateGrub ()
# 1st: Full or relative path to the policy's mapfile
showLabels ()
{
mapfile=$1
local mapfile=$1
local line
local ITEM
local found=0
if [ ! -r "$mapfile" -o "$mapfile" == "" ]; then
echo "Cannot read from vm configuration file $vmfile."
return -1
@@ -417,8 +536,8 @@ showLabels ()
# 2nd: the name of the policy
getDefaultSsid ()
{
mapfile=$1
pol=$2
local mapfile=$1
local pol=$2
RES=`cat $mapfile \
awk -vpol=$pol \
{ \
@@ -446,10 +565,13 @@ getDefaultSsid ()
# other : Prompts the user whether to proceed
relabel ()
{
vmfile=$1
label=$2
mapfile=$3
mode=$4
local vmfile=$1
local label=$2
local mapfile=$3
local mode=$4
local SSIDLO
local SSIDHI
local RES
if [ ! -r "$vmfile" ]; then
echo "Cannot read from vm configuration file $vmfile."
@@ -556,8 +678,8 @@ relabel ()
fi
#Write the output
vmtmp1="/tmp/__setlabel.tmp1"
vmtmp2="/tmp/__setlabel.tmp2"
local vmtmp1="/tmp/__setlabel.tmp1"
local vmtmp2="/tmp/__setlabel.tmp2"
touch $vmtmp1
touch $vmtmp2
if [ ! -w "$vmtmp1" -o ! -w "$vmtmp2" ]; then
@@ -584,8 +706,10 @@ relabel ()
# 2nd: Full or relative path to the policy's mapfile
translateSSIDREF ()
{
ssidref=$1
mapfile=$2
local ssidref=$1
local mapfile=$2
local line1
local line2
if [ ! -r "$mapfile" -o "$mapfile" == "" ]; then
echo "Cannot read from vm configuration file $vmfile."
+4 -2
View File
@@ -44,12 +44,13 @@ fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \
void usage(char *progname)
{
printf("Use: %s \n"
printf("Usage: %s ACTION\n"
"ACTION is one of:\n"
"\t getpolicy\n"
"\t dumpstats\n"
"\t loadpolicy <binary policy file>\n"
"\t getssid -d <domainid> [-f]\n"
"\t getssid -s <ssidref> [-f]\n", progname);
"\t getssid -s <ssidref> [-f]\n", progname);
exit(-1);
}
@@ -85,6 +86,7 @@ static inline int do_acm_op(int xc_handle, struct acm_op * op)
if ((ret = do_xen_hypercall(xc_handle, &hypercall)) < 0)
{
printf( "ACM operation failed: errno=%d\n", errno );
if (errno == EACCES)
fprintf(stderr, "ACM operation failed -- need to"
" rebuild the user-space tool set?\n");
+52 -17
View File
@@ -17,7 +17,7 @@
* sHype policy translation tool. This tool takes an XML
* policy specification as input and produces a binary
* policy file that can be loaded into Xen through the
* ACM operations (secpol_tool loadpolicy) interface or at
* ACM operations (xensec_tool loadpolicy) interface or at
* boot time (grub module parameter)
*
* indent -i4 -kr -nut
@@ -102,12 +102,22 @@ int have_chwall = 0;
/* input/output file names */
char *policy_filename = NULL,
*label_filename = NULL,
*binary_filename = NULL, *mapping_filename = NULL;
*binary_filename = NULL, *mapping_filename = NULL,
*schema_filename = NULL;
void usage(char *prg)
{
printf("usage:\n%s policyname[-policy.xml/-security_label_template.xml]\n",
prg);
printf("Usage: %s [OPTIONS] POLICYNAME\n", prg);
printf("POLICYNAME is the directory name within the policy directory\n");
printf("that contains the policy files. The default policy directory\n");
printf("is '%s' (see the '-d' option below to change it)\n", POLICY_DIR);
printf("The policy files contained in the POLICYNAME directory must be named:\n");
printf("\tPOLICYNAME-security_policy.xml\n");
printf("\tPOLICYNAME-security_label_template.xml\n\n");
printf("OPTIONS:\n");
printf("\t-d POLICYDIR\n");
printf("\t\tUse POLICYDIR as the policy directory. This directory must contain\n");
printf("\t\tthe policy schema file 'security_policy.xsd'\n");
exit(EXIT_FAILURE);
}
@@ -1237,7 +1247,7 @@ int is_valid(xmlDocPtr doc)
xmlSchemaParserCtxtPtr schemaparser_ctxt = NULL;
xmlSchemaValidCtxtPtr schemavalid_ctxt = NULL;
schemaparser_ctxt = xmlSchemaNewParserCtxt(SCHEMA_FILENAME);
schemaparser_ctxt = xmlSchemaNewParserCtxt(schema_filename);
schema_ctxt = xmlSchemaParse(schemaparser_ctxt);
schemavalid_ctxt = xmlSchemaNewValidCtxt(schema_ctxt);
@@ -1246,12 +1256,12 @@ int is_valid(xmlDocPtr doc)
if ((err = xmlSchemaIsValid(schemavalid_ctxt)) != 1)
{
printf("ERROR: Invalid schema file %s (err=%d)\n",
SCHEMA_FILENAME, err);
schema_filename, err);
err = -EIO;
goto out;
}
else
printf("XML Schema %s valid.\n", SCHEMA_FILENAME);
printf("XML Schema %s valid.\n", schema_filename);
#endif
if ((err = xmlSchemaValidateDoc(schemavalid_ctxt, doc)))
{
@@ -1275,37 +1285,59 @@ int main(int argc, char **argv)
char *file_prefix;
int prefix_len;
int opt_char;
char *policy_dir = POLICY_DIR;
if (ACM_POLICY_VERSION != WRITTEN_AGAINST_ACM_POLICY_VERSION)
{
printf("ERROR: This program was written against an older ACM version.\n");
exit(EXIT_FAILURE);
}
if (argc != 2)
while ((opt_char = getopt(argc, argv, "d:")) != -1) {
switch (opt_char) {
case 'd':
policy_dir = malloc(strlen(optarg) + 2); // null terminator and possibly "/"
if (!policy_dir) {
printf("ERROR allocating directory name memory.\n");
exit(EXIT_FAILURE);
}
strcpy(policy_dir, optarg);
if (policy_dir[strlen(policy_dir) - 1] != '/')
strcat(policy_dir, "/");
break;
default:
usage(basename(argv[0]));
}
}
if ((argc - optind) != 1)
usage(basename(argv[0]));
prefix_len = strlen(POLICY_SUBDIR) +
strlen(argv[1]) + 1 /* "/" */ +
strlen(argv[1]) + 1 /* "/" */ ;
prefix_len = strlen(policy_dir) +
strlen(argv[optind]) + 1 /* "/" */ +
strlen(argv[optind]) + 1 /* null terminator */ ;
file_prefix = malloc(prefix_len);
policy_filename = malloc(prefix_len + strlen(POLICY_EXTENSION));
label_filename = malloc(prefix_len + strlen(LABEL_EXTENSION));
binary_filename = malloc(prefix_len + strlen(BINARY_EXTENSION));
mapping_filename = malloc(prefix_len + strlen(MAPPING_EXTENSION));
schema_filename = malloc(strlen(policy_dir) + strlen(SCHEMA_FILENAME) + 1);
if (!file_prefix || !policy_filename || !label_filename ||
!binary_filename || !mapping_filename)
!binary_filename || !mapping_filename || !schema_filename)
{
printf("ERROR allocating file name memory.\n");
goto out2;
}
/* create input/output filenames out of prefix */
strcat(file_prefix, POLICY_SUBDIR);
strcat(file_prefix, argv[1]);
strcpy(file_prefix, policy_dir);
strcat(file_prefix, argv[optind]);
strcat(file_prefix, "/");
strcat(file_prefix, argv[1]);
strcat(file_prefix, argv[optind]);
strcpy(policy_filename, file_prefix);
strcpy(label_filename, file_prefix);
@@ -1317,11 +1349,14 @@ int main(int argc, char **argv)
strcat(binary_filename, BINARY_EXTENSION);
strcat(mapping_filename, MAPPING_EXTENSION);
strcpy(schema_filename, policy_dir);
strcat(schema_filename, SCHEMA_FILENAME);
labeldoc = xmlParseFile(label_filename);
if (labeldoc == NULL)
{
printf("Error: could not parse file %s.\n", argv[1]);
printf("Error: could not parse file %s.\n", argv[optind]);
goto out2;
}
@@ -1337,7 +1372,7 @@ int main(int argc, char **argv)
if (policydoc == NULL)
{
printf("Error: could not parse file %s.\n", argv[1]);
printf("Error: could not parse file %s.\n", argv[optind]);
goto out1;
}
+2 -2
View File
@@ -12,7 +12,7 @@
* License.
*
*/
#define POLICY_SUBDIR "policies/"
#define POLICY_DIR "/etc/xen/acm-security/policies/"
#define POLICY_EXTENSION "-security_policy.xml"
#define LABEL_EXTENSION "-security_label_template.xml"
#define BINARY_EXTENSION ".bin"
@@ -20,7 +20,7 @@
#define PRIMARY_COMPONENT_ATTR_NAME "order"
#define BOOTSTRAP_LABEL_ATTR_NAME "bootstrap"
#define PRIMARY_COMPONENT "PrimaryPolicyComponent"
#define SCHEMA_FILENAME "policies/security_policy.xsd"
#define SCHEMA_FILENAME "security_policy.xsd"
/* basic states (used as 1 << X) */
#define XML2BIN_SECPOL 0 /* policy tokens */
+35 -65
View File
@@ -35,102 +35,72 @@ if [ -z "$runbash" ]; then
fi
export PATH=$PATH:.
source labelfuncs.sh
dir=`dirname $0`
source $dir/labelfuncs.sh
usage ()
{
prg=`basename $0`
echo "Use this tool to put the ssidref corresponding to a label of a policy into
the VM configuration file, or use it to display all labels of a policy.
Usage: $0 [Option] <vmfile> <label> [<policy name>]
or $0 -l [<policy name>]
Usage: $prg [-r] <vmfile> <label> [<policy name> [<policy dir>]] or
$prg -l [<policy name> [<policy dir>]]
Valid options are:
-r : to relabel a file without being prompted
-l : to show the valid labels in a map file
vmfile : XEN vm configuration file; give complete path
label : the label to map to an ssidref
policy name : the name of the policy, i.e. 'chwall'
If the policy name is omitted, it is attempted
to find the current policy's name in grub.conf.
-l [<policy name>] is used to show valid labels in the map file of
the given or current policy. If the policy name
is omitted, it will be tried to determine the
current policy from grub.conf (/boot/grub/grub.conf)
policy dir : the directory where the <policy name> policy is located
The default location is '/etc/xen/acm-security/policies'
"
}
if [ "$1" == "-r" ]; then
mode="relabel"
shift
elif [ "$1" == "-l" ]; then
mode="show"
shift
elif [ "$1" == "-?" ]; then
elif [ "$1" == "-h" ]; then
mode="usage"
fi
if [ "$mode" == "show" ]; then
if [ "$1" == "" ]; then
findGrubConf
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf"
exit -1;
fi
findPolicyInGrub $grubconf
if [ "$policy" != "" ]; then
echo "Assuming policy to be '$policy'.";
else
echo "Could not find policy."
exit -1;
fi
else
policy=$1;
fi
findMapFile $policy
res=$?
if [ "$res" != "0" ]; then
showLabels $mapfile
else
echo "Could not find map file for policy '$policy'."
fi
elif [ "$mode" == "usage" ]; then
if [ "$mode" == "usage" ]; then
usage
elif [ "$mode" == "show" ]; then
setPolicyVars $1 $2
ret=$?
if [ $ret -eq 0 ]; then
echo "Error when trying to find policy-related information."
exit -1
fi
findMapFile $policy $policydir
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find map file for policy '$policy'."
exit -1
fi
showLabels $mapfile
else
if [ "$2" == "" ]; then
usage
exit -1
fi
if [ "$3" == "" ]; then
findGrubConf
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf"
exit -1;
fi
findPolicyInGrub $grubconf
if [ "$policy" != "" ]; then
echo "Assuming policy to be '$policy'.";
else
echo "Could not find policy."
exit -1;
fi
else
policy=$3;
setPolicyVars $3 $4
ret=$?
if [ $ret -eq 0 ]; then
echo "Error when trying to find policy-related information."
exit -1
fi
findMapFile $policy
res=$?
if [ "$res" != "0" ]; then
relabel $1 $2 $mapfile $mode
else
echo "Could not find map file for policy '$3'."
findMapFile $policy $policydir
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find map file for policy '$policy'."
exit -1
fi
relabel $1 $2 $mapfile $mode
fi
+35 -143
View File
@@ -22,166 +22,49 @@ if [ -z "$runbash" ]; then
exit
fi
dir=`dirname $0`
source $dir/labelfuncs.sh
acmroot=$ACM_DEFAULT_ROOT
# Show usage of this program
usage ()
{
prg=`basename $0`
echo "Use this tool to add the binary policy to the Xen grub entry and
have Xen automatically enforce the policy when starting.
Usage: $0 <policy name> <root of xen repository>
<policy name> : The name of the policy, i.e. xen_null
<root of xen repository> : The root of the XEN repository. Give
complete path.
Usage: $prg [-d <policies root>] <policy name> [<kernel version>]
<policies root> : The directory where the policies directory is located in;
default is $acmroot
<policy name> : The name of the policy, i.e. xen_null
<kernel version> : The version of the kernel to apply the policy
against, i.e. 2.6.12.6-xen0
If not specified, a kernel version ending with '-xen0'
will be searched for in '/lib/modules'
"
}
# This function sets the global variable 'linux'
# to the name of the linux kernel that was compiled
# For now a pattern should do the trick
getLinuxVersion ()
{
path=$1
linux=""
for f in $path/linux-*-xen0 ; do
versionfile=$f/include/linux/version.h
if [ -r $versionfile ]; then
lnx=`cat $versionfile | \
grep UTS_RELEASE | \
awk '{ \
len=length($3); \
version=substr($3,2,len-2); \
split(version,numbers,"."); \
if (numbers[4]=="") { \
printf("%s.%s.%s", \
numbers[1], \
numbers[2], \
numbers[3]); \
} else { \
printf("%s.%s.%s[.0-9]*-xen0",\
numbers[1], \
numbers[2], \
numbers[3]); \
} \
}'`
fi
if [ "$lnx" != "" ]; then
linux="[./0-9a-zA-z]*$lnx"
return;
fi
done
#Last resort.
linux="vmlinuz-2.[45678].[0-9]*[.0-9]*-xen0$"
}
#Return where the grub.conf file is.
#I only know of one place it can be.
findGrubConf()
{
grubconf="/boot/grub/grub.conf"
if [ -w $grubconf ]; then
return 1
fi
return 0
}
#Update the grub configuration file.
#Search for existing entries and replace the current
#policy entry with the policy passed to this script
#
#Arguments passed to this function
# 1st : the grub configuration file
# 2nd : the binary policy file name
# 3rd : the name or pattern of the linux kernel name to match
#
# The algorithm here is based on pattern matching
# and is working correctly if
# - under a title a line beginning with 'kernel' is found
# whose following item ends with "xen.gz"
# Example: kernel /xen.gz dom0_mem=....
# - a module line matching the 3rd parameter is found
#
updateGrub ()
{
grubconf=$1
policyfile=$2
linux=$3
if [ "$1" == "-h" ]; then
usage
exit 0
elif [ "$1" == "-d" ]; then
shift
acmroot=$1
shift
fi
tmpfile="/tmp/new_grub.conf"
cat $grubconf | \
awk -vpolicy=$policyfile \
-vlinux=$linux '{ \
if ( $1 == "title" ) { \
kernelfound = 0; \
if ( policymaycome == 1 ){ \
printf ("\tmodule %s%s\n", path, policy); \
} \
policymaycome = 0; \
} \
else if ( $1 == "kernel" ) { \
if ( match($2,"xen.gz$") ) { \
path=substr($2,1,RSTART-1); \
kernelfound = 1; \
} \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
match($2,linux) ) { \
policymaycome = 1; \
} \
else if ( $1 == "module" && \
kernelfound == 1 && \
policymaycome == 1 && \
match($2,"[0-9a-zA-Z]*.bin$") ) { \
printf ("\tmodule %s%s\n", path, policy); \
policymaycome = 0; \
kernelfound = 0; \
dontprint = 1; \
} \
else if ( $1 == "" && \
kernelfound == 1 && \
policymaycome == 1) { \
dontprint = 1; \
} \
if (dontprint == 0) { \
printf ("%s\n", $0); \
} \
dontprint = 0; \
} END { \
if ( policymaycome == 1 ) { \
printf ("\tmodule %s%s\n", path, policy); \
} \
}' > $tmpfile
if [ ! -r $tmpfile ]; then
echo "Could not create temporary file! Aborting."
exit -1
fi
diff $tmpfile $grubconf > /dev/null
RES=$?
if [ "$RES" == "0" ]; then
echo "No changes were made to $grubconf."
else
echo "Successfully updated $grubconf."
mv -f $tmpfile $grubconf
fi
}
if [ "$1" == "" -o "$2" == "" ]; then
if [ "$1" == "" ]; then
echo "Error: Not enough command line parameters."
echo ""
usage
exit -1
fi
if [ "$1" == "-?" ]; then
usage
exit 0
fi
policy=$1
policyfile=$policy.bin
@@ -189,10 +72,19 @@ policyfile=$policy.bin
getLinuxVersion $2
findGrubConf
ERR=$?
if [ $ERR -eq 0 ]; then
echo "Could not find grub.conf. Aborting."
ret=$?
if [ $ret -eq 0 ]; then
echo "Could not find grub.conf."
exit -1
elif [ $ret -eq 2 ]; then
echo "Need to have write-access to $grubconf. Exiting."
exit -1
fi
cpBootPolicy /boot $acmroot $policy
ret=$?
if [ $ret -ne 1 ]; then
echo "Error copying or generating the binary policy."
exit -1
fi
updateGrub $grubconf $policyfile $linux
+1
View File
@@ -52,6 +52,7 @@ AC_CONFIG_FILES([
tests/memset/Makefile
tests/migrate/Makefile
tests/network-attach/Makefile
tests/network/Makefile
tests/pause/Makefile
tests/reboot/Makefile
tests/restore/Makefile
+79
View File
@@ -0,0 +1,79 @@
#!/usr/bin/python
"""
Network.py - Common utilities for network tests
Copyright (C) International Business Machines Corp., 2005
Author: Jim Dykman <dykman@us.ibm.com>
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; under version 2 of the License.
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
"""
import sys;
import os;
import atexit;
from Test import *
from Xm import *
class NetworkError(Exception):
def __init__(self, msg):
self.errMsg = msg
def __str__(self):
return str(self.errMsg)
def undo_dom0_alias(eth, ip):
traceCommand("ip addr del " + ip + " dev " + eth)
class XmNetwork:
def __init__(self):
# Check for existing zeroconf address. We are using the zeroconf
# address range as static IP addresses.... if someone is using
# real zeroconf addresses, then we're going to skip tests to
# avoid interfering with them.
rc, out = traceCommand(
"ip addr show |grep \"inet 169.254\" | grep -v vif")
if rc == 0:
SKIP("Zeroconf address found: " + out)
def calc_ip_address(self, dom, interface):
# Generate an IP address from the dom# and eth#:
# 169.254.(eth#+153).(dom#+10)
ethnum = int(interface[len("eth"):])
domnum = int(dom[len("dom"):])
return "169.254."+ str(ethnum+153) + "." + str(domnum+10)
def ip(self, dom, interface, todomname=None, toeth=None):
newip = self.calc_ip_address(dom, interface)
# If the testcase is going to talk to dom0, we need to add an
# IP address in the proper subnet
if dom == "dom0":
# The domain's vif is a convenient place to add to
vifname = "vif" + str(domid(todomname)) + "." + toeth[3:]
# register the exit handler FIRST, just in case
atexit.register(undo_dom0_alias, vifname, newip)
# add the alias
status, output = traceCommand("ip addr add " + newip +
" dev " + vifname)
if status:
SKIP("\"ip addr add\" failed")
return newip
def mask(self, dom, interface):
return "255.255.255.0"
+1
View File
@@ -4,6 +4,7 @@
#
from Console import *
from Network import *
from Test import *
from Xm import *
from XenDomain import *
+1
View File
@@ -13,6 +13,7 @@ SUBDIRS = \
list \
memmax \
memset \
network \
network-attach \
pause \
reboot \
@@ -0,0 +1,84 @@
#!/usr/bin/python
# Copyright (C) International Business Machines Corp., 2005
# Author: <dykman@us.ibm.com>
# Ping tests on local interfaces.
# - creates a single guest domain
# - sets up a single NIC
# - conducts ping tests to the local loopback and IP address.
# ping -c 1 -s $size 127.0.0.1
# ping -c 1 -s $size $local_IP
# where $size = 1, 48, 64, 512, 1440, 1500, 1505,
# 4096, 4192, 32767, 65507, 65508
pingsizes = [ 1, 48, 64, 512, 1440, 1500, 1505, 4096, 4192,
32767, 65507 ]
from XmTestLib import *
rc = 0
Net = XmNetwork()
# read an IP address from the config
ip = Net.ip("dom1", "eth0")
mask = Net.mask("dom1", "eth0")
# Fire up a guest domain w/1 nic
domain = XmTestDomain(extraOpts={ 'nics' : 1 })
try:
domain.configSetVar('vif', " [ 'ip=" + ip + "' ]")
domain.start()
except DomainError, e:
if verbose:
print "Failed to create test domain because:"
print e.extra
FAIL(str(e))
# Attach a console
try:
console = XmConsole(domain.getName(), historySaveCmds=True)
except ConsoleError, e:
FAIL(str(e))
try:
# Activate the console
console.sendInput("bhs")
# Bring up the "lo" interface.
console.runCmd("ifconfig lo up")
console.runCmd("ifconfig eth0 inet "+ip+" netmask "+mask+" up")
# First the loopback pings
lofails=""
for size in pingsizes:
out = console.runCmd("ping -q -c 1 -s " + str(size) + " 127.0.0.1")
if out["return"]:
lofails += " " + str(size)
# Next comes eth0
eth0fails=""
for size in pingsizes:
out = console.runCmd("ping -q -c 1 -s " + str(size) + " " + ip)
if out["return"]:
eth0fails += " " + str(size)
except ConsoleError, e:
FAIL(str(e))
except NetworkError, e:
FAIL(str(e))
# Tally up failures
failures=""
if len(lofails):
failures += "ping loopback failed for size" + lofails + ". "
if len(eth0fails):
failures += "ping eth0 failed for size" + eth0fails + "."
if len(failures):
FAIL(failures)
@@ -0,0 +1,73 @@
#!/usr/bin/python
# Copyright (C) International Business Machines Corp., 2005
# Author: <dykman@us.ibm.com>
# Ping tests to dom0 interface
# - determines dom0 network
# - creates a single guest domain
# - sets up a single NIC on same subnet as dom0
# - conducts ping tests to the dom0 IP address.
# ping -c 1 -s $size $dom0_IP
# where $size = 1, 48, 64, 512, 1440, 1500, 1505,
# 4096, 4192, 32767, 65507, 65508
pingsizes = [ 1, 48, 64, 512, 1440, 1500, 1505, 4096, 4192,
32767, 65507 ]
from XmTestLib import *
rc = 0
Net = XmNetwork()
try:
# read an IP address from the config
ip = Net.ip("dom1", "eth0")
mask = Net.mask("dom1", "eth0")
except NetworkError, e:
FAIL(str(e))
# Fire up a guest domain w/1 nic
domain = XmTestDomain(extraOpts={ 'nics' : 1 })
try:
domain.configSetVar('vif', " [ 'ip=" + ip + "' ]")
domain.start()
except DomainError, e:
if verbose:
print "Failed to create test domain because:"
print e.extra
FAIL(str(e))
# Attach a console
try:
console = XmConsole(domain.getName(), historySaveCmds=True)
# Activate the console
console.sendInput("bhs")
except ConsoleError, e:
FAIL(str(e))
try:
# Add a suitable dom0 IP address
dom0ip = Net.ip("dom0", "eth0", todomname=domain.getName(), toeth="eth0")
except NetworkError, e:
FAIL(str(e))
try:
console.runCmd("ifconfig eth0 inet "+ip+" netmask "+mask+" up")
# Ping dom0
fails=""
for size in pingsizes:
out = console.runCmd("ping -q -c 1 -s " + str(size) + " " + dom0ip)
if out["return"]:
fails += " " + str(size)
except ConsoleError, e:
FAIL(str(e))
if len(fails):
FAIL("Ping to dom0 failed for size" + fails + ".")
@@ -0,0 +1,79 @@
#!/usr/bin/python
# Copyright (C) International Business Machines Corp., 2005
# Author: <dykman@us.ibm.com>
# Ping tests to domU interface
# - creates two guest domains
# - sets up a single NIC on each on same subnet
# - conducts ping tests to the domU IP address.
# ping -c 1 -s $size $domU_IP
# where $size = 1, 48, 64, 512, 1440, 1500, 1505,
# 4096, 4192, 32767, 65507, 65508
pingsizes = [ 1, 48, 64, 512, 1440, 1500, 1505, 4096, 4192,
32767, 65507 ]
from XmTestLib import *
def netDomain(ip):
dom = XmTestDomain(extraOpts={ 'nics' : 1 })
try:
dom.configSetVar('vif', " [ 'ip=" + ip + "' ]")
dom.start()
except DomainError, e:
if verbose:
print "Failed to create test domain because:"
print e.extra
FAIL(str(e))
try:
# Attach a console
console = XmConsole(dom.getName(), historySaveCmds=True)
# Activate the console
console.sendInput("bhs")
except ConsoleError, e:
FAIL(str(e))
return console
rc = 0
Net = XmNetwork()
try:
# pick an IP address
ip1 = Net.ip("dom1", "eth2")
mask1 = Net.mask("dom1", "eth2")
except NetworkError, e:
FAIL(str(e))
try:
# pick another IP address
ip2 = Net.ip("dom2", "eth2")
mask2 = Net.mask("dom2", "eth2")
except NetworkError, e:
FAIL(str(e))
# Fire up a pair of guest domains w/1 nic each
pinger_console = netDomain(ip1)
victim_console = netDomain(ip2)
try:
pinger_console.runCmd("ifconfig eth0 inet "+ip1+" netmask "+mask1+" up")
victim_console.runCmd("ifconfig eth0 inet "+ip2+" netmask "+mask2+" up")
# Ping the victim over eth0
fails=""
for size in pingsizes:
out = pinger_console.runCmd("ping -q -c 1 -s " + str(size) + " " + ip2)
if out["return"]:
fails += " " + str(size)
except ConsoleError, e:
FAIL(str(e))
if len(fails):
FAIL("Ping failed for size" + fails + ".")
+29
View File
@@ -0,0 +1,29 @@
SUBDIRS =
TESTS = \
02_network_local_ping_pos.test \
05_network_dom0_ping_pos.test \
11_network_domU_ping_pos.test
XFAIL_TESTS = \
02_network_local_ping_pos.test \
05_network_dom0_ping_pos.test \
11_network_domU_ping_pos.test
EXTRA_DIST = $(TESTS) $(XFAIL_TESTS)
TESTS_ENVIRONMENT=@TENV@
%.test: %.py
cp $< $@
chmod +x $@
clean-local: am_config_clean-local
am_config_clean-local:
rm -f *test
rm -f *log
rm -f *~
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.