Ejemplo n.º 1
0
static int local_service_generic(struct hostctrl *hc, int type,
                                 const struct service_id *srvid,
                                 unsigned short prefix_bits,
                                 unsigned int priority,
                                 unsigned int weight,
                                 const struct in_addr *ipaddr)
{
    struct {
        struct ctrlmsg_service cm;
        struct service_info service;
    } req;

    if (!srvid)
        return -1;

    memset(&req, 0, sizeof(req));
    req.cm.cmh.type = type;
    req.cm.cmh.xid = ++hc->xid;
    req.cm.cmh.len = CTRLMSG_SERVICE_NUM_LEN(1);
    req.cm.service[0].srvid_prefix_bits =
        (prefix_bits > SERVICE_ID_MAX_PREFIX_BITS) ?
        0 : prefix_bits;
    req.cm.service[0].priority = priority;
    req.cm.service[0].weight = weight;
    memcpy(&req.cm.service[0].srvid, srvid, sizeof(*srvid));

    if (ipaddr)
        memcpy(&req.cm.service[0].address, ipaddr, sizeof(*ipaddr));

    req.cm.service[0].if_index = -1;

    /* strncpy(req.cm.ifname, ifname, IFNAMSIZ - 1); */

    LOG_DBG("op=%d prefix_bits=%u len=%u sizeof(req)=%zu %zu %s\n",
            type, req.cm.service[0].srvid_prefix_bits,
            CTRLMSG_SERVICE_LEN(&req.cm), sizeof(req),
            CTRLMSG_SERVICE_NUM(&req.cm),
            service_id_to_str(&req.cm.service[0].srvid));

    return message_channel_send(hc->mc, &req.cm, req.cm.cmh.len);
}
Ejemplo n.º 2
0
int local_ctrlmsg_recv(struct hostctrl *hc, struct ctrlmsg *cm,
                       struct sockaddr *from, socklen_t from_len)
{
    struct in_addr local_ip;
    int ret = 0;

    if (!hc->cbs)
        return 0;

    memset(&local_ip, 0, sizeof(local_ip));

    if (from) {
        if (from->sa_family == AF_INET)
            memcpy(&local_ip, &((struct sockaddr_in *)from)->sin_addr,
                   sizeof(local_ip));
        else if (from->sa_family == AF_SERVAL &&
                 from_len > sizeof(struct sockaddr_in)) {
            channel_addr_t *addr = (channel_addr_t *)from;

            if (addr->sv_in.in.sin_family == AF_INET) {
                memcpy(&local_ip, &addr->sv_in.in.sin_addr,
                       sizeof(local_ip));
            }
        }
    }

    switch (cm->type) {
    case CTRLMSG_TYPE_REGISTER: {
        struct ctrlmsg_register *cmr = (struct ctrlmsg_register *)cm;
        ret = hc->cbs->service_registration(hc,
                                            &cmr->srvid,
                                            cmr->srvid_flags,
                                            cmr->srvid_prefix_bits,
                                            &local_ip, NULL);
        break;
    }
    case CTRLMSG_TYPE_UNREGISTER: {
        struct ctrlmsg_register *cmr = (struct ctrlmsg_register *)cm;
        ret = hc->cbs->service_unregistration(hc,
                                              &cmr->srvid,
                                              cmr->srvid_flags,
                                              cmr->srvid_prefix_bits,
                                              &local_ip);
        break;
    }
    case CTRLMSG_TYPE_RESOLVE:
        break;
    case CTRLMSG_TYPE_GET_SERVICE: {
        struct ctrlmsg_service *cs =
            (struct ctrlmsg_service *)cm;

        if (hc->cbs->service_get_result)
            ret = hc->cbs->service_get_result(hc,
                                              cm->xid,
                                              cm->retval,
                                              &cs->service[0],
                                              CTRLMSG_SERVICE_NUM(cs));
        break;
    }
    case CTRLMSG_TYPE_SERVICE_STAT: {
        struct ctrlmsg_service_stat *css =
            (struct ctrlmsg_service_stat *)cm;

        if (hc->cbs->service_stat_update)
            ret = hc->cbs->service_stat_update(hc,
                                               cm->xid,
                                               cm->retval,
                                               &css->stats,
                                               CTRLMSG_SERVICE_STAT_NUM(css));
        break;
    }
    case CTRLMSG_TYPE_ADD_SERVICE: {
        struct ctrlmsg_service *cs =
            (struct ctrlmsg_service *)cm;

        if (hc->cbs->service_add_result)
            ret = hc->cbs->service_add_result(hc,
                                              cm->xid,
                                              cm->retval,
                                              &cs->service[0],
                                              CTRLMSG_SERVICE_NUM(cs));
        break;
    }
    case CTRLMSG_TYPE_MOD_SERVICE: {
        struct ctrlmsg_service *cs =
            (struct ctrlmsg_service *)cm;

        if (hc->cbs->service_mod_result)
            ret = hc->cbs->service_mod_result(hc,
                                              cm->xid,
                                              cm->retval,
                                              &cs->service[0],
                                              CTRLMSG_SERVICE_NUM(cs));
        break;
    }
    case CTRLMSG_TYPE_DEL_SERVICE: {
        struct ctrlmsg_service_info_stat *csis =
            (struct ctrlmsg_service_info_stat *)cm;

        if (hc->cbs->service_remove_result)
            ret = hc->cbs->service_remove_result(hc,
                                                 cm->xid,
                                                 cm->retval,
                                                 &csis->service[0],
                                                 CTRLMSG_SERVICE_INFO_STAT_NUM(csis));
        break;
    }
    default:
        LOG_DBG("Received message type %u\n", cm->type);
        break;
    }

