#!/bin/sh [ -e /etc/functions.sh ] && . /etc/functions.sh || . ./functions.sh [ -x /sbin/modprobe ] && { insmod="modprobe" rmmod="$insmod -r" } || { insmod="insmod" rmmod="rmmod" } add_insmod() { eval "export isset=\${insmod_$1}" case "$isset" in 1) ;; *) { [ "$2" ] && append INSMOD "$rmmod $1 >&- 2>&-" "$N" append INSMOD "$insmod $* >&- 2>&-" "$N"; export insmod_$1=1 };; esac } [ -e /etc/config/network ] && { # only try to parse network config on openwrt find_ifname() {( reset_cb include /lib/network scan_interfaces config_get "$1" ifname )} } || { find_ifname() { echo "Interface not found." exit 1 } } parse_matching_rule() { local var="$1" local section="$2" local options="$3" local prefix="$4" local suffix="$5" local proto="$6" local mport="" local ports="" append "$var" "$prefix" "$N" for option in $options; do case "$option" in proto) config_get value "$section" proto; proto="${proto:-$value}";; esac done config_get type "$section" TYPE case "$type" in classify) unset pkt; append "$var" "-m mark --mark 0";; default) pkt=1; append "$var" "-m mark --mark 0";; reclassify) pkt=1;; esac append "$var" "${proto:+-p $proto}" for option in $options; do config_get value "$section" "$option" case "$pkt:$option" in *:srchost) append "$var" "-s $value" ;; *:dsthost) append "$var" "-d $value" ;; *:layer7) add_insmod ipt_layer7 add_insmod xt_layer7 append "$var" "-m layer7 --l7proto $value${pkt:+ --l7pkt}" ;; *:ports|*:srcports|*:dstports) value="$(echo "$value" | sed -e 's,-,:,g')" lproto=${lproto:-tcp} case "$proto" in ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} -m multiport";; *) unset "$var"; return 0;; esac case "$option" in ports) config_set "$section" srcports "" config_set "$section" dstports "" config_set "$section" portrange "" append "$var" "--ports $value" ;; srcports) config_set "$section" ports "" config_set "$section" dstports "" config_set "$section" portrange "" append "$var" "--sports $value" ;; dstports) config_set "$section" ports "" config_set "$section" srcports "" config_set "$section" portrange "" append "$var" "--dports $value" ;; esac ports=1 ;; *:portrange) config_set "$section" ports "" config_set "$section" srcports "" config_set "$section" dstports "" value="$(echo "$value" | sed -e 's,-,:,g')" case "$proto" in ""|tcp|udp) append "$var" "-m ${proto:-tcp -p tcp} --sport $value --dport $value";; *) unset "$var"; return 0;; esac ports=1 ;; *:connbytes) value="$(echo "$value" | sed -e 's,-,:,g')" add_insmod ipt_connbytes append "$var" "-m connbytes --connbytes $value --connbytes-dir both --connbytes-mode bytes" ;; *:tos) add_insmod ipt_tos case "$value" in !*) append "$var" "-m tos ! --tos $value";; *) append "$var" "-m tos --tos $value" esac ;; *:dscp) add_insmod ipt_dscp dscp_option="--dscp" [ -z "${value%%[EBCA]*}" ] && dscp_option="--dscp-class" case "$value" in !*) append "$var" "-m dscp ! $dscp_option $value";; *) append "$var" "-m dscp $dscp_option $value" esac ;; *:direction) value="$(echo "$value" | sed -e 's,-,:,g')" if [ "$value" = "out" ]; then append "$var" "-o $device" elif [ "$value" = "in" ]; then append "$var" "-i $device" fi ;; 1:pktsize) value="$(echo "$value" | sed -e 's,-,:,g')" add_insmod ipt_length append "$var" "-m length --length $value" ;; 1:limit) add_insmod ipt_limit append "$var" "-m limit --limit $value" ;; 1:tcpflags) case "$proto" in tcp) append "$var" "-m tcp --tcp-flags ALL $value";; *) unset $var; return 0;; esac ;; 1:mark) config_get class "${value##!}" classnr [ -z "$class" ] && continue; case "$value" in !*) append "$var" "-m mark ! --mark $class";; *) append "$var" "-m mark --mark $class";; esac ;; 1:TOS) add_insmod ipt_TOS config_get TOS "$rule" 'TOS' suffix="-j TOS --set-tos "${TOS:-"Normal-Service"} ;; 1:DSCP) add_insmod ipt_DSCP config_get DSCP "$rule" 'DSCP' [ -z "${DSCP%%[EBCA]*}" ] && set_value="--set-dscp-class $DSCP" \ || set_value="--set-dscp $DSCP" suffix="-j DSCP $set_value" ;; esac done append "$var" "$suffix" case "$ports:$proto" in 1:) parse_matching_rule "$var" "$section" "$options" "$prefix" "$suffix" "udp";; esac } config_cb() { option_cb() { return 0 } # Section start case "$1" in interface) config_set "$2" "classgroup" "Default" config_set "$2" "upload" "128" ;; classify|default|reclassify) option_cb() { append options "$1" } ;; esac # Section end config_get TYPE "$CONFIG_SECTION" TYPE case "$TYPE" in interface) config_get_bool enabled "$CONFIG_SECTION" enabled 1 [ 1 -eq "$enabled" ] || return 0 config_get classgroup "$CONFIG_SECTION" classgroup config_set "$CONFIG_SECTION" imqdev "$C" C=$(($C+1)) append INTERFACES "$CONFIG_SECTION" config_set "$classgroup" enabled 1 config_get device "$CONFIG_SECTION" device [ -z "$device" ] && { device="$(find_ifname ${CONFIG_SECTION})" config_set "$CONFIG_SECTION" device "${device:-eth0}" } ;; classgroup) append CG "$CONFIG_SECTION";; classify|default|reclassify) case "$TYPE" in classify) var="ctrules";; *) var="rules";; esac config_get target "$CONFIG_SECTION" target config_set "$CONFIG_SECTION" options "$options" append "$var" "$CONFIG_SECTION" unset options ;; esac } enum_classes() { local c="0" config_get classes "$1" classes config_get default "$1" default for class in $classes; do c="$(($c + 1))" config_set "${class}" classnr $c case "$class" in $default) class_default=$c;; esac done class_default="${class_default:-$c}" } cls_var() { local varname="$1" local class="$2" local name="$3" local type="$4" local default="$5" local tmp tmp1 tmp2 config_get tmp1 "$class" "$name" config_get tmp2 "${class}_${type}" "$name" tmp="${tmp2:-$tmp1}" tmp="${tmp:-$tmp2}" export ${varname}="${tmp:-$default}" } tcrules() { dir=/usr/lib/qos [ -e $dir/tcrules.awk ] || dir=. echo "$cstr" | awk \ -v device="$dev" \ -v linespeed="$rate" \ -f $dir/tcrules.awk } start_interface() { local iface="$1" local num_imq="$2" config_get device "$iface" device config_get_bool enabled "$iface" enabled 1 [ -z "$device" -o 1 -ne "$enabled" ] && { return 1 } config_get upload "$iface" upload config_get_bool halfduplex "$iface" halfduplex config_get download "$iface" download config_get classgroup "$iface" classgroup config_get_bool overhead "$iface" overhead 0 download="${download:-${halfduplex:+$upload}}" enum_classes "$classgroup" for dir in ${halfduplex:-up} ${download:+down}; do case "$dir" in up) [ "$overhead" = 1 ] && upload=$(($upload * 98 / 100 - (15 * 128 / $upload))) dev="$device" rate="$upload" dl_mode="" prefix="cls" ;; down) [ "$(ls -d /proc/sys/net/ipv4/conf/imq* 2>&- | wc -l)" -ne "$num_imq" ] && add_insmod imq numdevs="$num_imq" config_get imqdev "$iface" imqdev [ "$overhead" = 1 ] && download=$(($download * 98 / 100 - (80 * 1024 / $download))) dev="imq$imqdev" rate="$download" dl_mode=1 prefix="d_cls" ;; *) continue;; esac cstr= for class in $classes; do cls_var pktsize "$class" packetsize $dir 1500 cls_var pktdelay "$class" packetdelay $dir 0 cls_var maxrate "$class" limitrate $dir 100 cls_var prio "$class" priority $dir 1 cls_var avgrate "$class" avgrate $dir 0 cls_var qdisc_esfq "$class" qdisc_esfq $dir "" [ "$qdisc_esfq" != "" ] && add_insmod sch_esfq config_get classnr "$class" classnr append cstr "$classnr:$prio:$avgrate:$pktsize:$pktdelay:$maxrate:$qdisc_esfq" "$N" done append ${prefix}q "$(tcrules)" "$N" export dev_${dir}="ifconfig $dev up txqueuelen 5 >&- 2>&- tc qdisc del dev $dev root >&- 2>&- tc qdisc add dev $dev root handle 1: hfsc default ${class_default}0 tc class add dev $dev parent 1: classid 1:1 hfsc sc rate ${rate}kbit ul rate ${rate}kbit" done add_insmod cls_fw add_insmod sch_hfsc add_insmod sch_sfq add_insmod sch_red cat <&- 2>&- iptables -t mangle -N ${cg}_ct >&- 2>&- ${iptrules:+${iptrules}${N}iptables -t mangle -A ${cg}_ct -j CONNMARK --save-mark} iptables -t mangle -A ${cg} -j CONNMARK --restore-mark iptables -t mangle -A ${cg} -m mark --mark 0 -j ${cg}_ct $pktrules $up$N${down:+${down}$N} EOF unset INSMOD } start_firewall() { add_insmod ipt_multiport add_insmod ipt_CONNMARK cat <262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
/******************************************************************************
 * domain.c
 * 
 * Generic domain-handling functions.
 */

