|
175 | 175 | #define IP_NAME_SZ 32
|
176 | 176 | #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
|
177 | 177 | #define MPLS_STACK_BOTTOM htonl(0x00000100)
|
| 178 | +/* Max number of internet mix entries that can be specified in imix_weights. */ |
| 179 | +#define MAX_IMIX_ENTRIES 20 |
178 | 180 |
|
179 | 181 | #define func_enter() pr_debug("entering %s\n", __func__);
|
180 | 182 |
|
@@ -242,6 +244,12 @@ static char *pkt_flag_names[] = {
|
242 | 244 | #define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
|
243 | 245 | #define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
|
244 | 246 |
|
| 247 | +struct imix_pkt { |
| 248 | + u64 size; |
| 249 | + u64 weight; |
| 250 | + u64 count_so_far; |
| 251 | +}; |
| 252 | + |
245 | 253 | struct flow_state {
|
246 | 254 | __be32 cur_daddr;
|
247 | 255 | int count;
|
@@ -343,6 +351,10 @@ struct pktgen_dev {
|
343 | 351 | __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6
|
344 | 352 | (see RFC 3260, sec. 4) */
|
345 | 353 |
|
| 354 | + /* IMIX */ |
| 355 | + unsigned int n_imix_entries; |
| 356 | + struct imix_pkt imix_entries[MAX_IMIX_ENTRIES]; |
| 357 | + |
346 | 358 | /* MPLS */
|
347 | 359 | unsigned int nr_labels; /* Depth of stack, 0 = no MPLS */
|
348 | 360 | __be32 labels[MAX_MPLS_LABELS];
|
@@ -552,6 +564,16 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
|
552 | 564 | (unsigned long long)pkt_dev->count, pkt_dev->min_pkt_size,
|
553 | 565 | pkt_dev->max_pkt_size);
|
554 | 566 |
|
| 567 | + if (pkt_dev->n_imix_entries > 0) { |
| 568 | + seq_puts(seq, " imix_weights: "); |
| 569 | + for (i = 0; i < pkt_dev->n_imix_entries; i++) { |
| 570 | + seq_printf(seq, "%llu,%llu ", |
| 571 | + pkt_dev->imix_entries[i].size, |
| 572 | + pkt_dev->imix_entries[i].weight); |
| 573 | + } |
| 574 | + seq_puts(seq, "\n"); |
| 575 | + } |
| 576 | + |
555 | 577 | seq_printf(seq,
|
556 | 578 | " frags: %d delay: %llu clone_skb: %d ifname: %s\n",
|
557 | 579 | pkt_dev->nfrags, (unsigned long long) pkt_dev->delay,
|
@@ -792,6 +814,62 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen)
|
792 | 814 | return i;
|
793 | 815 | }
|
794 | 816 |
|
| 817 | +/* Parses imix entries from user buffer. |
| 818 | + * The user buffer should consist of imix entries separated by spaces |
| 819 | + * where each entry consists of size and weight delimited by commas. |
| 820 | + * "size1,weight_1 size2,weight_2 ... size_n,weight_n" for example. |
| 821 | + */ |
| 822 | +static ssize_t get_imix_entries(const char __user *buffer, |
| 823 | + struct pktgen_dev *pkt_dev) |
| 824 | +{ |
| 825 | + const int max_digits = 10; |
| 826 | + int i = 0; |
| 827 | + long len; |
| 828 | + char c; |
| 829 | + |
| 830 | + pkt_dev->n_imix_entries = 0; |
| 831 | + |
| 832 | + do { |
| 833 | + unsigned long weight; |
| 834 | + unsigned long size; |
| 835 | + |
| 836 | + len = num_arg(&buffer[i], max_digits, &size); |
| 837 | + if (len < 0) |
| 838 | + return len; |
| 839 | + i += len; |
| 840 | + if (get_user(c, &buffer[i])) |
| 841 | + return -EFAULT; |
| 842 | + /* Check for comma between size_i and weight_i */ |
| 843 | + if (c != ',') |
| 844 | + return -EINVAL; |
| 845 | + i++; |
| 846 | + |
| 847 | + if (size < 14 + 20 + 8) |
| 848 | + size = 14 + 20 + 8; |
| 849 | + |
| 850 | + len = num_arg(&buffer[i], max_digits, &weight); |
| 851 | + if (len < 0) |
| 852 | + return len; |
| 853 | + if (weight <= 0) |
| 854 | + return -EINVAL; |
| 855 | + |
| 856 | + pkt_dev->imix_entries[pkt_dev->n_imix_entries].size = size; |
| 857 | + pkt_dev->imix_entries[pkt_dev->n_imix_entries].weight = weight; |
| 858 | + |
| 859 | + i += len; |
| 860 | + if (get_user(c, &buffer[i])) |
| 861 | + return -EFAULT; |
| 862 | + |
| 863 | + i++; |
| 864 | + pkt_dev->n_imix_entries++; |
| 865 | + |
| 866 | + if (pkt_dev->n_imix_entries > MAX_IMIX_ENTRIES) |
| 867 | + return -E2BIG; |
| 868 | + } while (c == ' '); |
| 869 | + |
| 870 | + return i; |
| 871 | +} |
| 872 | + |
795 | 873 | static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
|
796 | 874 | {
|
797 | 875 | unsigned int n = 0;
|
@@ -960,6 +1038,18 @@ static ssize_t pktgen_if_write(struct file *file,
|
960 | 1038 | return count;
|
961 | 1039 | }
|
962 | 1040 |
|
| 1041 | + if (!strcmp(name, "imix_weights")) { |
| 1042 | + if (pkt_dev->clone_skb > 0) |
| 1043 | + return -EINVAL; |
| 1044 | + |
| 1045 | + len = get_imix_entries(&user_buffer[i], pkt_dev); |
| 1046 | + if (len < 0) |
| 1047 | + return len; |
| 1048 | + |
| 1049 | + i += len; |
| 1050 | + return count; |
| 1051 | + } |
| 1052 | + |
963 | 1053 | if (!strcmp(name, "debug")) {
|
964 | 1054 | len = num_arg(&user_buffer[i], 10, &value);
|
965 | 1055 | if (len < 0)
|
@@ -1082,10 +1172,16 @@ static ssize_t pktgen_if_write(struct file *file,
|
1082 | 1172 | len = num_arg(&user_buffer[i], 10, &value);
|
1083 | 1173 | if (len < 0)
|
1084 | 1174 | return len;
|
| 1175 | + /* clone_skb is not supported for netif_receive xmit_mode and |
| 1176 | + * IMIX mode. |
| 1177 | + */ |
1085 | 1178 | if ((value > 0) &&
|
1086 | 1179 | ((pkt_dev->xmit_mode == M_NETIF_RECEIVE) ||
|
1087 | 1180 | !(pkt_dev->odev->priv_flags & IFF_TX_SKB_SHARING)))
|
1088 | 1181 | return -ENOTSUPP;
|
| 1182 | + if (value > 0 && pkt_dev->n_imix_entries > 0) |
| 1183 | + return -EINVAL; |
| 1184 | + |
1089 | 1185 | i += len;
|
1090 | 1186 | pkt_dev->clone_skb = value;
|
1091 | 1187 |
|
|
0 commit comments