    return ret;
}
Ejemplo n.º 3
0
static int ctrl_handle_mod_service_msg(struct ctrlmsg *cm, int peer)
{
        struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm;
        unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr);
        unsigned int i, index = 0;
        int err = 0;

        if (num_res < 2 || num_res % 2 != 0) {
                LOG_DBG("Not an even number of service infos\n");
                return 0;
        }

        LOG_DBG("modifying %u services\n", num_res / 2);

        for (i = 0; i < num_res; i += 2) {
                struct net_device *dev;
                struct service_info *entry_old = &cmr->service[i];
                struct service_info *entry_new = &cmr->service[i+1];
                unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS;
                
                if (entry_old->srvid_prefix_bits > 0)
                        prefix_bits = entry_old->srvid_prefix_bits;

#if defined(ENABLE_DEBUG)
                {
                        char buf[18];
                        LOG_DBG("Modifying: %s flags(%i) bits(%i) %s\n", 
                                service_id_to_str(&entry_old->srvid), 
                                entry_old->srvid_flags, 
                                prefix_bits,
                                inet_ntop(AF_INET, &entry_old->address, 
                                          buf, 18));
                }
#endif
                dev = resolve_dev(entry_old);
                
                if (!dev)
                        continue;

                err = service_modify(&entry_old->srvid,
                                     prefix_bits,
                                     SERVICE_RULE_FORWARD,
                                     entry_old->srvid_flags, 
                                     entry_new->priority, 
                                     entry_new->weight, 
                                     &entry_old->address,
                                     sizeof(entry_old->address),
                                     &entry_new->address,
                                     sizeof(entry_new->address), 
                                     make_target(dev));
                if (err > 0) {
                        if (index < i) {
                                /* copy it over */
                                memcpy(&cmr->service[index], 
                                       entry_new, sizeof(*entry_new));
                        }
                        index++;
                } else {
                        LOG_ERR("Could not modify service %s: %i\n", 
                                service_id_to_str(&entry_old->srvid), 
                                err);
                }
                dev_put(dev);
        }
        
        if (index == 0) {
                cm->retval = CTRLMSG_RETVAL_NOENTRY;
        } else {
                cm->retval = CTRLMSG_RETVAL_OK;
                cm->len = CTRLMSG_SERVICE_NUM_LEN(index);
        }
        
        ctrl_sendmsg(cm, peer, GFP_KERNEL);

        return 0;
}
Ejemplo n.º 4
0
static int ctrl_handle_add_service_msg(struct ctrlmsg *cm, int peer)
{
        struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm;
        unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr);
        /* TODO - flags, etc */
        unsigned int i, index = 0;
        int err = 0;

        LOG_DBG("adding %u services, msg size %u\n", 
                num_res, CTRLMSG_SERVICE_LEN(cmr));
        
        for (i = 0; i < num_res; i++) {
                struct net_device *dev = NULL;
                struct service_info *entry = &cmr->service[i];
                unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS;

                if (entry->type == SERVICE_RULE_FORWARD) {
                        dev = resolve_dev(entry);
                        
                        if (!dev)
                                continue;
                }

                if (entry->srvid_prefix_bits > 0)
                        prefix_bits = entry->srvid_prefix_bits;
         
#if defined(ENABLE_DEBUG)
                {
                        char ipstr[18];
                        LOG_DBG("Adding service id: %s(%u) "
                                "@ address %s, priority %u, weight %u\n", 
                                service_id_to_str(&entry->srvid), 
                                prefix_bits, 
                                inet_ntop(AF_INET, &entry->address,
                                          ipstr, sizeof(ipstr)),
                                entry->priority, entry->weight);
                }
#endif
                err = service_add(&entry->srvid, 
                                  prefix_bits, 
                                  entry->type,
                                  entry->srvid_flags, 
                                  entry->priority, 
                                  entry->weight,
                                  &entry->address, 
                                  sizeof(entry->address),
                                  make_target(dev), GFP_KERNEL);
                if (dev)
                        dev_put(dev);

                if (err > 0) {
                        if (index < i) {
                                /* copy it over */
                                memcpy(&cmr->service[index], 
                                       entry, sizeof(*entry));
                        }
                        index++;
                } else {
                        LOG_ERR("Error adding service %s: err=%d\n", 
                                service_id_to_str(&entry->srvid), err);
                }
        }

        if (index == 0) {
                /* Just return the original request with a return value */
                cm->retval = CTRLMSG_RETVAL_NOENTRY;
        } else {
                /* Return the entries added */
                cm->retval = CTRLMSG_RETVAL_OK;
                cm->len = CTRLMSG_SERVICE_NUM_LEN(index);
        }

        ctrl_sendmsg(cm, peer, GFP_KERNEL);

        return 0;
}
Ejemplo n.º 5
0
static int ctrl_handle_del_service_msg(struct ctrlmsg *cm, int peer)
{
        struct ctrlmsg_service *cmr = (struct ctrlmsg_service *)cm;
        unsigned int num_res = CTRLMSG_SERVICE_NUM(cmr);
        const size_t cmsg_size = sizeof(struct ctrlmsg_service_info_stat) + 
                sizeof(struct service_info_stat) * num_res;
        struct ctrlmsg_service_info_stat *cms;
        struct service_id null_service = { .s_sid = { 0 } };
        unsigned int i = 0, index = 0;
        int err = 0;       

        LOG_DBG("deleting %u services\n", num_res);

        cms = kmalloc(cmsg_size, GFP_KERNEL);

        if (!cms) {
                cm->retval = CTRLMSG_RETVAL_ERROR;
                ctrl_sendmsg(cm, peer, GFP_KERNEL);
                return -ENOMEM;
        }

        memset(cms, 0, cmsg_size);

        for (i = 0; i < num_res; i++) {
                struct service_info *entry = &cmr->service[i];
                struct service_info_stat *stat = &cms->service[index];
                struct target_stats tstat;
                struct service_entry *se;
                unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS;

                /*
                  We might be trying to delete the "default" entry. In
                  that case
                */
                if (memcmp(&entry->srvid, &null_service, 
                           sizeof(null_service)) == 0 ||
                    entry->srvid_prefix_bits > 0)
                        prefix_bits = entry->srvid_prefix_bits;
                
                stat->service.srvid_prefix_bits = prefix_bits;
                se = service_find_exact(&entry->srvid, 
                                        prefix_bits);

                if (!se) {
                        LOG_DBG("No match for serviceID %s:(%u)\n",
                                service_id_to_str(&entry->srvid),
                                prefix_bits);
                        continue;
                }

                memset(&tstat, 0, sizeof(tstat));
                
                err = service_entry_remove_target(se,
                                                  entry->type,
                                                  &entry->address, 
                                                  sizeof(entry->address), 
                                                  &tstat);

                if (err > 0) {
                        stat->duration_sec = tstat.duration_sec;
                        stat->duration_nsec = tstat.duration_nsec;
                        stat->packets_resolved = tstat.packets_resolved;
                        stat->bytes_resolved = tstat.bytes_resolved;
                        stat->packets_dropped = tstat.packets_dropped;
                        stat->bytes_dropped = tstat.packets_dropped;

                        //if (index < i) {
                                memcpy(&stat->service, entry, 
                                       sizeof(*entry));
                        //}
                        LOG_DBG("Service ID %s:%u\n", service_id_to_str(&stat->service.srvid), stat->service.srvid_prefix_bits);
                        index++;
                } else if (err == 0) {
                        LOG_ERR("Could not find target for service %s\n", 
                                service_id_to_str(&entry->srvid));
                } else {
                        LOG_ERR("Could not remove service %s - err %d\n", 
                                service_id_to_str(&entry->srvid), 
                                err);
                }

                service_entry_put(se);
        }

        if (index == 0) {
                cm->retval = CTRLMSG_RETVAL_NOENTRY;
                ctrl_sendmsg(cm, peer, GFP_KERNEL);
        } else {
                cms->cmh.type = CTRLMSG_TYPE_DEL_SERVICE;
                cms->xid = cmr->xid;
                cms->cmh.xid = cm->xid;
                cms->cmh.retval = CTRLMSG_RETVAL_OK;
                cms->cmh.len = CTRLMSG_SERVICE_INFO_STAT_NUM_LEN(index);
                ctrl_sendmsg(&cms->cmh, peer, GFP_KERNEL);
        }

        kfree(cms);

        return 0;
}