Home | History | Annotate | Line # | Download | only in pfctl
      1  1.5   peter /*	$NetBSD: pfctl_qstats.c,v 1.5 2006/10/12 19:59:08 peter Exp $	*/
      2  1.4    yamt /*	$OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */
      3  1.1  itojun 
      4  1.1  itojun /*
      5  1.1  itojun  * Copyright (c) Henning Brauer <henning (at) openbsd.org>
      6  1.1  itojun  *
      7  1.1  itojun  * Permission to use, copy, modify, and distribute this software for any
      8  1.1  itojun  * purpose with or without fee is hereby granted, provided that the above
      9  1.1  itojun  * copyright notice and this permission notice appear in all copies.
     10  1.1  itojun  *
     11  1.1  itojun  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12  1.1  itojun  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13  1.1  itojun  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14  1.1  itojun  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15  1.1  itojun  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     16  1.1  itojun  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     17  1.1  itojun  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18  1.1  itojun  */
     19  1.1  itojun 
     20  1.1  itojun #include <sys/types.h>
     21  1.1  itojun #include <sys/ioctl.h>
     22  1.1  itojun #include <sys/socket.h>
     23  1.1  itojun 
     24  1.1  itojun #include <net/if.h>
     25  1.1  itojun #include <netinet/in.h>
     26  1.1  itojun #include <net/pfvar.h>
     27  1.1  itojun #include <arpa/inet.h>
     28  1.1  itojun 
     29  1.1  itojun #include <err.h>
     30  1.1  itojun #include <stdio.h>
     31  1.1  itojun #include <stdlib.h>
     32  1.1  itojun #include <string.h>
     33  1.1  itojun #include <unistd.h>
     34  1.1  itojun 
     35  1.1  itojun #include <altq/altq.h>
     36  1.1  itojun #include <altq/altq_cbq.h>
     37  1.1  itojun #include <altq/altq_priq.h>
     38  1.1  itojun #include <altq/altq_hfsc.h>
     39  1.1  itojun 
     40  1.1  itojun #include "pfctl.h"
     41  1.1  itojun #include "pfctl_parser.h"
     42  1.1  itojun 
     43  1.1  itojun union class_stats {
     44  1.1  itojun 	class_stats_t		cbq_stats;
     45  1.1  itojun 	struct priq_classstats	priq_stats;
     46  1.1  itojun 	struct hfsc_classstats	hfsc_stats;
     47  1.1  itojun };
     48  1.1  itojun 
     49  1.1  itojun #define AVGN_MAX	8
     50  1.1  itojun #define STAT_INTERVAL	5
     51  1.1  itojun 
     52  1.1  itojun struct queue_stats {
     53  1.1  itojun 	union class_stats	 data;
     54  1.1  itojun 	int			 avgn;
     55  1.1  itojun 	double			 avg_bytes;
     56  1.1  itojun 	double			 avg_packets;
     57  1.1  itojun 	u_int64_t		 prev_bytes;
     58  1.1  itojun 	u_int64_t		 prev_packets;
     59  1.1  itojun };
     60  1.1  itojun 
     61  1.1  itojun struct pf_altq_node {
     62  1.1  itojun 	struct pf_altq		 altq;
     63  1.1  itojun 	struct pf_altq_node	*next;
     64  1.1  itojun 	struct pf_altq_node	*children;
     65  1.1  itojun 	struct queue_stats	 qstats;
     66  1.1  itojun };
     67  1.1  itojun 
     68  1.1  itojun int			 pfctl_update_qstats(int, struct pf_altq_node **);
     69  1.1  itojun void			 pfctl_insert_altq_node(struct pf_altq_node **,
     70  1.1  itojun 			    const struct pf_altq, const struct queue_stats);
     71  1.1  itojun struct pf_altq_node	*pfctl_find_altq_node(struct pf_altq_node *,
     72  1.1  itojun 			    const char *, const char *);
     73  1.1  itojun void			 pfctl_print_altq_node(int, const struct pf_altq_node *,
     74  1.1  itojun 			     unsigned, int);
     75  1.1  itojun void			 print_cbqstats(struct queue_stats);
     76  1.1  itojun void			 print_priqstats(struct queue_stats);
     77  1.1  itojun void			 print_hfscstats(struct queue_stats);
     78  1.1  itojun void			 pfctl_free_altq_node(struct pf_altq_node *);
     79  1.1  itojun void			 pfctl_print_altq_nodestat(int,
     80  1.1  itojun 			    const struct pf_altq_node *);
     81  1.1  itojun 
     82  1.1  itojun void			 update_avg(struct pf_altq_node *);
     83  1.1  itojun 
     84  1.1  itojun int
     85  1.1  itojun pfctl_show_altq(int dev, const char *iface, int opts, int verbose2)
     86  1.1  itojun {
     87  1.1  itojun 	struct pf_altq_node	*root = NULL, *node;
     88  1.1  itojun 	int			 nodes, dotitle = (opts & PF_OPT_SHOWALL);
     89  1.1  itojun 
     90  1.1  itojun 
     91  1.1  itojun 	if ((nodes = pfctl_update_qstats(dev, &root)) < 0)
     92  1.1  itojun 		return (-1);
     93  1.1  itojun 
     94  1.4    yamt 	if (nodes == 0)
     95  1.4    yamt 		printf("No queue in use\n");
     96  1.1  itojun 	for (node = root; node != NULL; node = node->next) {
     97  1.1  itojun 		if (iface != NULL && strcmp(node->altq.ifname, iface))
     98  1.1  itojun 			continue;
     99  1.1  itojun 		if (dotitle) {
    100  1.1  itojun 			pfctl_print_title("ALTQ:");
    101  1.1  itojun 			dotitle = 0;
    102  1.1  itojun 		}
    103  1.1  itojun 		pfctl_print_altq_node(dev, node, 0, opts);
    104  1.1  itojun 	}
    105  1.1  itojun 
    106  1.4    yamt 	while (verbose2 && nodes > 0) {
    107  1.1  itojun 		printf("\n");
    108  1.1  itojun 		fflush(stdout);
    109  1.1  itojun 		sleep(STAT_INTERVAL);
    110  1.4    yamt 		if ((nodes = pfctl_update_qstats(dev, &root)) == -1)
    111  1.1  itojun 			return (-1);
    112  1.1  itojun 		for (node = root; node != NULL; node = node->next) {
    113  1.1  itojun 			if (iface != NULL && strcmp(node->altq.ifname, iface))
    114  1.1  itojun 				continue;
    115  1.1  itojun 			pfctl_print_altq_node(dev, node, 0, opts);
    116  1.1  itojun 		}
    117  1.1  itojun 	}
    118  1.1  itojun 	pfctl_free_altq_node(root);
    119  1.1  itojun 	return (0);
    120  1.1  itojun }
    121  1.1  itojun 
    122  1.1  itojun int
    123  1.1  itojun pfctl_update_qstats(int dev, struct pf_altq_node **root)
    124  1.1  itojun {
    125  1.1  itojun 	struct pf_altq_node	*node;
    126  1.1  itojun 	struct pfioc_altq	 pa;
    127  1.1  itojun 	struct pfioc_qstats	 pq;
    128  1.1  itojun 	u_int32_t		 mnr, nr;
    129  1.1  itojun 	struct queue_stats	 qstats;
    130  1.1  itojun 	static	u_int32_t	 last_ticket;
    131  1.1  itojun 
    132  1.1  itojun 	memset(&pa, 0, sizeof(pa));
    133  1.1  itojun 	memset(&pq, 0, sizeof(pq));
    134  1.1  itojun 	memset(&qstats, 0, sizeof(qstats));
    135  1.1  itojun 	if (ioctl(dev, DIOCGETALTQS, &pa)) {
    136  1.1  itojun 		warn("DIOCGETALTQS");
    137  1.1  itojun 		return (-1);
    138  1.1  itojun 	}
    139  1.1  itojun 
    140  1.1  itojun 	/* if a new set is found, start over */
    141  1.1  itojun 	if (pa.ticket != last_ticket && *root != NULL) {
    142  1.1  itojun 		pfctl_free_altq_node(*root);
    143  1.1  itojun 		*root = NULL;
    144  1.1  itojun 	}
    145  1.1  itojun 	last_ticket = pa.ticket;
    146  1.1  itojun 
    147  1.1  itojun 	mnr = pa.nr;
    148  1.1  itojun 	for (nr = 0; nr < mnr; ++nr) {
    149  1.1  itojun 		pa.nr = nr;
    150  1.1  itojun 		if (ioctl(dev, DIOCGETALTQ, &pa)) {
    151  1.1  itojun 			warn("DIOCGETALTQ");
    152  1.1  itojun 			return (-1);
    153  1.1  itojun 		}
    154  1.1  itojun 		if (pa.altq.qid > 0) {
    155  1.1  itojun 			pq.nr = nr;
    156  1.1  itojun 			pq.ticket = pa.ticket;
    157  1.1  itojun 			pq.buf = &qstats.data;
    158  1.1  itojun 			pq.nbytes = sizeof(qstats.data);
    159  1.1  itojun 			if (ioctl(dev, DIOCGETQSTATS, &pq)) {
    160  1.1  itojun 				warn("DIOCGETQSTATS");
    161  1.1  itojun 				return (-1);
    162  1.1  itojun 			}
    163  1.1  itojun 			if ((node = pfctl_find_altq_node(*root, pa.altq.qname,
    164  1.1  itojun 			    pa.altq.ifname)) != NULL) {
    165  1.1  itojun 				memcpy(&node->qstats.data, &qstats.data,
    166  1.1  itojun 				    sizeof(qstats.data));
    167  1.1  itojun 				update_avg(node);
    168  1.1  itojun 			} else {
    169  1.1  itojun 				pfctl_insert_altq_node(root, pa.altq, qstats);
    170  1.1  itojun 			}
    171  1.1  itojun 		}
    172  1.1  itojun 	}
    173  1.1  itojun 	return (mnr);
    174  1.1  itojun }
    175  1.1  itojun 
    176  1.1  itojun void
    177  1.1  itojun pfctl_insert_altq_node(struct pf_altq_node **root,
    178  1.1  itojun     const struct pf_altq altq, const struct queue_stats qstats)
    179  1.1  itojun {
    180  1.1  itojun 	struct pf_altq_node	*node;
    181  1.1  itojun 
    182  1.1  itojun 	node = calloc(1, sizeof(struct pf_altq_node));
    183  1.1  itojun 	if (node == NULL)
    184  1.1  itojun 		err(1, "pfctl_insert_altq_node: calloc");
    185  1.1  itojun 	memcpy(&node->altq, &altq, sizeof(struct pf_altq));
    186  1.1  itojun 	memcpy(&node->qstats, &qstats, sizeof(qstats));
    187  1.1  itojun 	node->next = node->children = NULL;
    188  1.1  itojun 
    189  1.1  itojun 	if (*root == NULL)
    190  1.1  itojun 		*root = node;
    191  1.1  itojun 	else if (!altq.parent[0]) {
    192  1.1  itojun 		struct pf_altq_node	*prev = *root;
    193  1.1  itojun 
    194  1.1  itojun 		while (prev->next != NULL)
    195  1.1  itojun 			prev = prev->next;
    196  1.1  itojun 		prev->next = node;
    197  1.1  itojun 	} else {
    198  1.1  itojun 		struct pf_altq_node	*parent;
    199  1.1  itojun 
    200  1.1  itojun 		parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname);
    201  1.1  itojun 		if (parent == NULL)
    202  1.1  itojun 			errx(1, "parent %s not found", altq.parent);
    203  1.1  itojun 		if (parent->children == NULL)
    204  1.1  itojun 			parent->children = node;
    205  1.1  itojun 		else {
    206  1.1  itojun 			struct pf_altq_node *prev = parent->children;
    207  1.1  itojun 
    208  1.1  itojun 			while (prev->next != NULL)
    209  1.1  itojun 				prev = prev->next;
    210  1.1  itojun 			prev->next = node;
    211  1.1  itojun 		}
    212  1.1  itojun 	}
    213  1.1  itojun 	update_avg(node);
    214  1.1  itojun }
    215  1.1  itojun 
    216  1.1  itojun struct pf_altq_node *
    217  1.1  itojun pfctl_find_altq_node(struct pf_altq_node *root, const char *qname,
    218  1.1  itojun     const char *ifname)
    219  1.1  itojun {
    220  1.1  itojun 	struct pf_altq_node	*node, *child;
    221  1.1  itojun 
    222  1.1  itojun 	for (node = root; node != NULL; node = node->next) {
    223  1.1  itojun 		if (!strcmp(node->altq.qname, qname)
    224  1.1  itojun 		    && !(strcmp(node->altq.ifname, ifname)))
    225  1.1  itojun 			return (node);
    226  1.1  itojun 		if (node->children != NULL) {
    227  1.1  itojun 			child = pfctl_find_altq_node(node->children, qname,
    228  1.1  itojun 			    ifname);
    229  1.1  itojun 			if (child != NULL)
    230  1.1  itojun 				return (child);
    231  1.1  itojun 		}
    232  1.1  itojun 	}
    233  1.1  itojun 	return (NULL);
    234  1.1  itojun }
    235  1.1  itojun 
    236  1.1  itojun void
    237  1.1  itojun pfctl_print_altq_node(int dev, const struct pf_altq_node *node, unsigned level,
    238  1.1  itojun     int opts)
    239  1.1  itojun {
    240  1.1  itojun 	const struct pf_altq_node	*child;
    241  1.1  itojun 
    242  1.1  itojun 	if (node == NULL)
    243  1.1  itojun 		return;
    244  1.1  itojun 
    245  1.1  itojun 	print_altq(&node->altq, level, NULL, NULL);
    246  1.1  itojun 
    247  1.1  itojun 	if (node->children != NULL) {
    248  1.1  itojun 		printf("{");
    249  1.1  itojun 		for (child = node->children; child != NULL;
    250  1.1  itojun 		    child = child->next) {
    251  1.1  itojun 			printf("%s", child->altq.qname);
    252  1.1  itojun 			if (child->next != NULL)
    253  1.1  itojun 				printf(", ");
    254  1.1  itojun 		}
    255  1.1  itojun 		printf("}");
    256  1.1  itojun 	}
    257  1.1  itojun 	printf("\n");
    258  1.1  itojun 
    259  1.1  itojun 	if (opts & PF_OPT_VERBOSE)
    260  1.1  itojun 		pfctl_print_altq_nodestat(dev, node);
    261  1.1  itojun 
    262  1.1  itojun 	if (opts & PF_OPT_DEBUG)
    263  1.1  itojun 		printf("  [ qid=%u ifname=%s ifbandwidth=%s ]\n",
    264  1.1  itojun 		    node->altq.qid, node->altq.ifname,
    265  1.1  itojun 		    rate2str((double)(node->altq.ifbandwidth)));
    266  1.1  itojun 
    267  1.1  itojun 	for (child = node->children; child != NULL;
    268  1.1  itojun 	    child = child->next)
    269  1.1  itojun 		pfctl_print_altq_node(dev, child, level + 1, opts);
    270  1.1  itojun }
    271  1.1  itojun 
    272  1.1  itojun void
    273  1.1  itojun pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a)
    274  1.1  itojun {
    275  1.1  itojun 	if (a->altq.qid == 0)
    276  1.1  itojun 		return;
    277  1.1  itojun 
    278  1.1  itojun 	switch (a->altq.scheduler) {
    279  1.1  itojun 	case ALTQT_CBQ:
    280  1.1  itojun 		print_cbqstats(a->qstats);
    281  1.1  itojun 		break;
    282  1.1  itojun 	case ALTQT_PRIQ:
    283  1.1  itojun 		print_priqstats(a->qstats);
    284  1.1  itojun 		break;
    285  1.1  itojun 	case ALTQT_HFSC:
    286  1.1  itojun 		print_hfscstats(a->qstats);
    287  1.1  itojun 		break;
    288  1.1  itojun 	}
    289  1.1  itojun }
    290  1.1  itojun 
    291  1.1  itojun void
    292  1.1  itojun print_cbqstats(struct queue_stats cur)
    293  1.1  itojun {
    294  1.1  itojun 	printf("  [ pkts: %10llu  bytes: %10llu  "
    295  1.1  itojun 	    "dropped pkts: %6llu bytes: %6llu ]\n",
    296  1.1  itojun 	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets,
    297  1.1  itojun 	    (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes,
    298  1.1  itojun 	    (unsigned long long)cur.data.cbq_stats.drop_cnt.packets,
    299  1.1  itojun 	    (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes);
    300  1.1  itojun 	printf("  [ qlength: %3d/%3d  borrows: %6u  suspends: %6u ]\n",
    301  1.1  itojun 	    cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax,
    302  1.1  itojun 	    cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays);
    303  1.1  itojun 
    304  1.1  itojun 	if (cur.avgn < 2)
    305  1.1  itojun 		return;
    306  1.1  itojun 
    307  1.1  itojun 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
    308  1.1  itojun 	    cur.avg_packets / STAT_INTERVAL,
    309  1.1  itojun 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
    310  1.1  itojun }
    311  1.1  itojun 
    312  1.1  itojun void
    313  1.1  itojun print_priqstats(struct queue_stats cur)
    314  1.1  itojun {
    315  1.1  itojun 	printf("  [ pkts: %10llu  bytes: %10llu  "
    316  1.1  itojun 	    "dropped pkts: %6llu bytes: %6llu ]\n",
    317  1.1  itojun 	    (unsigned long long)cur.data.priq_stats.xmitcnt.packets,
    318  1.1  itojun 	    (unsigned long long)cur.data.priq_stats.xmitcnt.bytes,
    319  1.1  itojun 	    (unsigned long long)cur.data.priq_stats.dropcnt.packets,
    320  1.1  itojun 	    (unsigned long long)cur.data.priq_stats.dropcnt.bytes);
    321  1.1  itojun 	printf("  [ qlength: %3d/%3d ]\n",
    322  1.1  itojun 	    cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit);
    323  1.1  itojun 
    324  1.1  itojun 	if (cur.avgn < 2)
    325  1.1  itojun 		return;
    326  1.1  itojun 
    327  1.1  itojun 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
    328  1.1  itojun 	    cur.avg_packets / STAT_INTERVAL,
    329  1.1  itojun 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
    330  1.1  itojun }
    331  1.1  itojun 
    332  1.1  itojun void
    333  1.1  itojun print_hfscstats(struct queue_stats cur)
    334  1.1  itojun {
    335  1.1  itojun 	printf("  [ pkts: %10llu  bytes: %10llu  "
    336  1.1  itojun 	    "dropped pkts: %6llu bytes: %6llu ]\n",
    337  1.1  itojun 	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets,
    338  1.1  itojun 	    (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes,
    339  1.1  itojun 	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets,
    340  1.1  itojun 	    (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes);
    341  1.1  itojun 	printf("  [ qlength: %3d/%3d ]\n",
    342  1.1  itojun 	    cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit);
    343  1.1  itojun 
    344  1.1  itojun 	if (cur.avgn < 2)
    345  1.1  itojun 		return;
    346  1.1  itojun 
    347  1.1  itojun 	printf("  [ measured: %7.1f packets/s, %s/s ]\n",
    348  1.1  itojun 	    cur.avg_packets / STAT_INTERVAL,
    349  1.1  itojun 	    rate2str((8 * cur.avg_bytes) / STAT_INTERVAL));
    350  1.1  itojun }
    351  1.1  itojun 
    352  1.1  itojun void
    353  1.1  itojun pfctl_free_altq_node(struct pf_altq_node *node)
    354  1.1  itojun {
    355  1.1  itojun 	while (node != NULL) {
    356  1.1  itojun 		struct pf_altq_node	*prev;
    357  1.1  itojun 
    358  1.1  itojun 		if (node->children != NULL)
    359  1.1  itojun 			pfctl_free_altq_node(node->children);
    360  1.1  itojun 		prev = node;
    361  1.1  itojun 		node = node->next;
    362  1.1  itojun 		free(prev);
    363  1.1  itojun 	}
    364  1.1  itojun }
    365  1.1  itojun 
    366  1.1  itojun void
    367  1.1  itojun update_avg(struct pf_altq_node *a)
    368  1.1  itojun {
    369  1.1  itojun 	struct queue_stats	*qs;
    370  1.1  itojun 	u_int64_t		 b, p;
    371  1.1  itojun 	int			 n;
    372  1.1  itojun 
    373  1.1  itojun 	if (a->altq.qid == 0)
    374  1.1  itojun 		return;
    375  1.1  itojun 
    376  1.1  itojun 	qs = &a->qstats;
    377  1.1  itojun 	n = qs->avgn;
    378  1.1  itojun 
    379  1.1  itojun 	switch (a->altq.scheduler) {
    380  1.1  itojun 	case ALTQT_CBQ:
    381  1.1  itojun 		b = qs->data.cbq_stats.xmit_cnt.bytes;
    382  1.1  itojun 		p = qs->data.cbq_stats.xmit_cnt.packets;
    383  1.1  itojun 		break;
    384  1.1  itojun 	case ALTQT_PRIQ:
    385  1.1  itojun 		b = qs->data.priq_stats.xmitcnt.bytes;
    386  1.1  itojun 		p = qs->data.priq_stats.xmitcnt.packets;
    387  1.1  itojun 		break;
    388  1.1  itojun 	case ALTQT_HFSC:
    389  1.1  itojun 		b = qs->data.hfsc_stats.xmit_cnt.bytes;
    390  1.1  itojun 		p = qs->data.hfsc_stats.xmit_cnt.packets;
    391  1.1  itojun 		break;
    392  1.1  itojun 	default:
    393  1.1  itojun 		b = 0;
    394  1.1  itojun 		p = 0;
    395  1.1  itojun 		break;
    396  1.1  itojun 	}
    397  1.1  itojun 
    398  1.1  itojun 	if (n == 0) {
    399  1.1  itojun 		qs->prev_bytes = b;
    400  1.1  itojun 		qs->prev_packets = p;
    401  1.1  itojun 		qs->avgn++;
    402  1.1  itojun 		return;
    403  1.1  itojun 	}
    404  1.1  itojun 
    405  1.1  itojun 	if (b >= qs->prev_bytes)
    406  1.1  itojun 		qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
    407  1.1  itojun 		    (b - qs->prev_bytes)) / n;
    408  1.1  itojun 
    409  1.1  itojun 	if (p >= qs->prev_packets)
    410  1.1  itojun 		qs->avg_packets = ((qs->avg_packets * (n - 1)) +
    411  1.1  itojun 		    (p - qs->prev_packets)) / n;
    412  1.1  itojun 
    413  1.1  itojun 	qs->prev_bytes = b;
    414  1.1  itojun 	qs->prev_packets = p;
    415  1.1  itojun 	if (n < AVGN_MAX)
    416  1.1  itojun 		qs->avgn++;
    417  1.1  itojun }
    418