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); }
static int local_service_modify(struct hostctrl *hc, const struct service_id *srvid, unsigned short prefix_bits, unsigned int priority, unsigned int weight, const struct in_addr *old_ip, const struct in_addr *new_ip) { struct { struct ctrlmsg_service cm; struct service_info service[2]; } req; if (!srvid || !old_ip) return -1; memset(&req, 0, sizeof(req)); req.cm.cmh.type = CTRLMSG_TYPE_MOD_SERVICE; req.cm.cmh.len = CTRLMSG_SERVICE_NUM_LEN(2); req.cm.cmh.xid = ++hc->xid; req.service[0].srvid_prefix_bits = (prefix_bits > SERVICE_ID_MAX_PREFIX_BITS) ? 0 : prefix_bits; req.service[0].priority = priority; req.service[0].weight = weight; memcpy(&req.service[0].srvid, srvid, sizeof(*srvid)); memcpy(&req.service[0].address, old_ip, sizeof(*old_ip)); req.service[0].if_index = -1; req.service[1].if_index = -1; if (!new_ip) memcpy(&req.service[1].address, old_ip, sizeof(*old_ip)); else memcpy(&req.service[1].address, new_ip, sizeof(*new_ip)); /* strncpy(cm.ifname, ifname, IFNAMSIZ - 1); */ return message_channel_send(hc->mc, &req.cm, req.cm.cmh.len); }
static int ctrl_handle_get_service_msg(struct ctrlmsg *cm, int peer) { struct ctrlmsg_service *cmg = (struct ctrlmsg_service *)cm; struct service_entry *se; struct service_iter iter; unsigned short prefix_bits = SERVICE_ID_MAX_PREFIX_BITS; struct target *t; LOG_DBG("getting service: %s\n", service_id_to_str(&cmg->service[0].srvid)); if (cmg->service[0].srvid_prefix_bits > 0) prefix_bits = cmg->service[0].srvid_prefix_bits; se = service_find(&cmg->service[0].srvid, prefix_bits); if (se) { struct ctrlmsg_service *cres; size_t size = CTRLMSG_SERVICE_NUM_LEN(se->count); int i = 0; cres = kmalloc(size, GFP_KERNEL); if (!cres) { service_entry_put(se); cm->retval = CTRLMSG_RETVAL_ERROR; ctrl_sendmsg(cm, peer, GFP_KERNEL); return -ENOMEM; } memset(cres, 0, size); cres->cmh.type = CTRLMSG_TYPE_GET_SERVICE; cres->cmh.len = size; cres->cmh.xid = cm->xid; cres->xid = cmg->xid; memset(&iter, 0, sizeof(iter)); service_iter_init(&iter, se, SERVICE_ITER_FORWARD); while ((t = service_iter_next(&iter)) != NULL) { struct service_info *entry = &cres->service[i++]; service_get_id(se, &entry->srvid); memcpy(&entry->address, t->dst, t->dstlen); entry->srvid_prefix_bits = service_get_prefix_bits(se); entry->srvid_flags = service_iter_get_flags(&iter); entry->weight = t->weight; entry->priority = service_iter_get_priority(&iter); #if defined(ENABLE_DEBUG) { char buf[18]; LOG_DBG("Get %s %s priority=%u weight=%u\n", service_id_to_str(&entry->srvid), inet_ntop(AF_INET, &t->dst, buf, 18), entry->priority, entry->weight); } #endif } service_iter_destroy(&iter); service_entry_put(se); if (i == 0) cres->cmh.retval = CTRLMSG_RETVAL_NOENTRY; else cres->cmh.retval = CTRLMSG_RETVAL_OK; ctrl_sendmsg(&cres->cmh, peer, GFP_KERNEL); kfree(cres); LOG_DBG("Service %s matched %u entries. msg_len=%u\n", service_id_to_str(&cmg->service[0].srvid), se->count, cres->cmh.len); } else { cmg->service[0].srvid_flags = SVSF_INVALID; cmg->cmh.retval = CTRLMSG_RETVAL_NOENTRY; ctrl_sendmsg(&cmg->cmh, peer, GFP_KERNEL); LOG_DBG("Service %s not found\n", service_id_to_str(&cmg->service[0].srvid)); } return 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; }
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; }