#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/mm.h>
#include <xen/event.h>
#include <xen/time.h>
#include <xen/console.h>
#include <asm/shadow.h>
#include <hypervisor-ifs/dom0_ops.h>
#include <asm/domain_page.h>

/* Both these structures are protected by the tasklist_lock. */
rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED;
struct domain *task_hash[TASK_HASH_SIZE];
struct domain *task_list;

struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
{
    char buf[100];
    struct domain *d, **pd;
    unsigned long flags;

    if ( (d = alloc_domain_struct()) == NULL )
        return NULL;

    atomic_set(&d->refcnt, 1);
    atomic_set(&d->pausecnt, 0);

    shadow_lock_init(d);

    d->domain    = dom_id;
    d->processor = cpu;
    d->create_time = NOW();
    /* Initialise the sleep_lock */
    spin_lock_init(&d->sleep_lock);
 
    memcpy(&d->thread, &idle0_task.thread, sizeof(d->thread));

    if ( d->domain != IDLE_DOMAIN_ID )
    {
        if ( init_event_channels(d) != 0 )
        {
            free_domain_struct(d);
            return NULL;
        }
        
        /* We use a large intermediate to avoid overflow in sprintf. */
        sprintf(buf, "Domain-%u", dom_id);
        strncpy(d->name, buf, MAX_DOMAIN_NAME);
        d->name[MAX_DOMAIN_NAME-1] = '\0';

        d->addr_limit = USER_DS;
        
        spin_lock_init(&d->page_alloc_lock);
        INIT_LIST_HEAD(&d->page_list);
        d->max_pages = d->tot_pages = 0;

	arch_do_createdomain(d);

        /* Per-domain PCI-device list. */
        spin_lock_init(&d->pcidev_lock);
        INIT_LIST_HEAD(&d->pcidev_list);

        sched_add_domain(d);

        write_lock_irqsave(&tasklist_lock, flags);
        pd = &task_list; /* NB. task_list is maintained in order of dom_id. */
        for ( pd = &task_list; *pd != NULL; pd = &(*pd)->next_list )
            if ( (*pd)->domain > d->domain )
                break;
        d->next_list = *pd;
        *pd = d;
        d->next_hash = task_hash[TASK_HASH(dom_id)];
        task_hash[TASK_HASH(dom_id)] = d;
        write_unlock_irqrestore(&tasklist_lock, flags);
    }
    else
    {
        sprintf(d->name, "Idle-%d", cpu);
        sched_add_domain(d);
    }

    return d;
}


