📄 pktgen.c
字号:
len = num_arg(&user_buffer[i], 5, &value); if (len < 0) { return len; } i += len; pkt_dev->queue_map_max = value; sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max); return count; } if (!strcmp(name, "mpls")) { unsigned n, cnt; len = get_labels(&user_buffer[i], pkt_dev); if (len < 0) return len; i += len; cnt = sprintf(pg_result, "OK: mpls="); for (n = 0; n < pkt_dev->nr_labels; n++) cnt += sprintf(pg_result + cnt, "%08x%s", ntohl(pkt_dev->labels[n]), n == pkt_dev->nr_labels-1 ? "" : ","); if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) { pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ pkt_dev->svlan_id = 0xffff; if (debug) printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n"); } return count; } if (!strcmp(name, "vlan_id")) { len = num_arg(&user_buffer[i], 4, &value); if (len < 0) { return len; } i += len; if (value <= 4095) { pkt_dev->vlan_id = value; /* turn on VLAN */ if (debug) printk(KERN_DEBUG "pktgen: VLAN turned on\n"); if (debug && pkt_dev->nr_labels) printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); pkt_dev->nr_labels = 0; /* turn off MPLS */ sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id); } else { pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ pkt_dev->svlan_id = 0xffff; if (debug) printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); } return count; } if (!strcmp(name, "vlan_p")) { len = num_arg(&user_buffer[i], 1, &value); if (len < 0) { return len; } i += len; if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) { pkt_dev->vlan_p = value; sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p); } else { sprintf(pg_result, "ERROR: vlan_p must be 0-7"); } return count; } if (!strcmp(name, "vlan_cfi")) { len = num_arg(&user_buffer[i], 1, &value); if (len < 0) { return len; } i += len; if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) { pkt_dev->vlan_cfi = value; sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi); } else { sprintf(pg_result, "ERROR: vlan_cfi must be 0-1"); } return count; } if (!strcmp(name, "svlan_id")) { len = num_arg(&user_buffer[i], 4, &value); if (len < 0) { return len; } i += len; if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) { pkt_dev->svlan_id = value; /* turn on SVLAN */ if (debug) printk(KERN_DEBUG "pktgen: SVLAN turned on\n"); if (debug && pkt_dev->nr_labels) printk(KERN_DEBUG "pktgen: MPLS auto turned off\n"); pkt_dev->nr_labels = 0; /* turn off MPLS */ sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id); } else { pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */ pkt_dev->svlan_id = 0xffff; if (debug) printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n"); } return count; } if (!strcmp(name, "svlan_p")) { len = num_arg(&user_buffer[i], 1, &value); if (len < 0) { return len; } i += len; if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) { pkt_dev->svlan_p = value; sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p); } else { sprintf(pg_result, "ERROR: svlan_p must be 0-7"); } return count; } if (!strcmp(name, "svlan_cfi")) { len = num_arg(&user_buffer[i], 1, &value); if (len < 0) { return len; } i += len; if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) { pkt_dev->svlan_cfi = value; sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi); } else { sprintf(pg_result, "ERROR: svlan_cfi must be 0-1"); } return count; } if (!strcmp(name, "tos")) { __u32 tmp_value = 0; len = hex32_arg(&user_buffer[i], 2, &tmp_value); if (len < 0) { return len; } i += len; if (len == 2) { pkt_dev->tos = tmp_value; sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos); } else { sprintf(pg_result, "ERROR: tos must be 00-ff"); } return count; } if (!strcmp(name, "traffic_class")) { __u32 tmp_value = 0; len = hex32_arg(&user_buffer[i], 2, &tmp_value); if (len < 0) { return len; } i += len; if (len == 2) { pkt_dev->traffic_class = tmp_value; sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class); } else { sprintf(pg_result, "ERROR: traffic_class must be 00-ff"); } return count; } sprintf(pkt_dev->result, "No such parameter \"%s\"", name); return -EINVAL;}static int pktgen_if_open(struct inode *inode, struct file *file){ return single_open(file, pktgen_if_show, PDE(inode)->data);}static const struct file_operations pktgen_if_fops = { .owner = THIS_MODULE, .open = pktgen_if_open, .read = seq_read, .llseek = seq_lseek, .write = pktgen_if_write, .release = single_release,};static int pktgen_thread_show(struct seq_file *seq, void *v){ struct pktgen_thread *t = seq->private; struct pktgen_dev *pkt_dev; BUG_ON(!t); seq_printf(seq, "Running: "); if_lock(t); list_for_each_entry(pkt_dev, &t->if_list, list) if (pkt_dev->running) seq_printf(seq, "%s ", pkt_dev->odev->name); seq_printf(seq, "\nStopped: "); list_for_each_entry(pkt_dev, &t->if_list, list) if (!pkt_dev->running) seq_printf(seq, "%s ", pkt_dev->odev->name); if (t->result[0]) seq_printf(seq, "\nResult: %s\n", t->result); else seq_printf(seq, "\nResult: NA\n"); if_unlock(t); return 0;}static ssize_t pktgen_thread_write(struct file *file, const char __user * user_buffer, size_t count, loff_t * offset){ struct seq_file *seq = (struct seq_file *)file->private_data; struct pktgen_thread *t = seq->private; int i = 0, max, len, ret; char name[40]; char *pg_result; if (count < 1) { // sprintf(pg_result, "Wrong command format"); return -EINVAL; } max = count - i; len = count_trail_chars(&user_buffer[i], max); if (len < 0) return len; i += len; /* Read variable name */ len = strn_len(&user_buffer[i], sizeof(name) - 1); if (len < 0) return len; memset(name, 0, sizeof(name)); if (copy_from_user(name, &user_buffer[i], len)) return -EFAULT; i += len; max = count - i; len = count_trail_chars(&user_buffer[i], max); if (len < 0) return len; i += len; if (debug) printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n", name, (unsigned long)count); if (!t) { printk(KERN_ERR "pktgen: ERROR: No thread\n"); ret = -EINVAL; goto out; } pg_result = &(t->result[0]); if (!strcmp(name, "add_device")) { char f[32]; memset(f, 0, 32); len = strn_len(&user_buffer[i], sizeof(f) - 1); if (len < 0) { ret = len; goto out; } if (copy_from_user(f, &user_buffer[i], len)) return -EFAULT; i += len; mutex_lock(&pktgen_thread_lock); pktgen_add_device(t, f); mutex_unlock(&pktgen_thread_lock); ret = count; sprintf(pg_result, "OK: add_device=%s", f); goto out; } if (!strcmp(name, "rem_device_all")) { mutex_lock(&pktgen_thread_lock); t->control |= T_REMDEVALL; mutex_unlock(&pktgen_thread_lock); schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ ret = count; sprintf(pg_result, "OK: rem_device_all"); goto out; } if (!strcmp(name, "max_before_softirq")) { sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use"); ret = count; goto out; } ret = -EINVAL;out: return ret;}static int pktgen_thread_open(struct inode *inode, struct file *file){ return single_open(file, pktgen_thread_show, PDE(inode)->data);}static const struct file_operations pktgen_thread_fops = { .owner = THIS_MODULE, .open = pktgen_thread_open, .read = seq_read, .llseek = seq_lseek, .write = pktgen_thread_write, .release = single_release,};/* Think find or remove for NN */static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove){ struct pktgen_thread *t; struct pktgen_dev *pkt_dev = NULL; list_for_each_entry(t, &pktgen_threads, th_list) { pkt_dev = pktgen_find_dev(t, ifname); if (pkt_dev) { if (remove) { if_lock(t); pkt_dev->removal_mark = 1; t->control |= T_REMDEV; if_unlock(t); } break; } } return pkt_dev;}/* * mark a device for removal */static void pktgen_mark_device(const char *ifname){ struct pktgen_dev *pkt_dev = NULL; const int max_tries = 10, msec_per_try = 125; int i = 0; mutex_lock(&pktgen_thread_lock); pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname); while (1) { pkt_dev = __pktgen_NN_threads(ifname, REMOVE); if (pkt_dev == NULL) break; /* success */ mutex_unlock(&pktgen_thread_lock); pr_debug("pktgen: pktgen_mark_device waiting for %s " "to disappear....\n", ifname); schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try)); mutex_lock(&pktgen_thread_lock); if (++i >= max_tries) { printk(KERN_ERR "pktgen_mark_device: timed out after " "waiting %d msec for device %s to be removed\n", msec_per_try * i, ifname); break; } } mutex_unlock(&pktgen_thread_lock);}static void pktgen_change_name(struct net_device *dev){ struct pktgen_thread *t; list_for_each_entry(t, &pktgen_threads, th_list) { struct pktgen_dev *pkt_dev; list_for_each_entry(pkt_dev, &t->if_list, list) { if (pkt_dev->odev != dev) continue; remove_proc_entry(pkt_dev->entry->name, pg_proc_dir); pkt_dev->entry = create_proc_entry(dev->name, 0600, pg_proc_dir); if (!pkt_dev->entry) printk(KERN_ERR "pktgen: can't move proc " " entry for '%s'\n", dev->name); break; } }}static int pktgen_device_event(struct notifier_block *unused, unsigned long event, void *ptr){ struct net_device *dev = ptr; if (dev->nd_net != &init_net) return NOTIFY_DONE; /* It is OK that we do not hold the group lock right now, * as we run under the RTNL lock. */ switch (event) { case NETDEV_CHANGENAME: pktgen_change_name(dev); break; case NETDEV_UNREGISTER: pktgen_mark_device(dev->name); break; } return NOTIFY_DONE;}/* Associate pktgen_dev with a device. */static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname){ struct net_device *odev; int err; /* Clean old setups */ if (pkt_dev->odev) { dev_put(pkt_dev->odev); pkt_dev->odev = NULL; } odev = dev_get_by_name(&init_net, ifname); if (!odev) { printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname); return -ENODEV; } if (odev->type != ARPHRD_ETHER) { printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname); err = -EINVAL; } else if (!netif_running(odev)) { printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname); err = -ENETDOWN; } else { pkt_dev->odev = odev; return 0; } dev_put(odev); return err;}/* Read pkt_dev from the interface and set up internal pktgen_dev * structure to have the right information to create/send packets */static void pktgen_setup_inject(struct pktgen_dev *pkt_dev){ if (!pkt_dev->odev) { printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in " "setup_inject.\n"); sprintf(pkt_dev->result, "ERROR: pkt_dev->odev == NULL in setup_inject.\n"); return; } /* Default to the interface's mac if not explicitly set. */ if (is_zero_ether_addr(pkt_dev->src_mac)) memcpy(&(pkt_dev->hh[6]), pkt_dev->odev->dev_addr, ETH_ALEN); /* Set up Dest MAC */ memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); /* Set up pkt size */ pkt_dev->cur_pkt_size = pkt_dev->min_pkt_size; if (pkt_dev->flags & F_IPV6) { /* * Skip this automatic address setting until locks or functions * gets exported */#ifdef NOTNOW int i, set = 0, err = 1; struct inet6_dev *idev; for (i = 0; i < IN6_ADDR_HSIZE; i++) if (pkt_dev->cur_in6_saddr.s6_addr[i]) { set = 1; break; } if (!set) { /* * Use linklevel address if unconfigured. * * use ipv6_get_lladdr if/when it's get exported
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -