static int get_free_port(struct domain *d) { struct evtchn *chn; struct evtchn **grp; int port; if ( d->is_dying ) return -EINVAL; for ( port = 0; port_is_valid(d, port); port++ ) { if ( port > d->max_evtchn_port ) return -ENOSPC; if ( evtchn_from_port(d, port)->state == ECS_FREE ) return port; } if ( port == d->max_evtchns || port > d->max_evtchn_port ) return -ENOSPC; if ( !group_from_port(d, port) ) { grp = xzalloc_array(struct evtchn *, BUCKETS_PER_GROUP); if ( !grp ) return -ENOMEM; group_from_port(d, port) = grp; }
static int flask_get_peer_sid(struct xen_flask_peersid *arg) { int rv = -EINVAL; struct domain *d = current->domain; struct domain *peer; struct evtchn *chn; struct domain_security_struct *dsec; spin_lock(&d->event_lock); if ( !port_is_valid(d, arg->evtchn) ) goto out; chn = evtchn_from_port(d, arg->evtchn); if ( chn->state != ECS_INTERDOMAIN ) goto out; peer = chn->u.interdomain.remote_dom; if ( !peer ) goto out; dsec = peer->ssid; arg->sid = dsec->sid; rv = 0; out: spin_unlock(&d->event_lock); return rv; }
int evtchn_unmask(unsigned int port) { struct domain *d = current->domain; struct vcpu *v; ASSERT(spin_is_locked(&d->event_lock)); if ( unlikely(!port_is_valid(d, port)) ) return -EINVAL; v = d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; /* * These operations must happen in strict order. Based on * include/xen/event.h:evtchn_set_pending(). */ if ( test_and_clear_bit(port, &shared_info(d, evtchn_mask)) && test_bit (port, &shared_info(d, evtchn_pending)) && !test_and_set_bit (port / BITS_PER_EVTCHN_WORD(d), &vcpu_info(v, evtchn_pending_sel)) ) { vcpu_mark_events_pending(v); } return 0; }
static int get_free_port(struct domain *d) { struct evtchn *chn; int port; int i, j; if ( d->is_dying ) return -EINVAL; for ( port = 0; port_is_valid(d, port); port++ ) if ( evtchn_from_port(d, port)->state == ECS_FREE ) return port; if ( port == MAX_EVTCHNS(d) ) return -ENOSPC; chn = xzalloc_array(struct evtchn, EVTCHNS_PER_BUCKET); if ( unlikely(chn == NULL) ) return -ENOMEM; bucket_from_port(d, port) = chn; for ( i = 0; i < EVTCHNS_PER_BUCKET; i++ ) { if ( xsm_alloc_security_evtchn(&chn[i]) ) { for ( j = 0; j < i; j++ ) xsm_free_security_evtchn(&chn[j]); xfree(chn); return -ENOMEM; } } return port; }
/** * Check whether host is connectible. * * i.e. that it has a valid port and that its IP address is not private * nor bogus. */ gboolean host_is_valid(const host_addr_t addr, guint16 port) { if (!port_is_valid(port)) return FALSE; return host_address_is_usable(addr); }
long evtchn_bind_vcpu(unsigned int port, unsigned int vcpu_id) { struct domain *d = current->domain; struct evtchn *chn; long rc = 0; if ( (vcpu_id >= d->max_vcpus) || (d->vcpu[vcpu_id] == NULL) ) return -ENOENT; spin_lock(&d->event_lock); if ( !port_is_valid(d, port) ) { rc = -EINVAL; goto out; } chn = evtchn_from_port(d, port); /* Guest cannot re-bind a Xen-attached event channel. */ if ( unlikely(consumer_is_xen(chn)) ) { rc = -EINVAL; goto out; } switch ( chn->state ) { case ECS_VIRQ: if ( virq_is_global(chn->u.virq) ) chn->notify_vcpu_id = vcpu_id; else rc = -EINVAL; break; case ECS_UNBOUND: case ECS_INTERDOMAIN: chn->notify_vcpu_id = vcpu_id; break; case ECS_PIRQ: if ( chn->notify_vcpu_id == vcpu_id ) break; unlink_pirq_port(chn, d->vcpu[chn->notify_vcpu_id]); chn->notify_vcpu_id = vcpu_id; pirq_set_affinity(d, chn->u.pirq.irq, cpumask_of(d->vcpu[vcpu_id]->processor)); link_pirq_port(port, chn, d->vcpu[vcpu_id]); break; default: rc = -EINVAL; break; } out: spin_unlock(&d->event_lock); return rc; }
int evtchn_send(struct domain *d, unsigned int lport) { struct evtchn *lchn, *rchn; struct domain *ld = d, *rd; struct vcpu *rvcpu; int rport, ret = 0; spin_lock(&ld->event_lock); if ( unlikely(!port_is_valid(ld, lport)) ) { spin_unlock(&ld->event_lock); return -EINVAL; } lchn = evtchn_from_port(ld, lport); /* Guest cannot send via a Xen-attached event channel. */ if ( unlikely(consumer_is_xen(lchn)) ) { spin_unlock(&ld->event_lock); return -EINVAL; } ret = xsm_evtchn_send(ld, lchn); if ( ret ) goto out; switch ( lchn->state ) { case ECS_INTERDOMAIN: rd = lchn->u.interdomain.remote_dom; rport = lchn->u.interdomain.remote_port; rchn = evtchn_from_port(rd, rport); rvcpu = rd->vcpu[rchn->notify_vcpu_id]; if ( consumer_is_xen(rchn) ) (*xen_notification_fn(rchn))(rvcpu, rport); else evtchn_set_pending(rvcpu, rport); break; case ECS_IPI: evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); break; case ECS_UNBOUND: /* silently drop the notification */ break; default: ret = -EINVAL; } out: spin_unlock(&ld->event_lock); return ret; }
void cmd_port_down(uint8_t port_id) { int err; if (!port_is_valid(port_id)) { return ; } if ((err = rte_eth_dev_set_link_down(port_id)) == 0) { plog_info("Bringing port %d down\n", port_id); } else { plog_warn("Failed to bring port %d down with error %d\n", port_id, err); } }
void magnet_add_sha1_source(struct magnet_resource *res, const struct sha1 *sha1, const host_addr_t addr, const uint16 port, const struct guid *guid, const gnet_host_vec_t *proxies) { struct magnet_source *s; g_return_if_fail(res); g_return_if_fail(sha1); g_return_if_fail(!res->sha1 || sha1_eq(res->sha1, sha1)); g_return_if_fail(guid != NULL || port_is_valid(port)); if (!res->sha1) { magnet_set_sha1(res, sha1); } s = magnet_source_new(); s->addr = addr; s->port = port; s->sha1 = atom_sha1_get(sha1); s->guid = guid ? atom_guid_get(guid) : NULL; if (proxies != NULL) { int i, n; GSList *sl = NULL; n = gnet_host_vec_count(proxies); for (i = 0; i < n; i++) { gnet_host_t host; host = gnet_host_vec_get(proxies, i); sl = g_slist_prepend(sl, gnet_host_dup(&host)); } s->proxies = sl; } magnet_add_source(res, s); }
void cmd_portinfo(uint8_t port_id) { if (!port_is_valid(port_id)) { return ; } struct dppd_port_cfg* port_cfg = &dppd_port_cfg[port_id]; plog_info("Port info for port %u\n", port_id); plog_info("\tName: %s\n", port_cfg->name); plog_info("\tDriver: %s\n", port_cfg->driver_name); plog_info("\tMac address: "MAC_BYTES_FMT"\n", MAC_BYTES(port_cfg->eth_addr.addr_bytes)); plog_info("\tLink speed: %u Mbps\n", port_cfg->link_speed); plog_info("\tLink status: %s\n", port_cfg->link_up? "up" : "down"); plog_info("\tSocket: %u\n", port_cfg->socket); plog_info("\tPromiscuous: %s\n", port_cfg->promiscuous? "yes" : "no"); plog_info("\tNumber of RX/TX descriptors: %u/%u\n", port_cfg->n_rxd, port_cfg->n_txd); plog_info("\tNumber of RX/TX queues: %u/%u (max: %u/%u)\n", port_cfg->n_rxq, port_cfg->n_txq, port_cfg->max_rxq, port_cfg->max_txq); plog_info("\tMemory pools:\n"); for (uint8_t i = 0; i < 32; ++i) { if (port_cfg->pool[i]) { plog_info("\t\tname: %s (%p)\n", port_cfg->pool[i]->name, port_cfg->pool[i]); } } }
static long evtchn_reset(evtchn_reset_t *r) { domid_t dom = r->dom; struct domain *d; int i, rc; rc = rcu_lock_target_domain_by_id(dom, &d); if ( rc ) return rc; rc = xsm_evtchn_reset(current->domain, d); if ( rc ) goto out; for ( i = 0; port_is_valid(d, i); i++ ) (void)__evtchn_close(d, i); rc = 0; out: rcu_unlock_domain(d); return rc; }
long evtchn_send(unsigned int lport) { struct evtchn *lchn, *rchn; struct domain *ld = current->domain, *rd; struct vcpu *rvcpu; int rport, ret = 0; spin_lock(&ld->evtchn_lock); if ( unlikely(!port_is_valid(ld, lport)) ) { spin_unlock(&ld->evtchn_lock); return -EINVAL; } lchn = evtchn_from_port(ld, lport); /* Guest cannot send via a Xen-attached event channel. */ if ( unlikely(lchn->consumer_is_xen) ) { spin_unlock(&ld->evtchn_lock); return -EINVAL; } ret = xsm_evtchn_send(ld, lchn); if ( ret ) goto out; switch ( lchn->state ) { case ECS_INTERDOMAIN: rd = lchn->u.interdomain.remote_dom; rport = lchn->u.interdomain.remote_port; rchn = evtchn_from_port(rd, rport); rvcpu = rd->vcpu[rchn->notify_vcpu_id]; if ( rchn->consumer_is_xen ) { /* Xen consumers need notification only if they are blocked. */ if ( test_and_clear_bit(_VPF_blocked_in_xen, &rvcpu->pause_flags) ) vcpu_wake(rvcpu); } else { evtchn_set_pending(rvcpu, rport); } break; case ECS_IPI: evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); break; case ECS_UNBOUND: /* silently drop the notification */ break; default: ret = -EINVAL; } out: spin_unlock(&ld->evtchn_lock); return ret; }
static long __evtchn_close(struct domain *d1, int port1) { struct domain *d2 = NULL; struct vcpu *v; struct evtchn *chn1, *chn2; int port2; long rc = 0; again: spin_lock(&d1->evtchn_lock); if ( !port_is_valid(d1, port1) ) { rc = -EINVAL; goto out; } chn1 = evtchn_from_port(d1, port1); /* Guest cannot close a Xen-attached event channel. */ if ( unlikely(chn1->consumer_is_xen) ) { rc = -EINVAL; goto out; } switch ( chn1->state ) { case ECS_FREE: case ECS_RESERVED: rc = -EINVAL; goto out; case ECS_UNBOUND: break; case ECS_PIRQ: pirq_guest_unbind(d1, chn1->u.pirq); d1->pirq_to_evtchn[chn1->u.pirq] = 0; break; case ECS_VIRQ: for_each_vcpu ( d1, v ) { if ( v->virq_to_evtchn[chn1->u.virq] != port1 ) continue; v->virq_to_evtchn[chn1->u.virq] = 0; spin_barrier(&v->virq_lock); } break; case ECS_IPI: break; case ECS_INTERDOMAIN: if ( d2 == NULL ) { d2 = chn1->u.interdomain.remote_dom; /* If we unlock d1 then we could lose d2. Must get a reference. */ if ( unlikely(!get_domain(d2)) ) BUG(); if ( d1 < d2 ) { spin_lock(&d2->evtchn_lock); } else if ( d1 != d2 ) { spin_unlock(&d1->evtchn_lock); spin_lock(&d2->evtchn_lock); goto again; } } else if ( d2 != chn1->u.interdomain.remote_dom ) { /* * We can only get here if the port was closed and re-bound after * unlocking d1 but before locking d2 above. We could retry but * it is easier to return the same error as if we had seen the * port in ECS_CLOSED. It must have passed through that state for * us to end up here, so it's a valid error to return. */ rc = -EINVAL; goto out; } port2 = chn1->u.interdomain.remote_port; BUG_ON(!port_is_valid(d2, port2)); chn2 = evtchn_from_port(d2, port2); BUG_ON(chn2->state != ECS_INTERDOMAIN); BUG_ON(chn2->u.interdomain.remote_dom != d1); chn2->state = ECS_UNBOUND; chn2->u.unbound.remote_domid = d1->domain_id; break; default: BUG(); } /* Clear pending event to avoid unexpected behavior on re-bind. */ clear_bit(port1, shared_info_addr(d1, evtchn_pending)); /* Reset binding to vcpu0 when the channel is freed. */ chn1->state = ECS_FREE; chn1->notify_vcpu_id = 0; xsm_evtchn_close_post(chn1); out: if ( d2 != NULL ) { if ( d1 != d2 ) spin_unlock(&d2->evtchn_lock); put_domain(d2); } spin_unlock(&d1->evtchn_lock); return rc; }
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind) { struct evtchn *lchn, *rchn; struct domain *ld = current->domain, *rd; int lport, rport = bind->remote_port; domid_t rdom = bind->remote_dom; long rc; if ( rdom == DOMID_SELF ) rdom = current->domain->domain_id; if ( (rd = rcu_lock_domain_by_id(rdom)) == NULL ) return -ESRCH; /* Avoid deadlock by first acquiring lock of domain with smaller id. */ if ( ld < rd ) { spin_lock(&ld->evtchn_lock); spin_lock(&rd->evtchn_lock); } else { if ( ld != rd ) spin_lock(&rd->evtchn_lock); spin_lock(&ld->evtchn_lock); } if ( (lport = get_free_port(ld)) < 0 ) ERROR_EXIT(lport); lchn = evtchn_from_port(ld, lport); if ( !port_is_valid(rd, rport) ) ERROR_EXIT_DOM(-EINVAL, rd); rchn = evtchn_from_port(rd, rport); if ( (rchn->state != ECS_UNBOUND) || (rchn->u.unbound.remote_domid != ld->domain_id) ) ERROR_EXIT_DOM(-EINVAL, rd); rc = xsm_evtchn_interdomain(ld, lchn, rd, rchn); if ( rc ) goto out; lchn->u.interdomain.remote_dom = rd; lchn->u.interdomain.remote_port = (u16)rport; lchn->state = ECS_INTERDOMAIN; rchn->u.interdomain.remote_dom = ld; rchn->u.interdomain.remote_port = (u16)lport; rchn->state = ECS_INTERDOMAIN; /* * We may have lost notifications on the remote unbound port. Fix that up * here by conservatively always setting a notification on the local port. */ evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport); bind->local_port = lport; out: spin_unlock(&ld->evtchn_lock); if ( ld != rd ) spin_unlock(&rd->evtchn_lock); rcu_unlock_domain(rd); return rc; }
static long evtchn_status(evtchn_status_t *status) { struct domain *d; domid_t dom = status->dom; int port = status->port; struct evtchn *chn; long rc = 0; rc = rcu_lock_target_domain_by_id(dom, &d); if ( rc ) return rc; spin_lock(&d->event_lock); if ( !port_is_valid(d, port) ) { rc = -EINVAL; goto out; } chn = evtchn_from_port(d, port); rc = xsm_evtchn_status(d, chn); if ( rc ) goto out; switch ( chn->state ) { case ECS_FREE: case ECS_RESERVED: status->status = EVTCHNSTAT_closed; break; case ECS_UNBOUND: status->status = EVTCHNSTAT_unbound; status->u.unbound.dom = chn->u.unbound.remote_domid; break; case ECS_INTERDOMAIN: status->status = EVTCHNSTAT_interdomain; status->u.interdomain.dom = chn->u.interdomain.remote_dom->domain_id; status->u.interdomain.port = chn->u.interdomain.remote_port; break; case ECS_PIRQ: status->status = EVTCHNSTAT_pirq; status->u.pirq = chn->u.pirq.irq; break; case ECS_VIRQ: status->status = EVTCHNSTAT_virq; status->u.virq = chn->u.virq; break; case ECS_IPI: status->status = EVTCHNSTAT_ipi; break; default: BUG(); } status->vcpu = chn->notify_vcpu_id; out: spin_unlock(&d->event_lock); rcu_unlock_domain(d); return rc; }