struct domain *find_domain_by_id(domid_t dom)
{
    struct domain *d;
    unsigned long flags;

    read_lock_irqsave(&tasklist_lock, flags);
    d = task_hash[TASK_HASH(dom)];
    while ( d != NULL )
    {
        if ( d->domain == dom )
        {
            if ( unlikely(!get_domain(d)) )
                d = NULL;
            break;
        }
        d = d->next_hash;
    }
    read_unlock_irqrestore(&tasklist_lock, flags);

    return d;
}


/* Return the most recently created domain. */
struct domain *find_last_domain(void)
{
    struct domain *d, *dlast;
    unsigned long flags;

    read_lock_irqsave(&tasklist_lock, flags);
    dlast = task_list;
    d = dlast->next_list;
    while ( d != NULL )
    {
        if ( d->create_time > dlast->create_time )
            dlast = d;
        d = d->next_list;
    }
    if ( !get_domain(dlast) )
        dlast = NULL;
    read_unlock_irqrestore(&tasklist_lock, flags);

    return dlast;
}


void domain_kill(struct domain *d)
{
    domain_pause(d);
    if ( !test_and_set_bit(DF_DYING, &d->flags) )
    {
        sched_rem_domain(d);
        domain_relinquish_memory(d);
        put_domain(d);
    }
}


void domain_crash(void)
{
    struct domain *d;

    set_bit(DF_CRASHED, &current->flags);

    d = find_domain_by_id(0);
    send_guest_virq(d, VIRQ_DOM_EXC);
    put_domain(d);
    
    __enter_scheduler();
    BUG();
}

void domain_shutdown(u8 reason)
{
    struct domain *d;

    if ( current->domain == 0 )
    {
        extern void machine_restart(char *);
        extern void machine_halt(void);

        if ( reason == 0 ) 
        {
            printk("Domain 0 halted: Our work here is done.\n");
            machine_halt();
        }
        else
        {
            printk("Domain 0 shutdown: rebooting machine!\n");
            machine_restart(0);
        }
    }

    current->shutdown_code = reason;
    set_bit(DF_SHUTDOWN, &current->flags);

    d = find_domain_by_id(0);
    send_guest_virq(d, VIRQ_DOM_EXC);
    put_domain(d);

    __enter_scheduler();
}

unsigned int alloc_new_dom_mem(struct domain *d, unsigned int kbytes)
{
    unsigned int alloc_pfns, nr_pages;
    struct pfn_info *page;

    nr_pages = (kbytes + ((PAGE_SIZE-1)>>10)) >> (PAGE_SHIFT - 10);
    d->max_pages = nr_pages; /* this can now be controlled independently */

    /* Grow the allocation if necessary. */
    for ( alloc_pfns = d->tot_pages; alloc_pfns < nr_pages; alloc_pfns++ )
    {
        if ( unlikely((page = alloc_domheap_page(d)) == NULL) )
        {
            domain_relinquish_memory(d);
            return -ENOMEM;
        }

        /* initialise to machine_to_phys_mapping table to likely pfn */
        machine_to_phys_mapping[page-frame_table] = alloc_pfns;

#ifndef NDEBUG
        {
            /* Initialise with magic marker if in DEBUG mode. */
            void *a = map_domain_mem((page-frame_table)<<PAGE_SHIFT);
            memset(a, 0x80 | (char)d->domain, PAGE_SIZE);
            unmap_domain_mem(a);
        }
#endif
    }

    return 0;
}
 

/* Release resources belonging to task @p. */
void domain_destruct(struct domain *d)
{
    struct domain **pd;
    unsigned long flags;

    if ( !test_bit(DF_DYING, &d->flags) )
        BUG();

    /* May be already destructed, or get_domain() can race us. */
    if ( cmpxchg(&d->refcnt.counter, 0, DOMAIN_DESTRUCTED) != 0 )
        return;

    DPRINTK("Releasing task %u\n", d->domain);

    /* Delete from task list and task hashtable. */
    write_lock_irqsave(&tasklist_lock, flags);
    pd = &task_list;
    while ( *pd != d ) 
        pd = &(*pd)->next_list;
    *pd = d->next_list;
    pd = &task_hash[TASK_HASH(d->domain)];
    while ( *pd != d ) 
        pd = &(*pd)->next_hash;
    *pd = d->next_hash;
    write_unlock_irqrestore(&tasklist_lock, flags);

    destroy_event_channels(d);

    free_perdomain_pt(d);
    free_xenheap_page((unsigned long)d->shared_info);

    free_domain_struct(d);
}


/*
 * final_setup_guestos is used for final setup and launching of domains other
 * than domain 0. ie. the domains that are being built by the userspace dom0
 * domain builder.
 */
int final_setup_guestos(struct domain *p, dom0_builddomain_t *builddomain)
{
    int rc = 0;
    full_execution_context_t *c;

    if ( (c = xmalloc(sizeof(*c))) == NULL )
        return -ENOMEM;

    if ( test_bit(DF_CONSTRUCTED, &p->flags) )
    {
        rc = -EINVAL;
        goto out;
    }

    if ( copy_from_user(c, builddomain->ctxt, sizeof(*c)) )
    {
        rc = -EFAULT;
        goto out;
    }
    
    arch_final_setup_guestos(p,c);

    /* Set up the shared info structure. */
    update_dom_time(p->shared_info);

    set_bit(DF_CONSTRUCTED, &p->flags);

 out:    
    if ( c != NULL )
        xfree(c);
    return rc;
}