netconsole.c
来自「linux 内核源代码」· C语言 代码 · 共 816 行 · 第 1/2 页
C
816 行
const char *buf, size_t count){ long remote_port;#define __U16_MAX ((__u16) ~0U) if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } remote_port = strtol10_check_range(buf, 0, __U16_MAX); if (remote_port < 0) return remote_port; nt->np.remote_port = remote_port; return strnlen(buf, count);}static ssize_t store_local_ip(struct netconsole_target *nt, const char *buf, size_t count){ if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } nt->np.local_ip = ntohl(in_aton(buf)); return strnlen(buf, count);}static ssize_t store_remote_ip(struct netconsole_target *nt, const char *buf, size_t count){ if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } nt->np.remote_ip = ntohl(in_aton(buf)); return strnlen(buf, count);}static ssize_t store_remote_mac(struct netconsole_target *nt, const char *buf, size_t count){ u8 remote_mac[ETH_ALEN]; char *p = (char *) buf; int i; if (nt->enabled) { printk(KERN_ERR "netconsole: target (%s) is enabled, " "disable to update parameters\n", config_item_name(&nt->item)); return -EINVAL; } for (i = 0; i < ETH_ALEN - 1; i++) { remote_mac[i] = simple_strtoul(p, &p, 16); if (*p != ':') goto invalid; p++; } remote_mac[ETH_ALEN - 1] = simple_strtoul(p, &p, 16); if (*p && (*p != '\n')) goto invalid; memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN); return strnlen(buf, count);invalid: printk(KERN_ERR "netconsole: invalid input\n"); return -EINVAL;}/* * Attribute definitions for netconsole_target. */#define NETCONSOLE_TARGET_ATTR_RO(_name) \static struct netconsole_target_attr netconsole_target_##_name = \ __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)#define NETCONSOLE_TARGET_ATTR_RW(_name) \static struct netconsole_target_attr netconsole_target_##_name = \ __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)NETCONSOLE_TARGET_ATTR_RW(enabled);NETCONSOLE_TARGET_ATTR_RW(dev_name);NETCONSOLE_TARGET_ATTR_RW(local_port);NETCONSOLE_TARGET_ATTR_RW(remote_port);NETCONSOLE_TARGET_ATTR_RW(local_ip);NETCONSOLE_TARGET_ATTR_RW(remote_ip);NETCONSOLE_TARGET_ATTR_RO(local_mac);NETCONSOLE_TARGET_ATTR_RW(remote_mac);static struct configfs_attribute *netconsole_target_attrs[] = { &netconsole_target_enabled.attr, &netconsole_target_dev_name.attr, &netconsole_target_local_port.attr, &netconsole_target_remote_port.attr, &netconsole_target_local_ip.attr, &netconsole_target_remote_ip.attr, &netconsole_target_local_mac.attr, &netconsole_target_remote_mac.attr, NULL,};/* * Item operations and type for netconsole_target. */static void netconsole_target_release(struct config_item *item){ kfree(to_target(item));}static ssize_t netconsole_target_attr_show(struct config_item *item, struct configfs_attribute *attr, char *buf){ ssize_t ret = -EINVAL; struct netconsole_target *nt = to_target(item); struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); if (na->show) ret = na->show(nt, buf); return ret;}static ssize_t netconsole_target_attr_store(struct config_item *item, struct configfs_attribute *attr, const char *buf, size_t count){ ssize_t ret = -EINVAL; struct netconsole_target *nt = to_target(item); struct netconsole_target_attr *na = container_of(attr, struct netconsole_target_attr, attr); if (na->store) ret = na->store(nt, buf, count); return ret;}static struct configfs_item_operations netconsole_target_item_ops = { .release = netconsole_target_release, .show_attribute = netconsole_target_attr_show, .store_attribute = netconsole_target_attr_store,};static struct config_item_type netconsole_target_type = { .ct_attrs = netconsole_target_attrs, .ct_item_ops = &netconsole_target_item_ops, .ct_owner = THIS_MODULE,};/* * Group operations and type for netconsole_subsys. */static struct config_item *make_netconsole_target(struct config_group *group, const char *name){ unsigned long flags; struct netconsole_target *nt; /* * Allocate and initialize with defaults. * Target is disabled at creation (enabled == 0). */ nt = kzalloc(sizeof(*nt), GFP_KERNEL); if (!nt) { printk(KERN_ERR "netconsole: failed to allocate memory\n"); return NULL; } nt->np.name = "netconsole"; strlcpy(nt->np.dev_name, "eth0", IFNAMSIZ); nt->np.local_port = 6665; nt->np.remote_port = 6666; memset(nt->np.remote_mac, 0xff, ETH_ALEN); /* Initialize the config_item member */ config_item_init_type_name(&nt->item, name, &netconsole_target_type); /* Adding, but it is disabled */ spin_lock_irqsave(&target_list_lock, flags); list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); return &nt->item;}static void drop_netconsole_target(struct config_group *group, struct config_item *item){ unsigned long flags; struct netconsole_target *nt = to_target(item); spin_lock_irqsave(&target_list_lock, flags); list_del(&nt->list); spin_unlock_irqrestore(&target_list_lock, flags); /* * The target may have never been enabled, or was manually disabled * before being removed so netpoll may have already been cleaned up. */ if (nt->enabled) netpoll_cleanup(&nt->np); config_item_put(&nt->item);}static struct configfs_group_operations netconsole_subsys_group_ops = { .make_item = make_netconsole_target, .drop_item = drop_netconsole_target,};static struct config_item_type netconsole_subsys_type = { .ct_group_ops = &netconsole_subsys_group_ops, .ct_owner = THIS_MODULE,};/* The netconsole configfs subsystem */static struct configfs_subsystem netconsole_subsys = { .su_group = { .cg_item = { .ci_namebuf = "netconsole", .ci_type = &netconsole_subsys_type, }, },};#endif /* CONFIG_NETCONSOLE_DYNAMIC *//* Handle network interface device notifications */static int netconsole_netdev_event(struct notifier_block *this, unsigned long event, void *ptr){ unsigned long flags; struct netconsole_target *nt; struct net_device *dev = ptr; if (!(event == NETDEV_CHANGEADDR || event == NETDEV_CHANGENAME)) goto done; spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->np.dev == dev) { switch (event) { case NETDEV_CHANGEADDR: memcpy(nt->np.local_mac, dev->dev_addr, ETH_ALEN); break; case NETDEV_CHANGENAME: strlcpy(nt->np.dev_name, dev->name, IFNAMSIZ); break; } } netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags);done: return NOTIFY_DONE;}static struct notifier_block netconsole_netdev_notifier = { .notifier_call = netconsole_netdev_event,};static void write_msg(struct console *con, const char *msg, unsigned int len){ int frag, left; unsigned long flags; struct netconsole_target *nt; const char *tmp; /* Avoid taking lock and disabling interrupts unnecessarily */ if (list_empty(&target_list)) return; spin_lock_irqsave(&target_list_lock, flags); list_for_each_entry(nt, &target_list, list) { netconsole_target_get(nt); if (nt->enabled && netif_running(nt->np.dev)) { /* * We nest this inside the for-each-target loop above * so that we're able to get as much logging out to * at least one target if we die inside here, instead * of unnecessarily keeping all targets in lock-step. */ tmp = msg; for (left = len; left;) { frag = min(left, MAX_PRINT_CHUNK); netpoll_send_udp(&nt->np, tmp, frag); tmp += frag; left -= frag; } } netconsole_target_put(nt); } spin_unlock_irqrestore(&target_list_lock, flags);}static struct console netconsole = { .name = "netcon", .flags = CON_ENABLED | CON_PRINTBUFFER, .write = write_msg,};static int __init init_netconsole(void){ int err; struct netconsole_target *nt, *tmp; unsigned long flags; char *target_config; char *input = config; if (strnlen(input, MAX_PARAM_LENGTH)) { while ((target_config = strsep(&input, ";"))) { nt = alloc_param_target(target_config); if (IS_ERR(nt)) { err = PTR_ERR(nt); goto fail; } spin_lock_irqsave(&target_list_lock, flags); list_add(&nt->list, &target_list); spin_unlock_irqrestore(&target_list_lock, flags); } } err = register_netdevice_notifier(&netconsole_netdev_notifier); if (err) goto fail; err = dynamic_netconsole_init(); if (err) goto undonotifier; register_console(&netconsole); printk(KERN_INFO "netconsole: network logging started\n"); return err;undonotifier: unregister_netdevice_notifier(&netconsole_netdev_notifier);fail: printk(KERN_ERR "netconsole: cleaning up\n"); /* * Remove all targets and destroy them (only targets created * from the boot/module option exist here). Skipping the list * lock is safe here, and netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); free_param_target(nt); } return err;}static void __exit cleanup_netconsole(void){ struct netconsole_target *nt, *tmp; unregister_console(&netconsole); dynamic_netconsole_exit(); unregister_netdevice_notifier(&netconsole_netdev_notifier); /* * Targets created via configfs pin references on our module * and would first be rmdir(2)'ed from userspace. We reach * here only when they are already destroyed, and only those * created from the boot/module option are left, so remove and * destroy them. Skipping the list lock is safe here, and * netpoll_cleanup() will sleep. */ list_for_each_entry_safe(nt, tmp, &target_list, list) { list_del(&nt->list); free_param_target(nt); }}module_init(init_netconsole);module_exit(cleanup_netconsole);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?