📄 ip_vs_ctl.c
字号:
rc = seq_open(file, &ip_vs_info_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s; memset(s, 0, sizeof(*s));out: return rc;out_kfree: kfree(s); goto out;}static struct file_operations ip_vs_info_fops = { .owner = THIS_MODULE, .open = ip_vs_info_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};#endifstruct ip_vs_stats ip_vs_stats;#ifdef CONFIG_PROC_FSstatic int ip_vs_stats_show(struct seq_file *seq, void *v){/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ seq_puts(seq, " Total Incoming Outgoing Incoming Outgoing\n"); seq_printf(seq, " Conns Packets Packets Bytes Bytes\n"); spin_lock_bh(&ip_vs_stats.lock); seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns, ip_vs_stats.inpkts, ip_vs_stats.outpkts, (unsigned long long) ip_vs_stats.inbytes, (unsigned long long) ip_vs_stats.outbytes);/* 01234567 01234567 01234567 0123456701234567 0123456701234567 */ seq_puts(seq, " Conns/s Pkts/s Pkts/s Bytes/s Bytes/s\n"); seq_printf(seq,"%8X %8X %8X %16X %16X\n", ip_vs_stats.cps, ip_vs_stats.inpps, ip_vs_stats.outpps, ip_vs_stats.inbps, ip_vs_stats.outbps); spin_unlock_bh(&ip_vs_stats.lock); return 0;}static int ip_vs_stats_seq_open(struct inode *inode, struct file *file){ return single_open(file, ip_vs_stats_show, NULL);}static struct file_operations ip_vs_stats_fops = { .owner = THIS_MODULE, .open = ip_vs_stats_seq_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};#endif/* * Set timeout values for tcp tcpfin udp in the timeout_table. */static int ip_vs_set_timeout(struct ip_vs_timeout_user *u){ IP_VS_DBG(2, "Setting timeout tcp:%d tcpfin:%d udp:%d\n", u->tcp_timeout, u->tcp_fin_timeout, u->udp_timeout);#ifdef CONFIG_IP_VS_PROTO_TCP if (u->tcp_timeout) { ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED] = u->tcp_timeout * HZ; } if (u->tcp_fin_timeout) { ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT] = u->tcp_fin_timeout * HZ; }#endif#ifdef CONFIG_IP_VS_PROTO_UDP if (u->udp_timeout) { ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL] = u->udp_timeout * HZ; }#endif return 0;}#define SET_CMDID(cmd) (cmd - IP_VS_BASE_CTL)#define SERVICE_ARG_LEN (sizeof(struct ip_vs_service_user))#define SVCDEST_ARG_LEN (sizeof(struct ip_vs_service_user) + \ sizeof(struct ip_vs_dest_user))#define TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user))#define DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user))#define MAX_ARG_LEN SVCDEST_ARG_LENstatic const unsigned char set_arglen[SET_CMDID(IP_VS_SO_SET_MAX)+1] = { [SET_CMDID(IP_VS_SO_SET_ADD)] = SERVICE_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_EDIT)] = SERVICE_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_DEL)] = SERVICE_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_FLUSH)] = 0, [SET_CMDID(IP_VS_SO_SET_ADDDEST)] = SVCDEST_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_DELDEST)] = SVCDEST_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_EDITDEST)] = SVCDEST_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_TIMEOUT)] = TIMEOUT_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_STARTDAEMON)] = DAEMON_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_STOPDAEMON)] = DAEMON_ARG_LEN, [SET_CMDID(IP_VS_SO_SET_ZERO)] = SERVICE_ARG_LEN,};static intdo_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len){ int ret; unsigned char arg[MAX_ARG_LEN]; struct ip_vs_service_user *usvc; struct ip_vs_service *svc; struct ip_vs_dest_user *udest; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (len != set_arglen[SET_CMDID(cmd)]) { IP_VS_ERR("set_ctl: len %u != %u\n", len, set_arglen[SET_CMDID(cmd)]); return -EINVAL; } if (copy_from_user(arg, user, len) != 0) return -EFAULT; /* increase the module use count */ ip_vs_use_count_inc(); if (down_interruptible(&__ip_vs_mutex)) { ret = -ERESTARTSYS; goto out_dec; } if (cmd == IP_VS_SO_SET_FLUSH) { /* Flush the virtual service */ ret = ip_vs_flush(); goto out_unlock; } else if (cmd == IP_VS_SO_SET_TIMEOUT) { /* Set timeout values for (tcp tcpfin udp) */ ret = ip_vs_set_timeout((struct ip_vs_timeout_user *)arg); goto out_unlock; } else if (cmd == IP_VS_SO_SET_STARTDAEMON) { struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg; ret = start_sync_thread(dm->state, dm->mcast_ifn, dm->syncid); goto out_unlock; } else if (cmd == IP_VS_SO_SET_STOPDAEMON) { struct ip_vs_daemon_user *dm = (struct ip_vs_daemon_user *)arg; ret = stop_sync_thread(dm->state); goto out_unlock; } usvc = (struct ip_vs_service_user *)arg; udest = (struct ip_vs_dest_user *)(usvc + 1); if (cmd == IP_VS_SO_SET_ZERO) { /* if no service address is set, zero counters in all */ if (!usvc->fwmark && !usvc->addr && !usvc->port) { ret = ip_vs_zero_all(); goto out_unlock; } } /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ if (usvc->protocol!=IPPROTO_TCP && usvc->protocol!=IPPROTO_UDP) { IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", usvc->protocol, NIPQUAD(usvc->addr), ntohs(usvc->port), usvc->sched_name); ret = -EFAULT; goto out_unlock; } /* Lookup the exact service by <protocol, addr, port> or fwmark */ if (usvc->fwmark == 0) svc = __ip_vs_service_get(usvc->protocol, usvc->addr, usvc->port); else svc = __ip_vs_svc_fwm_get(usvc->fwmark); if (cmd != IP_VS_SO_SET_ADD && (svc == NULL || svc->protocol != usvc->protocol)) { ret = -ESRCH; goto out_unlock; } switch (cmd) { case IP_VS_SO_SET_ADD: if (svc != NULL) ret = -EEXIST; else ret = ip_vs_add_service(usvc, &svc); break; case IP_VS_SO_SET_EDIT: ret = ip_vs_edit_service(svc, usvc); break; case IP_VS_SO_SET_DEL: ret = ip_vs_del_service(svc); if (!ret) goto out_unlock; break; case IP_VS_SO_SET_ZERO: ret = ip_vs_zero_service(svc); break; case IP_VS_SO_SET_ADDDEST: ret = ip_vs_add_dest(svc, udest); break; case IP_VS_SO_SET_EDITDEST: ret = ip_vs_edit_dest(svc, udest); break; case IP_VS_SO_SET_DELDEST: ret = ip_vs_del_dest(svc, udest); break; default: ret = -EINVAL; } if (svc) ip_vs_service_put(svc); out_unlock: up(&__ip_vs_mutex); out_dec: /* decrease the module use count */ ip_vs_use_count_dec(); return ret;}static voidip_vs_copy_stats(struct ip_vs_stats_user *dst, struct ip_vs_stats *src){ spin_lock_bh(&src->lock); memcpy(dst, src, (char*)&src->lock - (char*)src); spin_unlock_bh(&src->lock);}static voidip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src){ dst->protocol = src->protocol; dst->addr = src->addr; dst->port = src->port; dst->fwmark = src->fwmark; strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name)); dst->flags = src->flags; dst->timeout = src->timeout / HZ; dst->netmask = src->netmask; dst->num_dests = src->num_dests; ip_vs_copy_stats(&dst->stats, &src->stats);}static inline int__ip_vs_get_service_entries(const struct ip_vs_get_services *get, struct ip_vs_get_services __user *uptr){ int idx, count=0; struct ip_vs_service *svc; struct ip_vs_service_entry entry; int ret = 0; for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) { if (count >= get->num_services) goto out; memset(&entry, 0, sizeof(entry)); ip_vs_copy_service(&entry, svc); if (copy_to_user(&uptr->entrytable[count], &entry, sizeof(entry))) { ret = -EFAULT; goto out; } count++; } } for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) { if (count >= get->num_services) goto out; memset(&entry, 0, sizeof(entry)); ip_vs_copy_service(&entry, svc); if (copy_to_user(&uptr->entrytable[count], &entry, sizeof(entry))) { ret = -EFAULT; goto out; } count++; } } out: return ret;}static inline int__ip_vs_get_dest_entries(const struct ip_vs_get_dests *get, struct ip_vs_get_dests __user *uptr){ struct ip_vs_service *svc; int ret = 0; if (get->fwmark) svc = __ip_vs_svc_fwm_get(get->fwmark); else svc = __ip_vs_service_get(get->protocol, get->addr, get->port); if (svc) { int count = 0; struct ip_vs_dest *dest; struct ip_vs_dest_entry entry; list_for_each_entry(dest, &svc->destinations, n_list) { if (count >= get->num_dests) break; entry.addr = dest->addr; entry.port = dest->port; entry.conn_flags = atomic_read(&dest->conn_flags); entry.weight = atomic_read(&dest->weight); entry.u_threshold = dest->u_threshold; entry.l_threshold = dest->l_threshold; entry.activeconns = atomic_read(&dest->activeconns); entry.inactconns = atomic_read(&dest->inactconns); entry.persistconns = atomic_read(&dest->persistconns); ip_vs_copy_stats(&entry.stats, &dest->stats); if (copy_to_user(&uptr->entrytable[count], &entry, sizeof(entry))) { ret = -EFAULT; break; } count++; } ip_vs_service_put(svc); } else ret = -ESRCH; return ret;}static inline void__ip_vs_get_timeouts(struct ip_vs_timeout_user *u){#ifdef CONFIG_IP_VS_PROTO_TCP u->tcp_timeout = ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_ESTABLISHED] / HZ; u->tcp_fin_timeout = ip_vs_protocol_tcp.timeout_table[IP_VS_TCP_S_FIN_WAIT] / HZ;#endif#ifdef CONFIG_IP_VS_PROTO_UDP u->udp_timeout = ip_vs_protocol_udp.timeout_table[IP_VS_UDP_S_NORMAL] / HZ;#endif}#define GET_CMDID(cmd) (cmd - IP_VS_BASE_CTL)#define GET_INFO_ARG_LEN (sizeof(struct ip_vs_getinfo))#define GET_SERVICES_ARG_LEN (sizeof(struct ip_vs_get_services))#define GET_SERVICE_ARG_LEN (sizeof(struct ip_vs_service_entry))#define GET_DESTS_ARG_LEN (sizeof(struct ip_vs_get_dests))#define GET_TIMEOUT_ARG_LEN (sizeof(struct ip_vs_timeout_user))#define GET_DAEMON_ARG_LEN (sizeof(struct ip_vs_daemon_user) * 2)static const unsigned char get_arglen[GET_CMDID(IP_VS_SO_GET_MAX)+1] = { [GET_CMDID(IP_VS_SO_GET_VERSION)] = 64, [GET_CMDID(IP_VS_SO_GET_INFO)] = GET_INFO_ARG_LEN, [GET_CMDID(IP_VS_SO_GET_SERVICES)] = GET_SERVICES_ARG_LEN, [GET_CMDID(IP_VS_SO_GET_SERVICE)] = GET_SERVICE_ARG_LEN, [GET_CMDID(IP_VS_SO_GET_DESTS)] = GET_DESTS_ARG_LEN, [GET_CMDID(IP_VS_SO_GET_TIMEOUT)] = GET_TIMEOUT_ARG_LEN, [GET_CMDID(IP_VS_SO_GET_DAEMON)] = GET_DAEMON_ARG_LEN,};static intdo_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len){ unsigned char arg[128]; int ret = 0; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (*len < get_arglen[GET_CMDID(cmd)]) { IP_VS_ERR("get_ctl: len %u < %u\n", *len, get_arglen[GET_CMDID(cmd)]); return -EINVAL; } if (copy_from_user(arg, user, get_arglen[GET_CMDID(cmd)]) != 0) return -EFAULT; if (down_interruptible(&__ip_vs_mutex)) return -ERESTARTSYS; switch (cmd) { case IP_VS_SO_GET_VERSION: { char buf[64]; sprintf(buf, "IP Virtual Server version %d.%d.%d (size=%d)", NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE); if (copy_to_user(user, buf, strlen(buf)+1) != 0) { ret = -EFAULT; goto out; } *len = strlen(buf)+1; } break; case IP_VS_SO_GET_INFO: { struct ip_vs_getinfo info; info.version = IP_VS_VERSION_CODE; info.size = IP_VS_CONN_TAB_SIZE; info.num_services = ip_vs_num_services; if (copy_to_user(user, &info, sizeof(info)) != 0) ret = -EFAULT; } break; case IP_VS_SO_GET_SERVICES: { struct ip_vs_get_services *get; int size; get = (struct ip_vs_get_services *)arg; size = sizeof(*get) + sizeof(struct ip_vs_service_entry) * get->num_services; if (*len != size) { IP_VS_ERR("length: %u != %u\n", *len, size); ret = -EINVAL; goto out; } ret = __ip_vs_get_service_entries(get, user); } break; case IP_VS_SO_GET_SERVICE: { struct ip_vs_service_entry *entry; struct ip_vs_service *svc; entry = (struct ip_vs_service_entry *)arg; if (entry->fwmark) svc = __ip_vs_svc_fwm_get(entry->fwmark); else svc = __ip_vs_service_get(entry->protocol, entry->addr, entry->port); if (svc) { ip_vs_copy_service(entry, svc); if (copy_to_user(user, entry, sizeof(*entry)) != 0) ret = -EFAULT; ip_vs_service_put(svc); } else ret = -ESRCH; } break; case IP_VS_SO_GET_DESTS: { struct ip_vs_get_dests *get; int size; get = (struct ip_vs_get_dests *)arg; size = sizeof(*get) + sizeof(struct ip_vs_dest_entry) * get->num_dests; if (*len != size) { IP_VS_ERR("length: %u != %u\n", *len, size); ret = -EINVAL; goto out; } ret = __ip_vs_get_dest_entries(get, user); } break; case IP_VS_SO_GET_TIMEOUT: { struct ip_vs_timeout_user t; __ip_vs_get_timeouts(&t); if (copy_to_user(user, &t, sizeof(t)) != 0) ret = -EFAULT; } break; case IP_VS_SO_GET_DAEMON: { struct ip_vs_daemon_user d[2]; memset(&d, 0, sizeof(d)); if (ip_vs_sync_state & IP_VS_STATE_MASTER) { d[0].state = IP_VS_STATE_MASTER; strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn)); d[0].syncid = ip_vs_master_syncid; } if (ip_vs_sync_state & IP_VS_STATE_BACKUP) { d[1].state = IP_VS_STATE_BACKUP; strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn)); d[1].syncid = ip_vs_backup_syncid; } if (copy_to_user(user, &d, sizeof(d)) != 0) ret = -EFAULT; } break; default: ret = -EINVAL; } out: up(&__ip_vs_mutex); return ret;}static struct nf_sockopt_ops ip_vs_sockopts = { .pf = PF_INET, .set_optmin = IP_VS_BASE_CTL, .set_optmax = IP_VS_SO_SET_MAX+1, .set = do_ip_vs_set_ctl, .get_optmin = IP_VS_BASE_CTL, .get_optmax = IP_VS_SO_GET_MAX+1, .get = do_ip_vs_get_ctl,};int ip_vs_control_init(void){ int ret; int idx; EnterFunction(2); ret = nf_register_sockopt(&ip_vs_sockopts); if (ret) { IP_VS_ERR("cannot register sockopt.\n"); return ret; } proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops); proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops); sysctl_header = register_sysctl_table(vs_root_table, 0); /* Initialize ip_vs_svc_table, ip_vs_svc_fwm_table, ip_vs_rtable */ for(idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) { INIT_LIST_HEAD(&ip_vs_svc_table[idx]); INIT_LIST_HEAD(&ip_vs_svc_fwm_table[idx]); } for(idx = 0; idx < IP_VS_RTAB_SIZE; idx++) { INIT_LIST_HEAD(&ip_vs_rtable[idx]); } memset(&ip_vs_stats, 0, sizeof(ip_vs_stats)); spin_lock_init(&ip_vs_stats.lock); ip_vs_new_estimator(&ip_vs_stats); /* Hook the defense timer */ schedule_delayed_work(&defense_work, DEFENSE_TIMER_PERIOD); LeaveFunction(2); return 0;}void ip_vs_control_cleanup(void){ EnterFunction(2); ip_vs_trash_cleanup(); cancel_rearming_delayed_work(&defense_work); ip_vs_kill_estimator(&ip_vs_stats); unregister_sysctl_table(sysctl_header); proc_net_remove("ip_vs_stats"); proc_net_remove("ip_vs"); nf_unregister_sockopt(&ip_vs_sockopts); LeaveFunction(2);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -