示例#1
0
文件: nltest.c 项目: openSUSE/lldpad
int set_ieee(char *ifname, struct ieee_ets *ets_data, struct ieee_pfc *pfc_data,
	     struct dcb_app *app_data)
{
	struct nlmsghdr *nlh;
	struct rtattr *ieee, *apptbl;

	nlh = start_msg(RTM_SETDCB, DCB_CMD_IEEE_SET);
	if (NULL == nlh)
		return -EIO;

	addattr_l(nlh, DCB_ATTR_IFNAME, ifname, strlen(ifname) + 1);
	ieee = addattr_nest(nlh, DCB_ATTR_IEEE);
	if (ets_data)
		addattr_l(nlh, DCB_ATTR_IEEE_ETS, ets_data, sizeof(*ets_data));
	if (pfc_data)
		addattr_l(nlh, DCB_ATTR_IEEE_PFC, pfc_data, sizeof(*pfc_data));
	if (app_data) {
		apptbl = addattr_nest(nlh, DCB_ATTR_IEEE_APP_TABLE);
		addattr_l(nlh, DCB_ATTR_IEEE_APP, app_data, sizeof(*app_data));
#if 1
		app_data->protocol++;
		addattr_l(nlh, DCB_ATTR_IEEE_APP, app_data, sizeof(*app_data));
#endif
		addattr_nest_end(nlh, apptbl);
	}
	addattr_nest_end(nlh, ieee);

	if (send_msg(nlh))
		return -EIO;

	return recv_msg(DCB_CMD_IEEE_SET, DCB_ATTR_IEEE);
}
示例#2
0
static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n)
{
	struct m_pedit_key_ex *k = sel->keys_ex;
	struct rtattr *keys_start;
	int i;

	if (!sel->extended)
		return 0;

	keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED);

	for (i = 0; i < sel->sel.nkeys; i++) {
		struct rtattr *key_start;

		key_start = addattr_nest(n, MAX_MSG,
					 TCA_PEDIT_KEY_EX | NLA_F_NESTED);

		if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) ||
		    addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) {
			return -1;
		}

		addattr_nest_end(n, key_start);

		k++;
	}

	addattr_nest_end(n, keys_start);

	return 0;
}
示例#3
0
文件: ipmacsec.c 项目: dtaht/tc-adv
static int do_modify_nl(enum cmd c, enum macsec_nl_commands cmd, int ifindex,
			struct rxsc_desc *rxsc, struct sa_desc *sa)
{
	struct rtattr *attr_sa;

	MACSEC_GENL_REQ(req, MACSEC_BUFLEN, cmd, NLM_F_REQUEST);

	addattr32(&req.n, MACSEC_BUFLEN, MACSEC_ATTR_IFINDEX, ifindex);
	if (rxsc) {
		struct rtattr *attr_rxsc;

		attr_rxsc = addattr_nest(&req.n, MACSEC_BUFLEN,
					 MACSEC_ATTR_RXSC_CONFIG);
		addattr64(&req.n, MACSEC_BUFLEN,
			  MACSEC_RXSC_ATTR_SCI, rxsc->sci);
		if (c != CMD_DEL && rxsc->active != 0xff)
			addattr8(&req.n, MACSEC_BUFLEN,
				 MACSEC_RXSC_ATTR_ACTIVE, rxsc->active);

		addattr_nest_end(&req.n, attr_rxsc);
	}

	if (sa->an == 0xff)
		goto talk;

	attr_sa = addattr_nest(&req.n, MACSEC_BUFLEN, MACSEC_ATTR_SA_CONFIG);

	addattr8(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_AN, sa->an);

	if (c != CMD_DEL) {
		if (sa->pn)
			addattr32(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_PN,
				  sa->pn);

		if (sa->key_len) {
			addattr_l(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_KEYID,
				  sa->key_id, MACSEC_KEYID_LEN);
			addattr_l(&req.n, MACSEC_BUFLEN, MACSEC_SA_ATTR_KEY,
				  sa->key, sa->key_len);
		}

		if (sa->active != 0xff) {
			addattr8(&req.n, MACSEC_BUFLEN,
				 MACSEC_SA_ATTR_ACTIVE, sa->active);
		}
	}

	addattr_nest_end(&req.n, attr_sa);

talk:
	if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
		return -2;

	return 0;
}
示例#4
0
static int
parse_connmark(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
	      struct nlmsghdr *n)
{
	struct tc_connmark sel = {};
	char **argv = *argv_p;
	int argc = *argc_p;
	int ok = 0;
	struct rtattr *tail;

	while (argc > 0) {
		if (matches(*argv, "connmark") == 0) {
			ok = 1;
			argc--;
			argv++;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			break;
		}

	}

	if (!ok) {
		explain();
		return -1;
	}

	if (argc) {
		if (matches(*argv, "zone") == 0) {
			NEXT_ARG();
			if (get_u16(&sel.zone, *argv, 10)) {
				fprintf(stderr, "simple: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
		}
	}

	parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_PIPE);

	if (argc) {
		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&sel.index, *argv, 10)) {
				fprintf(stderr, "simple: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	addattr_l(n, MAX_MSG, TCA_CONNMARK_PARMS, &sel, sizeof(sel));
	addattr_nest_end(n, tail);

	*argc_p = argc;
	*argv_p = argv;
	return 0;
}
示例#5
0
文件: q_codel.c 项目: dtaht/tc-adv
static int codel_parse_opt(struct qdisc_util *qu, int argc, char **argv,
			   struct nlmsghdr *n, const char *dev)
{
	unsigned int limit = 0;
	unsigned int target = 0;
	unsigned int interval = 0;
	unsigned int ce_threshold = ~0U;
	int ecn = -1;
	struct rtattr *tail;

	while (argc > 0) {
		if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			if (get_unsigned(&limit, *argv, 0)) {
				fprintf(stderr, "Illegal \"limit\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "target") == 0) {
			NEXT_ARG();
			if (get_time(&target, *argv)) {
				fprintf(stderr, "Illegal \"target\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "ce_threshold") == 0) {
			NEXT_ARG();
			if (get_time(&ce_threshold, *argv)) {
				fprintf(stderr, "Illegal \"ce_threshold\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "interval") == 0) {
			NEXT_ARG();
			if (get_time(&interval, *argv)) {
				fprintf(stderr, "Illegal \"interval\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "ecn") == 0) {
			ecn = 1;
		} else if (strcmp(*argv, "noecn") == 0) {
			ecn = 0;
		} else if (strcmp(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "What is \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--; argv++;
	}

	tail = addattr_nest(n, 1024, TCA_OPTIONS);
	if (limit)
		addattr_l(n, 1024, TCA_CODEL_LIMIT, &limit, sizeof(limit));
	if (interval)
		addattr_l(n, 1024, TCA_CODEL_INTERVAL, &interval, sizeof(interval));
	if (target)
		addattr_l(n, 1024, TCA_CODEL_TARGET, &target, sizeof(target));
	if (ecn != -1)
		addattr_l(n, 1024, TCA_CODEL_ECN, &ecn, sizeof(ecn));
	if (ce_threshold != ~0U)
		addattr_l(n, 1024, TCA_CODEL_CE_THRESHOLD,
			  &ce_threshold, sizeof(ce_threshold));

	addattr_nest_end(n, tail);
	return 0;
}
示例#6
0
static int bond_parse_opt(struct link_util *lu, int argc, char **argv,
			  struct nlmsghdr *n)
{
	__u8 mode, use_carrier, primary_reselect, fail_over_mac;
	__u8 xmit_hash_policy, num_peer_notif, all_slaves_active;
	__u8 lacp_rate, ad_select, tlb_dynamic_lb;
	__u16 ad_user_port_key, ad_actor_sys_prio;
	__u32 miimon, updelay, downdelay, arp_interval, arp_validate;
	__u32 arp_all_targets, resend_igmp, min_links, lp_interval;
	__u32 packets_per_slave;
	unsigned ifindex;

	while (argc > 0) {
		if (matches(*argv, "mode") == 0) {
			NEXT_ARG();
			if (get_index(mode_tbl, *argv) < 0)
				invarg("invalid mode", *argv);
			mode = get_index(mode_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_MODE, mode);
		} else if (matches(*argv, "active_slave") == 0) {
			NEXT_ARG();
			ifindex = if_nametoindex(*argv);
			if (!ifindex)
				return -1;
			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, ifindex);
		} else if (matches(*argv, "clear_active_slave") == 0) {
			addattr32(n, 1024, IFLA_BOND_ACTIVE_SLAVE, 0);
		} else if (matches(*argv, "miimon") == 0) {
			NEXT_ARG();
			if (get_u32(&miimon, *argv, 0))
				invarg("invalid miimon", *argv);
			addattr32(n, 1024, IFLA_BOND_MIIMON, miimon);
		} else if (matches(*argv, "updelay") == 0) {
			NEXT_ARG();
			if (get_u32(&updelay, *argv, 0))
				invarg("invalid updelay", *argv);
			addattr32(n, 1024, IFLA_BOND_UPDELAY, updelay);
		} else if (matches(*argv, "downdelay") == 0) {
			NEXT_ARG();
			if (get_u32(&downdelay, *argv, 0))
				invarg("invalid downdelay", *argv);
			addattr32(n, 1024, IFLA_BOND_DOWNDELAY, downdelay);
		} else if (matches(*argv, "use_carrier") == 0) {
			NEXT_ARG();
			if (get_u8(&use_carrier, *argv, 0))
				invarg("invalid use_carrier", *argv);
			addattr8(n, 1024, IFLA_BOND_USE_CARRIER, use_carrier);
		} else if (matches(*argv, "arp_interval") == 0) {
			NEXT_ARG();
			if (get_u32(&arp_interval, *argv, 0))
				invarg("invalid arp_interval", *argv);
			addattr32(n, 1024, IFLA_BOND_ARP_INTERVAL, arp_interval);
		} else if (matches(*argv, "arp_ip_target") == 0) {
			struct rtattr * nest = addattr_nest(n, 1024,
				IFLA_BOND_ARP_IP_TARGET);
			if (NEXT_ARG_OK()) {
				NEXT_ARG();
				char *targets = strdupa(*argv);
				char *target = strtok(targets, ",");
				int i;

				for(i = 0; target && i < BOND_MAX_ARP_TARGETS; i++) {
					__u32 addr = get_addr32(target);
					addattr32(n, 1024, i, addr);
					target = strtok(NULL, ",");
				}
				addattr_nest_end(n, nest);
			}
			addattr_nest_end(n, nest);
		} else if (matches(*argv, "arp_validate") == 0) {
			NEXT_ARG();
			if (get_index(arp_validate_tbl, *argv) < 0)
				invarg("invalid arp_validate", *argv);
			arp_validate = get_index(arp_validate_tbl, *argv);
			addattr32(n, 1024, IFLA_BOND_ARP_VALIDATE, arp_validate);
		} else if (matches(*argv, "arp_all_targets") == 0) {
			NEXT_ARG();
			if (get_index(arp_all_targets_tbl, *argv) < 0)
				invarg("invalid arp_all_targets", *argv);
			arp_all_targets = get_index(arp_all_targets_tbl, *argv);
			addattr32(n, 1024, IFLA_BOND_ARP_ALL_TARGETS, arp_all_targets);
		} else if (matches(*argv, "primary") == 0) {
			NEXT_ARG();
			ifindex = if_nametoindex(*argv);
			if (!ifindex)
				return -1;
			addattr32(n, 1024, IFLA_BOND_PRIMARY, ifindex);
		} else if (matches(*argv, "primary_reselect") == 0) {
			NEXT_ARG();
			if (get_index(primary_reselect_tbl, *argv) < 0)
				invarg("invalid primary_reselect", *argv);
			primary_reselect = get_index(primary_reselect_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_PRIMARY_RESELECT,
				 primary_reselect);
		} else if (matches(*argv, "fail_over_mac") == 0) {
			NEXT_ARG();
			if (get_index(fail_over_mac_tbl, *argv) < 0)
				invarg("invalid fail_over_mac", *argv);
			fail_over_mac = get_index(fail_over_mac_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_FAIL_OVER_MAC,
				 fail_over_mac);
		} else if (matches(*argv, "xmit_hash_policy") == 0) {
			NEXT_ARG();
			if (get_index(xmit_hash_policy_tbl, *argv) < 0)
				invarg("invalid xmit_hash_policy", *argv);

			xmit_hash_policy = get_index(xmit_hash_policy_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_XMIT_HASH_POLICY,
				 xmit_hash_policy);
		} else if (matches(*argv, "resend_igmp") == 0) {
			NEXT_ARG();
			if (get_u32(&resend_igmp, *argv, 0))
				invarg("invalid resend_igmp", *argv);

			addattr32(n, 1024, IFLA_BOND_RESEND_IGMP, resend_igmp);
		} else if (matches(*argv, "num_grat_arp") == 0 ||
			   matches(*argv, "num_unsol_na") == 0) {
			NEXT_ARG();
			if (get_u8(&num_peer_notif, *argv, 0))
				invarg("invalid num_grat_arp|num_unsol_na",
				       *argv);

			addattr8(n, 1024, IFLA_BOND_NUM_PEER_NOTIF,
				 num_peer_notif);
		} else if (matches(*argv, "all_slaves_active") == 0) {
			NEXT_ARG();
			if (get_u8(&all_slaves_active, *argv, 0))
				invarg("invalid all_slaves_active", *argv);

			addattr8(n, 1024, IFLA_BOND_ALL_SLAVES_ACTIVE,
				 all_slaves_active);
		} else if (matches(*argv, "min_links") == 0) {
			NEXT_ARG();
			if (get_u32(&min_links, *argv, 0))
				invarg("invalid min_links", *argv);

			addattr32(n, 1024, IFLA_BOND_MIN_LINKS, min_links);
		} else if (matches(*argv, "lp_interval") == 0) {
			NEXT_ARG();
			if (get_u32(&lp_interval, *argv, 0))
				invarg("invalid lp_interval", *argv);

			addattr32(n, 1024, IFLA_BOND_LP_INTERVAL, lp_interval);
		} else if (matches(*argv, "packets_per_slave") == 0) {
			NEXT_ARG();
			if (get_u32(&packets_per_slave, *argv, 0))
				invarg("invalid packets_per_slave", *argv);

			addattr32(n, 1024, IFLA_BOND_PACKETS_PER_SLAVE,
				  packets_per_slave);
		} else if (matches(*argv, "lacp_rate") == 0) {
			NEXT_ARG();
			if (get_index(lacp_rate_tbl, *argv) < 0)
				invarg("invalid lacp_rate", *argv);

			lacp_rate = get_index(lacp_rate_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_AD_LACP_RATE, lacp_rate);
		} else if (matches(*argv, "ad_select") == 0) {
			NEXT_ARG();
			if (get_index(ad_select_tbl, *argv) < 0)
				invarg("invalid ad_select", *argv);

			ad_select = get_index(ad_select_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select);
		} else if (matches(*argv, "ad_user_port_key") == 0) {
			NEXT_ARG();
			if (get_u16(&ad_user_port_key, *argv, 0))
				invarg("invalid ad_user_port_key", *argv);

			addattr16(n, 1024, IFLA_BOND_AD_USER_PORT_KEY,
				  ad_user_port_key);
		} else if (matches(*argv, "ad_actor_sys_prio") == 0) {
			NEXT_ARG();
			if (get_u16(&ad_actor_sys_prio, *argv, 0))
				invarg("invalid ad_actor_sys_prio", *argv);

			addattr16(n, 1024, IFLA_BOND_AD_ACTOR_SYS_PRIO,
				  ad_actor_sys_prio);
		} else if (matches(*argv, "ad_actor_system") == 0) {
			int len;
			char abuf[32];

			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(n, 1024, IFLA_BOND_AD_ACTOR_SYSTEM,
				  abuf, len);
		} else if (matches(*argv, "tlb_dynamic_lb") == 0) {
			NEXT_ARG();
			if (get_u8(&tlb_dynamic_lb, *argv, 0)) {
				invarg("invalid tlb_dynamic_lb", *argv);
				return -1;
			}
			addattr8(n, 1024, IFLA_BOND_TLB_DYNAMIC_LB,
				 tlb_dynamic_lb);
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "bond: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	return 0;
}
示例#7
0
文件: q_hfsc.c 项目: dtaht/tc-adv
static int
hfsc_parse_class_opt(struct qdisc_util *qu, int argc, char **argv,
		     struct nlmsghdr *n, const char *dev)
{
	struct tc_service_curve rsc = {}, fsc = {}, usc = {};
	int rsc_ok = 0, fsc_ok = 0, usc_ok = 0;
	struct rtattr *tail;

	while (argc > 0) {
		if (matches(*argv, "rt") == 0) {
			NEXT_ARG();
			if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
				explain1("rt");
				return -1;
			}
			rsc_ok = 1;
		} else if (matches(*argv, "ls") == 0) {
			NEXT_ARG();
			if (hfsc_get_sc(&argc, &argv, &fsc, dev) < 0) {
				explain1("ls");
				return -1;
			}
			fsc_ok = 1;
		} else if (matches(*argv, "sc") == 0) {
			NEXT_ARG();
			if (hfsc_get_sc(&argc, &argv, &rsc, dev) < 0) {
				explain1("sc");
				return -1;
			}
			memcpy(&fsc, &rsc, sizeof(fsc));
			rsc_ok = 1;
			fsc_ok = 1;
		} else if (matches(*argv, "ul") == 0) {
			NEXT_ARG();
			if (hfsc_get_sc(&argc, &argv, &usc, dev) < 0) {
				explain1("ul");
				return -1;
			}
			usc_ok = 1;
		} else if (matches(*argv, "help") == 0) {
			explain_class();
			return -1;
		} else {
			fprintf(stderr, "HFSC: What is \"%s\" ?\n", *argv);
			explain_class();
			return -1;
		}
		argc--, argv++;
	}

	if (!(rsc_ok || fsc_ok || usc_ok)) {
		fprintf(stderr, "HFSC: no parameters given\n");
		explain_class();
		return -1;
	}
	if (usc_ok && !fsc_ok) {
		fprintf(stderr, "HFSC: Upper-limit Service Curve without Link-Share Service Curve\n");
		explain_class();
		return -1;
	}

	tail = addattr_nest(n, 1024, TCA_OPTIONS);
	if (rsc_ok)
		addattr_l(n, 1024, TCA_HFSC_RSC, &rsc, sizeof(rsc));
	if (fsc_ok)
		addattr_l(n, 1024, TCA_HFSC_FSC, &fsc, sizeof(fsc));
	if (usc_ok)
		addattr_l(n, 1024, TCA_HFSC_USC, &usc, sizeof(usc));

	addattr_nest_end(n, tail);
	return 0;
}
示例#8
0
int iplink_parse(int argc, char **argv, struct iplink_req *req,
		char **name, char **type, char **link, char **dev, int *group, int *index)
{
	int ret, len;
	char abuf[32];
	int qlen = -1;
	int mtu = -1;
	int netns = -1;
	int vf = -1;
	int numtxqueues = -1;
	int numrxqueues = -1;
	int dev_index = 0;

	*group = -1;
	ret = argc;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			*name = *argv;
		} else if (strcmp(*argv, "index") == 0) {
			NEXT_ARG();
			*index = atoi(*argv);
		} else if (matches(*argv, "link") == 0) {
			NEXT_ARG();
			*link = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
		} else if (matches(*argv, "broadcast") == 0 ||
				strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
		} else if (matches(*argv, "txqueuelen") == 0 ||
				strcmp(*argv, "qlen") == 0 ||
				matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
		} else if (strcmp(*argv, "netns") == 0) {
			NEXT_ARG();
			if (netns != -1)
				duparg("netns", *argv);
			if ((netns = get_netns_fd(*argv)) >= 0)
				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
			else if (get_integer(&netns, *argv, 0) == 0)
				addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
			else
				invarg("Invalid \"netns\" value\n", *argv);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast", *argv);
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast", *argv);
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc", *argv);
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers", *argv);
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOARP;
			} else
				return on_off("noarp", *argv);
		} else if (strcmp(*argv, "vf") == 0) {
			struct rtattr *vflist;
			NEXT_ARG();
			if (get_integer(&vf,  *argv, 0)) {
				invarg("Invalid \"vf\" value\n", *argv);
			}
			vflist = addattr_nest(&req->n, sizeof(*req),
					      IFLA_VFINFO_LIST);
			if (dev_index == 0)
				missarg("dev");

			len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
			if (len < 0)
				return -1;
			addattr_nest_end(&req->n, vflist);
		} else if (matches(*argv, "master") == 0) {
			int ifindex;
			NEXT_ARG();
			ifindex = ll_name_to_index(*argv);
			if (!ifindex)
				invarg("Device does not exist\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
				  &ifindex, 4);
		} else if (matches(*argv, "nomaster") == 0) {
			int ifindex = 0;
			addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
				  &ifindex, 4);
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic", *argv);
		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} else if (matches(*argv, "alias") == 0) {
			NEXT_ARG();
			addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
				  *argv, strlen(*argv));
			argc--; argv++;
			break;
		} else if (strcmp(*argv, "group") == 0) {
			NEXT_ARG();
			if (*group != -1)
				duparg("group", *argv);
			if (rtnl_group_a2n(group, *argv))
				invarg("Invalid \"group\" value\n", *argv);
		} else if (strcmp(*argv, "mode") == 0) {
			int mode;
			NEXT_ARG();
			mode = get_link_mode(*argv);
			if (mode < 0)
				invarg("Invalid link mode\n", *argv);
			addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
		} else if (strcmp(*argv, "state") == 0) {
			int state;
			NEXT_ARG();
			state = get_operstate(*argv);
			if (state < 0)
				invarg("Invalid operstate\n", *argv);

			addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
		} else if (matches(*argv, "numtxqueues") == 0) {
			NEXT_ARG();
			if (numtxqueues != -1)
				duparg("numtxqueues", *argv);
			if (get_integer(&numtxqueues, *argv, 0))
				invarg("Invalid \"numtxqueues\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
				  &numtxqueues, 4);
		} else if (matches(*argv, "numrxqueues") == 0) {
			NEXT_ARG();
			if (numrxqueues != -1)
				duparg("numrxqueues", *argv);
			if (get_integer(&numrxqueues, *argv, 0))
				invarg("Invalid \"numrxqueues\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
				  &numrxqueues, 4);
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (*dev)
				duparg2("dev", *argv);
			*dev = *argv;
			dev_index = ll_name_to_index(*dev);
			if (dev_index == 0)
				invarg("Unknown device", *argv);
		}
		argc--; argv++;
	}

	return ret - argc;
}
示例#9
0
static int vlan_modify(int cmd, int argc, char **argv)
{
    struct {
        struct nlmsghdr 	n;
        struct ifinfomsg 	ifm;
        char   			buf[1024];
    } req;
    char *d = NULL;
    short vid = -1;
    struct rtattr *afspec;
    struct bridge_vlan_info vinfo;
    unsigned short flags = 0;

    memset(&vinfo, 0, sizeof(vinfo));
    memset(&req, 0, sizeof(req));

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST;
    req.n.nlmsg_type = cmd;
    req.ifm.ifi_family = PF_BRIDGE;

    while (argc > 0) {
        if (strcmp(*argv, "dev") == 0) {
            NEXT_ARG();
            d = *argv;
        } else if (strcmp(*argv, "vid") == 0) {
            NEXT_ARG();
            vid = atoi(*argv);
        } else if (strcmp(*argv, "self") == 0) {
            flags |= BRIDGE_FLAGS_SELF;
        } else if (strcmp(*argv, "master") == 0) {
            flags |= BRIDGE_FLAGS_MASTER;
        } else if (strcmp(*argv, "pvid") == 0) {
            vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
        } else if (strcmp(*argv, "untagged") == 0) {
            vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
        } else {
            if (matches(*argv, "help") == 0) {
                NEXT_ARG();
            }
        }
        argc--;
        argv++;
    }

    if (d == NULL || vid == -1) {
        fprintf(stderr, "Device and VLAN ID are required arguments.\n");
        exit(-1);
    }

    req.ifm.ifi_index = ll_name_to_index(d);
    if (req.ifm.ifi_index == 0) {
        fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
        return -1;
    }

    if (vid >= 4096) {
        fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
        return -1;
    }

    vinfo.vid = vid;

    afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);

    if (flags)
        addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);

    addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
              sizeof(vinfo));

    addattr_nest_end(&req.n, afspec);

    if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
        exit(2);

    return 0;
}
示例#10
0
static int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p,
		       int tca_id, struct nlmsghdr *n)
{
	struct m_pedit_sel sel = {};

	int argc = *argc_p;
	char **argv = *argv_p;
	int ok = 0, iok = 0;
	struct rtattr *tail;

	while (argc > 0) {
		if (pedit_debug > 1)
			fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv);
		if (matches(*argv, "pedit") == 0) {
			NEXT_ARG();
			ok++;

			if (matches(*argv, "ex") == 0) {
				if (ok > 1) {
					fprintf(stderr,
						"'ex' must be before first 'munge'\n");
					explain();
					return -1;
				}
				sel.extended = true;
				NEXT_ARG();
			}

			continue;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else if (matches(*argv, "munge") == 0) {
			if (!ok) {
				fprintf(stderr, "Bad pedit construct (%s)\n",
					*argv);
				explain();
				return -1;
			}
			NEXT_ARG();

			if (parse_munge(&argc, &argv, &sel)) {
				fprintf(stderr, "Bad pedit construct (%s)\n",
					*argv);
				explain();
				return -1;
			}
			ok++;
		} else {
			break;
		}

	}

	if (!ok) {
		explain();
		return -1;
	}

	parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);

	if (argc) {
		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&sel.sel.index, *argv, 10)) {
				fprintf(stderr, "Pedit: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
			iok++;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	if (!sel.extended) {
		addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
			  sizeof(sel.sel) +
			  sel.sel.nkeys * sizeof(struct tc_pedit_key));
	} else {
		addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel,
			  sizeof(sel.sel) +
			  sel.sel.nkeys * sizeof(struct tc_pedit_key));

		pedit_keys_ex_addattr(&sel, n);
	}

	addattr_nest_end(n, tail);

	*argc_p = argc;
	*argv_p = argv;
	return 0;
}
示例#11
0
文件: q_fq.c 项目: eworm-de/iproute2
static int fq_parse_opt(struct qdisc_util *qu, int argc, char **argv,
			struct nlmsghdr *n, const char *dev)
{
	unsigned int plimit;
	unsigned int flow_plimit;
	unsigned int quantum;
	unsigned int initial_quantum;
	unsigned int buckets = 0;
	unsigned int maxrate;
	unsigned int low_rate_threshold;
	unsigned int defrate;
	unsigned int refill_delay;
	unsigned int orphan_mask;
	unsigned int ce_threshold;
	bool set_plimit = false;
	bool set_flow_plimit = false;
	bool set_quantum = false;
	bool set_initial_quantum = false;
	bool set_maxrate = false;
	bool set_defrate = false;
	bool set_refill_delay = false;
	bool set_orphan_mask = false;
	bool set_low_rate_threshold = false;
	bool set_ce_threshold = false;
	int pacing = -1;
	struct rtattr *tail;

	while (argc > 0) {
		if (strcmp(*argv, "limit") == 0) {
			NEXT_ARG();
			if (get_unsigned(&plimit, *argv, 0)) {
				fprintf(stderr, "Illegal \"limit\"\n");
				return -1;
			}
			set_plimit = true;
		} else if (strcmp(*argv, "flow_limit") == 0) {
			NEXT_ARG();
			if (get_unsigned(&flow_plimit, *argv, 0)) {
				fprintf(stderr, "Illegal \"flow_limit\"\n");
				return -1;
			}
			set_flow_plimit = true;
		} else if (strcmp(*argv, "buckets") == 0) {
			NEXT_ARG();
			if (get_unsigned(&buckets, *argv, 0)) {
				fprintf(stderr, "Illegal \"buckets\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "maxrate") == 0) {
			NEXT_ARG();
			if (strchr(*argv, '%')) {
				if (get_percent_rate(&maxrate, *argv, dev)) {
					fprintf(stderr, "Illegal \"maxrate\"\n");
					return -1;
				}
			} else if (get_rate(&maxrate, *argv)) {
				fprintf(stderr, "Illegal \"maxrate\"\n");
				return -1;
			}
			set_maxrate = true;
		} else if (strcmp(*argv, "low_rate_threshold") == 0) {
			NEXT_ARG();
			if (get_rate(&low_rate_threshold, *argv)) {
				fprintf(stderr, "Illegal \"low_rate_threshold\"\n");
				return -1;
			}
			set_low_rate_threshold = true;
		} else if (strcmp(*argv, "ce_threshold") == 0) {
			NEXT_ARG();
			if (get_time(&ce_threshold, *argv)) {
				fprintf(stderr, "Illegal \"ce_threshold\"\n");
				return -1;
			}
			set_ce_threshold = true;
		} else if (strcmp(*argv, "defrate") == 0) {
			NEXT_ARG();
			if (strchr(*argv, '%')) {
				if (get_percent_rate(&defrate, *argv, dev)) {
					fprintf(stderr, "Illegal \"defrate\"\n");
					return -1;
				}
			} else if (get_rate(&defrate, *argv)) {
				fprintf(stderr, "Illegal \"defrate\"\n");
				return -1;
			}
			set_defrate = true;
		} else if (strcmp(*argv, "quantum") == 0) {
			NEXT_ARG();
			if (get_unsigned(&quantum, *argv, 0)) {
				fprintf(stderr, "Illegal \"quantum\"\n");
				return -1;
			}
			set_quantum = true;
		} else if (strcmp(*argv, "initial_quantum") == 0) {
			NEXT_ARG();
			if (get_unsigned(&initial_quantum, *argv, 0)) {
				fprintf(stderr, "Illegal \"initial_quantum\"\n");
				return -1;
			}
			set_initial_quantum = true;
		} else if (strcmp(*argv, "orphan_mask") == 0) {
			NEXT_ARG();
			if (get_unsigned(&orphan_mask, *argv, 0)) {
				fprintf(stderr, "Illegal \"initial_quantum\"\n");
				return -1;
			}
			set_orphan_mask = true;
		} else if (strcmp(*argv, "refill_delay") == 0) {
			NEXT_ARG();
			if (get_time(&refill_delay, *argv)) {
				fprintf(stderr, "Illegal \"refill_delay\"\n");
				return -1;
			}
			set_refill_delay = true;
		} else if (strcmp(*argv, "pacing") == 0) {
			pacing = 1;
		} else if (strcmp(*argv, "nopacing") == 0) {
			pacing = 0;
		} else if (strcmp(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "What is \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--; argv++;
	}

	tail = addattr_nest(n, 1024, TCA_OPTIONS);
	if (buckets) {
		unsigned int log = ilog2(buckets);

		addattr_l(n, 1024, TCA_FQ_BUCKETS_LOG,
			  &log, sizeof(log));
	}
	if (set_plimit)
		addattr_l(n, 1024, TCA_FQ_PLIMIT,
			  &plimit, sizeof(plimit));
	if (set_flow_plimit)
		addattr_l(n, 1024, TCA_FQ_FLOW_PLIMIT,
			  &flow_plimit, sizeof(flow_plimit));
	if (set_quantum)
		addattr_l(n, 1024, TCA_FQ_QUANTUM, &quantum, sizeof(quantum));
	if (set_initial_quantum)
		addattr_l(n, 1024, TCA_FQ_INITIAL_QUANTUM,
			  &initial_quantum, sizeof(initial_quantum));
	if (pacing != -1)
		addattr_l(n, 1024, TCA_FQ_RATE_ENABLE,
			  &pacing, sizeof(pacing));
	if (set_maxrate)
		addattr_l(n, 1024, TCA_FQ_FLOW_MAX_RATE,
			  &maxrate, sizeof(maxrate));
	if (set_low_rate_threshold)
		addattr_l(n, 1024, TCA_FQ_LOW_RATE_THRESHOLD,
			  &low_rate_threshold, sizeof(low_rate_threshold));
	if (set_defrate)
		addattr_l(n, 1024, TCA_FQ_FLOW_DEFAULT_RATE,
			  &defrate, sizeof(defrate));
	if (set_refill_delay)
		addattr_l(n, 1024, TCA_FQ_FLOW_REFILL_DELAY,
			  &refill_delay, sizeof(refill_delay));
	if (set_orphan_mask)
		addattr_l(n, 1024, TCA_FQ_ORPHAN_MASK,
			  &orphan_mask, sizeof(refill_delay));
	if (set_ce_threshold)
		addattr_l(n, 1024, TCA_FQ_CE_THRESHOLD,
			  &ce_threshold, sizeof(ce_threshold));
	addattr_nest_end(n, tail);
	return 0;
}
示例#12
0
static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
			   struct nlmsghdr *n)
{
	int dist_size = 0;
	struct rtattr *tail;
	struct tc_netem_qopt opt = { .limit = 1000 };
	struct tc_netem_corr cor;
	struct tc_netem_reorder reorder;
	struct tc_netem_corrupt corrupt;
	struct tc_netem_gimodel gimodel;
	struct tc_netem_gemodel gemodel;
	struct tc_netem_rate rate;
	__s16 *dist_data = NULL;
	__u16 loss_type = NETEM_LOSS_UNSPEC;
	int present[__TCA_NETEM_MAX];
	__u64 rate64 = 0;

	memset(&cor, 0, sizeof(cor));
	memset(&reorder, 0, sizeof(reorder));
	memset(&corrupt, 0, sizeof(corrupt));
	memset(&rate, 0, sizeof(rate));
	memset(present, 0, sizeof(present));

	for( ; argc > 0; --argc, ++argv) {
		if (matches(*argv, "limit") == 0) {
			NEXT_ARG();
			if (get_size(&opt.limit, *argv)) {
				explain1("limit");
				return -1;
			}
		} else if (matches(*argv, "latency") == 0 ||
			   matches(*argv, "delay") == 0) {
			NEXT_ARG();
			if (get_ticks(&opt.latency, *argv)) {
				explain1("latency");
				return -1;
			}

			if (NEXT_IS_NUMBER()) {
				NEXT_ARG();
				if (get_ticks(&opt.jitter, *argv)) {
					explain1("latency");
					return -1;
				}

				if (NEXT_IS_NUMBER()) {
					NEXT_ARG();
					++present[TCA_NETEM_CORR];
					if (get_percent(&cor.delay_corr, *argv)) {
						explain1("latency");
						return -1;
					}
				}
			}
		} else if (matches(*argv, "loss") == 0 ||
			   matches(*argv, "drop") == 0) {
			if (opt.loss > 0 || loss_type != NETEM_LOSS_UNSPEC) {
				explain1("duplicate loss argument\n");
				return -1;
			}

			NEXT_ARG();
			/* Old (deprecated) random loss model syntax */
			if (isdigit(argv[0][0]))
				goto random_loss_model;

			if (!strcmp(*argv, "random")) {
				NEXT_ARG();
	random_loss_model:
				if (get_percent(&opt.loss, *argv)) {
					explain1("loss percent");
					return -1;
				}
				if (NEXT_IS_NUMBER()) {
					NEXT_ARG();
					++present[TCA_NETEM_CORR];
					if (get_percent(&cor.loss_corr, *argv)) {
						explain1("loss correllation");
						return -1;
					}
				}
			} else if (!strcmp(*argv, "state")) {
				double p13;

				NEXT_ARG();
				if (parse_percent(&p13, *argv)) {
					explain1("loss p13");
					return -1;
				}

				/* set defaults */
				set_percent(&gimodel.p13, p13);
				set_percent(&gimodel.p31, 1. - p13);
				set_percent(&gimodel.p32, 0);
				set_percent(&gimodel.p23, 1.);
				set_percent(&gimodel.p14, 0);
				loss_type = NETEM_LOSS_GI;

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gimodel.p31, *argv)) {
					explain1("loss p31");
					return -1;
				}

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gimodel.p32, *argv)) {
					explain1("loss p32");
					return -1;
				}

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gimodel.p23, *argv)) {
					explain1("loss p23");
					return -1;
				}
				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gimodel.p14, *argv)) {
					explain1("loss p14");
					return -1;
				}

			} else if (!strcmp(*argv, "gemodel")) {
				NEXT_ARG();
				if (get_percent(&gemodel.p, *argv)) {
					explain1("loss gemodel p");
					return -1;
				}

				/* set defaults */
				set_percent(&gemodel.r, 1.);
				set_percent(&gemodel.h, 0);
				set_percent(&gemodel.k1, 0);
				loss_type = NETEM_LOSS_GE;

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gemodel.r, *argv)) {
					explain1("loss gemodel r");
					return -1;
				}

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gemodel.h, *argv)) {
					explain1("loss gemodel h");
					return -1;
				}
				/* netem option is "1-h" but kernel
				 * expects "h".
				 */
				gemodel.h = max_percent_value - gemodel.h;

				if (!NEXT_IS_NUMBER())
					continue;
				NEXT_ARG();
				if (get_percent(&gemodel.k1, *argv)) {
					explain1("loss gemodel k");
					return -1;
				}
			} else {
				fprintf(stderr, "Unknown loss parameter: %s\n",
					*argv);
				return -1;
			}
		} else if (matches(*argv, "ecn") == 0) {
				present[TCA_NETEM_ECN] = 1;
		} else if (matches(*argv, "reorder") == 0) {
			NEXT_ARG();
			present[TCA_NETEM_REORDER] = 1;
			if (get_percent(&reorder.probability, *argv)) {
				explain1("reorder");
				return -1;
			}
			if (NEXT_IS_NUMBER()) {
				NEXT_ARG();
				++present[TCA_NETEM_CORR];
				if (get_percent(&reorder.correlation, *argv)) {
					explain1("reorder");
					return -1;
				}
			}
		} else if (matches(*argv, "corrupt") == 0) {
			NEXT_ARG();
			present[TCA_NETEM_CORRUPT] = 1;
			if (get_percent(&corrupt.probability, *argv)) {
				explain1("corrupt");
				return -1;
			}
			if (NEXT_IS_NUMBER()) {
				NEXT_ARG();
				++present[TCA_NETEM_CORR];
				if (get_percent(&corrupt.correlation, *argv)) {
					explain1("corrupt");
					return -1;
				}
			}
		} else if (matches(*argv, "gap") == 0) {
			NEXT_ARG();
			if (get_u32(&opt.gap, *argv, 0)) {
				explain1("gap");
				return -1;
			}
		} else if (matches(*argv, "duplicate") == 0) {
			NEXT_ARG();
			if (get_percent(&opt.duplicate, *argv)) {
				explain1("duplicate");
				return -1;
			}
			if (NEXT_IS_NUMBER()) {
				NEXT_ARG();
				if (get_percent(&cor.dup_corr, *argv)) {
					explain1("duplicate");
					return -1;
				}
			}
		} else if (matches(*argv, "distribution") == 0) {
			NEXT_ARG();
			dist_data = calloc(sizeof(dist_data[0]), MAX_DIST);
			dist_size = get_distribution(*argv, dist_data, MAX_DIST);
			if (dist_size <= 0) {
				free(dist_data);
				return -1;
			}
		} else if (matches(*argv, "rate") == 0) {
			++present[TCA_NETEM_RATE];
			NEXT_ARG();
			if (get_rate64(&rate64, *argv)) {
				explain1("rate");
				return -1;
			}
			if (NEXT_IS_SIGNED_NUMBER()) {
				NEXT_ARG();
				if (get_s32(&rate.packet_overhead, *argv, 0)) {
					explain1("rate");
					return -1;
				}
			}
			if (NEXT_IS_NUMBER()) {
				NEXT_ARG();
				if (get_u32(&rate.cell_size, *argv, 0)) {
					explain1("rate");
					return -1;
				}
			}
			if (NEXT_IS_SIGNED_NUMBER()) {
				NEXT_ARG();
				if (get_s32(&rate.cell_overhead, *argv, 0)) {
					explain1("rate");
					return -1;
				}
			}
		} else if (strcmp(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "What is \"%s\"?\n", *argv);
			explain();
			return -1;
		}
	}

	tail = NLMSG_TAIL(n);

	if (reorder.probability) {
		if (opt.latency == 0) {
			fprintf(stderr, "reordering not possible without specifying some delay\n");
			explain();
			return -1;
		}
		if (opt.gap == 0)
			opt.gap = 1;
	} else if (opt.gap > 0) {
		fprintf(stderr, "gap specified without reorder probability\n");
		explain();
		return -1;
	}

	if (present[TCA_NETEM_ECN]) {
		if (opt.loss <= 0 && loss_type == NETEM_LOSS_UNSPEC) {
			fprintf(stderr, "ecn requested without loss model\n");
			explain();
			return -1;
		}
	}

	if (dist_data && (opt.latency == 0 || opt.jitter == 0)) {
		fprintf(stderr, "distribution specified but no latency and jitter values\n");
		explain();
		return -1;
	}

	if (addattr_l(n, 1024, TCA_OPTIONS, &opt, sizeof(opt)) < 0)
		return -1;

	if (present[TCA_NETEM_CORR] &&
	    addattr_l(n, 1024, TCA_NETEM_CORR, &cor, sizeof(cor)) < 0)
			return -1;

	if (present[TCA_NETEM_REORDER] &&
	    addattr_l(n, 1024, TCA_NETEM_REORDER, &reorder, sizeof(reorder)) < 0)
		return -1;

	if (present[TCA_NETEM_ECN] &&
	    addattr_l(n, 1024, TCA_NETEM_ECN, &present[TCA_NETEM_ECN],
		      sizeof(present[TCA_NETEM_ECN])) < 0)
			return -1;

	if (present[TCA_NETEM_CORRUPT] &&
	    addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
		return -1;

	if (loss_type != NETEM_LOSS_UNSPEC) {
		struct rtattr *start;

		start = addattr_nest(n, 1024, TCA_NETEM_LOSS | NLA_F_NESTED);
		if (loss_type == NETEM_LOSS_GI) {
			if (addattr_l(n, 1024, NETEM_LOSS_GI,
				      &gimodel, sizeof(gimodel)) < 0)
			    return -1;
		} else if (loss_type == NETEM_LOSS_GE) {
			if (addattr_l(n, 1024, NETEM_LOSS_GE,
				      &gemodel, sizeof(gemodel)) < 0)
			    return -1;
		} else {
			fprintf(stderr, "loss in the weeds!\n");
			return -1;
		}
		
		addattr_nest_end(n, start);
	}

	if (present[TCA_NETEM_RATE]) {
		if (rate64 >= (1ULL << 32)) {
			if (addattr_l(n, 1024,
				      TCA_NETEM_RATE64, &rate64, sizeof(rate64)) < 0)
				return -1;
			rate.rate = ~0U;
		} else {
			rate.rate = rate64;
		}
		if (addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0)
			return -1;
	}

	if (dist_data) {
		if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]),
			      TCA_NETEM_DELAY_DIST,
			      dist_data, dist_size * sizeof(dist_data[0])) < 0)
			return -1;
		free(dist_data);
	}
	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
	return 0;
}

static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
	const struct tc_netem_corr *cor = NULL;
	const struct tc_netem_reorder *reorder = NULL;
	const struct tc_netem_corrupt *corrupt = NULL;
	const struct tc_netem_gimodel *gimodel = NULL;
	const struct tc_netem_gemodel *gemodel = NULL;
	int *ecn = NULL;
	struct tc_netem_qopt qopt;
	const struct tc_netem_rate *rate = NULL;
	int len = RTA_PAYLOAD(opt) - sizeof(qopt);
	__u64 rate64 = 0;
	SPRINT_BUF(b1);

	if (opt == NULL)
		return 0;

	if (len < 0) {
		fprintf(stderr, "options size error\n");
		return -1;
	}
	memcpy(&qopt, RTA_DATA(opt), sizeof(qopt));

	if (len > 0) {
		struct rtattr *tb[TCA_NETEM_MAX+1];
		parse_rtattr(tb, TCA_NETEM_MAX, RTA_DATA(opt) + sizeof(qopt),
			     len);

		if (tb[TCA_NETEM_CORR]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_CORR]) < sizeof(*cor))
				return -1;
			cor = RTA_DATA(tb[TCA_NETEM_CORR]);
		}
		if (tb[TCA_NETEM_REORDER]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_REORDER]) < sizeof(*reorder))
				return -1;
			reorder = RTA_DATA(tb[TCA_NETEM_REORDER]);
		}
		if (tb[TCA_NETEM_CORRUPT]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_CORRUPT]) < sizeof(*corrupt))
				return -1;
			corrupt = RTA_DATA(tb[TCA_NETEM_CORRUPT]);
		}
		if (tb[TCA_NETEM_LOSS]) {
			struct rtattr *lb[NETEM_LOSS_MAX + 1];

			parse_rtattr_nested(lb, NETEM_LOSS_MAX, tb[TCA_NETEM_LOSS]);
			if (lb[NETEM_LOSS_GI])
				gimodel = RTA_DATA(lb[NETEM_LOSS_GI]);
			if (lb[NETEM_LOSS_GE])
				gemodel = RTA_DATA(lb[NETEM_LOSS_GE]);
		}			
		if (tb[TCA_NETEM_RATE]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_RATE]) < sizeof(*rate))
				return -1;
			rate = RTA_DATA(tb[TCA_NETEM_RATE]);
		}
		if (tb[TCA_NETEM_ECN]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_ECN]) < sizeof(*ecn))
				return -1;
			ecn = RTA_DATA(tb[TCA_NETEM_ECN]);
		}
		if (tb[TCA_NETEM_RATE64]) {
			if (RTA_PAYLOAD(tb[TCA_NETEM_RATE64]) < sizeof(rate64))
				return -1;
			rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]);
		}
	}

	fprintf(f, "limit %d", qopt.limit);

	if (qopt.latency) {
		fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1));

		if (qopt.jitter) {
			fprintf(f, "  %s", sprint_ticks(qopt.jitter, b1));
			if (cor && cor->delay_corr)
				fprintf(f, " %s", sprint_percent(cor->delay_corr, b1));
		}
	}

	if (qopt.loss) {
		fprintf(f, " loss %s", sprint_percent(qopt.loss, b1));
		if (cor && cor->loss_corr)
			fprintf(f, " %s", sprint_percent(cor->loss_corr, b1));
	}

	if (gimodel) {
		fprintf(f, " loss state p13 %s", sprint_percent(gimodel->p13, b1));
		fprintf(f, " p31 %s", sprint_percent(gimodel->p31, b1));
		fprintf(f, " p32 %s", sprint_percent(gimodel->p32, b1));
		fprintf(f, " p23 %s", sprint_percent(gimodel->p23, b1));
		fprintf(f, " p14 %s", sprint_percent(gimodel->p14, b1));
	}

	if (gemodel) {
		fprintf(f, " loss gemodel p %s",
			sprint_percent(gemodel->p, b1));
		fprintf(f, " r %s", sprint_percent(gemodel->r, b1));
		fprintf(f, " 1-h %s", sprint_percent(max_percent_value -
						     gemodel->h, b1));
		fprintf(f, " 1-k %s", sprint_percent(gemodel->k1, b1));
	}

	if (qopt.duplicate) {
		fprintf(f, " duplicate %s",
			sprint_percent(qopt.duplicate, b1));
		if (cor && cor->dup_corr)
			fprintf(f, " %s", sprint_percent(cor->dup_corr, b1));
	}

	if (reorder && reorder->probability) {
		fprintf(f, " reorder %s",
			sprint_percent(reorder->probability, b1));
		if (reorder->correlation)
			fprintf(f, " %s",
				sprint_percent(reorder->correlation, b1));
	}

	if (corrupt && corrupt->probability) {
		fprintf(f, " corrupt %s",
			sprint_percent(corrupt->probability, b1));
		if (corrupt->correlation)
			fprintf(f, " %s",
				sprint_percent(corrupt->correlation, b1));
	}

	if (rate && rate->rate) {
		if (rate64)
			fprintf(f, " rate %s", sprint_rate(rate64, b1));
		else
			fprintf(f, " rate %s", sprint_rate(rate->rate, b1));
		if (rate->packet_overhead)
			fprintf(f, " packetoverhead %d", rate->packet_overhead);
		if (rate->cell_size)
			fprintf(f, " cellsize %u", rate->cell_size);
		if (rate->cell_overhead)
			fprintf(f, " celloverhead %d", rate->cell_overhead);
	}

	if (ecn)
		fprintf(f, " ecn ");

	if (qopt.gap)
		fprintf(f, " gap %lu", (unsigned long)qopt.gap);


	return 0;
}

struct qdisc_util netem_qdisc_util = {
	.id	   	= "netem",
	.parse_qopt	= netem_parse_opt,
	.print_qopt	= netem_print_opt,
};
示例#13
0
static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
			   struct iplink_req *req)
{
	int len, argc = *argcp;
	char **argv = *argvp;
	struct rtattr *vfinfo;

	vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);

	while (NEXT_ARG_OK()) {
		NEXT_ARG();
		if (matches(*argv, "mac") == 0) {
			struct ifla_vf_mac ivm;
			NEXT_ARG();
			ivm.vf = vf;
			len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
		} else if (matches(*argv, "vlan") == 0) {
			struct ifla_vf_vlan ivv;
			NEXT_ARG();
			if (get_unsigned(&ivv.vlan, *argv, 0)) {
				invarg("Invalid \"vlan\" value\n", *argv);
			}
			ivv.vf = vf;
			ivv.qos = 0;
			if (NEXT_ARG_OK()) {
				NEXT_ARG();
				if (matches(*argv, "qos") == 0) {
					NEXT_ARG();
					if (get_unsigned(&ivv.qos, *argv, 0)) {
						invarg("Invalid \"qos\" value\n", *argv);
					}
				} else {
					/* rewind arg */
					PREV_ARG();
				}
			}
			addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
		} else if (matches(*argv, "rate") == 0) {
			struct ifla_vf_tx_rate ivt;
			NEXT_ARG();
			if (get_unsigned(&ivt.rate, *argv, 0)) {
				invarg("Invalid \"rate\" value\n", *argv);
			}
			ivt.vf = vf;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
		
		} else if (matches(*argv, "spoofchk") == 0) {
			struct ifla_vf_spoofchk ivs;
			NEXT_ARG();
			if (matches(*argv, "on") == 0)
				ivs.setting = 1;
			else if (matches(*argv, "off") == 0)
				ivs.setting = 0;
			else
				invarg("Invalid \"spoofchk\" value\n", *argv);
			ivs.vf = vf;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));

		} else {
			/* rewind arg */
			PREV_ARG();
			break;
		}
	}

	if (argc == *argcp)
		incomplete_command();

	addattr_nest_end(&req->n, vfinfo);

	*argcp = argc;
	*argvp = argv;
	return 0;
}
int iplink_parse(int argc, char **argv, struct iplink_req *req,
		char **name, char **type, char **link, char **dev)
{
	int ret, len;
	char abuf[32];
	int qlen = -1;
	int mtu = -1;
	int netns = -1;
	int vf = -1;

	ret = argc;

	while (argc > 0) {
		if (strcmp(*argv, "up") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags |= IFF_UP;
		} else if (strcmp(*argv, "down") == 0) {
			req->i.ifi_change |= IFF_UP;
			req->i.ifi_flags &= ~IFF_UP;
		} else if (strcmp(*argv, "name") == 0) {
			NEXT_ARG();
			*name = *argv;
		} else if (matches(*argv, "link") == 0) {
			NEXT_ARG();
			*link = *argv;
		} else if (matches(*argv, "address") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
		} else if (matches(*argv, "broadcast") == 0 ||
				strcmp(*argv, "brd") == 0) {
			NEXT_ARG();
			len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
		} else if (matches(*argv, "txqueuelen") == 0 ||
				strcmp(*argv, "qlen") == 0 ||
				matches(*argv, "txqlen") == 0) {
			NEXT_ARG();
			if (qlen != -1)
				duparg("txqueuelen", *argv);
			if (get_integer(&qlen,  *argv, 0))
				invarg("Invalid \"txqueuelen\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
		} else if (strcmp(*argv, "mtu") == 0) {
			NEXT_ARG();
			if (mtu != -1)
				duparg("mtu", *argv);
			if (get_integer(&mtu, *argv, 0))
				invarg("Invalid \"mtu\" value\n", *argv);
			addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
                                duparg("netns", *argv);
                        if (get_integer(&netns, *argv, 0))
                                invarg("Invalid \"netns\" value\n", *argv);
                        addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
		} else if (strcmp(*argv, "multicast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_MULTICAST;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_MULTICAST;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_MULTICAST;
			} else
				return on_off("multicast");
		} else if (strcmp(*argv, "allmulticast") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_ALLMULTI;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_ALLMULTI;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_ALLMULTI;
			} else
				return on_off("allmulticast");
		} else if (strcmp(*argv, "multipath") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOMULTIPATH;
			req->i.ifi_change |= IFF_MPBACKUP;
			req->i.ifi_change |= IFF_MPHANDOVER;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags &= ~IFF_MPBACKUP;
				req->i.ifi_flags &= ~IFF_MPHANDOVER;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOMULTIPATH;
			} else if (strcmp(*argv, "backup") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags |= IFF_MPBACKUP;
			} else if (strcmp(*argv, "handover") == 0) {
				req->i.ifi_flags &= ~IFF_NOMULTIPATH;
				req->i.ifi_flags |= IFF_MPHANDOVER;
			} else {
				fprintf(stderr, "Error: argument of \"multipath\" must be"
						"\"on\", \"off\", \"backup\" or \"handover\"\n");
				return -1;
			}
		} else if (strcmp(*argv, "promisc") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_PROMISC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_PROMISC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_PROMISC;
			} else
				return on_off("promisc");
		} else if (strcmp(*argv, "trailers") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOTRAILERS;
			if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOTRAILERS;
			} else if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOTRAILERS;
			} else
				return on_off("trailers");
		} else if (strcmp(*argv, "arp") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_NOARP;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags &= ~IFF_NOARP;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags |= IFF_NOARP;
			} else
				return on_off("noarp");
		} else if (strcmp(*argv, "vf") == 0) {
			struct rtattr *vflist;
			NEXT_ARG();
			if (get_integer(&vf,  *argv, 0)) {
				invarg("Invalid \"vf\" value\n", *argv);
			}
			vflist = addattr_nest(&req->n, sizeof(*req),
					      IFLA_VFINFO_LIST);
			len = iplink_parse_vf(vf, &argc, &argv, req);
			if (len < 0)
				return -1;
			addattr_nest_end(&req->n, vflist);
#ifdef IFF_DYNAMIC
		} else if (matches(*argv, "dynamic") == 0) {
			NEXT_ARG();
			req->i.ifi_change |= IFF_DYNAMIC;
			if (strcmp(*argv, "on") == 0) {
				req->i.ifi_flags |= IFF_DYNAMIC;
			} else if (strcmp(*argv, "off") == 0) {
				req->i.ifi_flags &= ~IFF_DYNAMIC;
			} else
				return on_off("dynamic");
#endif
		} else if (matches(*argv, "type") == 0) {
			NEXT_ARG();
			*type = *argv;
			argc--; argv++;
			break;
		} else if (matches(*argv, "alias") == 0) {
			NEXT_ARG();
			addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
				  *argv, strlen(*argv));
			argc--; argv++;
			break;
		} else {
			if (strcmp(*argv, "dev") == 0) {
				NEXT_ARG();
			}
			if (matches(*argv, "help") == 0)
				usage();
			if (*dev)
				duparg2("dev", *argv);
			*dev = *argv;
		}
		argc--; argv++;
	}

	return ret - argc;
}
示例#15
0
static int brlink_modify(int argc, char **argv)
{
    struct {
        struct nlmsghdr  n;
        struct ifinfomsg ifm;
        char             buf[512];
    } req;
    char *d = NULL;
    __s8 learning = -1;
    __s8 learning_sync = -1;
    __s8 flood = -1;
    __s8 hairpin = -1;
    __s8 bpdu_guard = -1;
    __s8 fast_leave = -1;
    __s8 root_block = -1;
    __u32 cost = 0;
    __s16 priority = -1;
    __s8 state = -1;
    __s16 mode = -1;
    __u16 flags = 0;
    struct rtattr *nest;

    memset(&req, 0, sizeof(req));

    req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
    req.n.nlmsg_flags = NLM_F_REQUEST;
    req.n.nlmsg_type = RTM_SETLINK;
    req.ifm.ifi_family = PF_BRIDGE;

    while (argc > 0) {
        if (strcmp(*argv, "dev") == 0) {
            NEXT_ARG();
            d = *argv;
        } else if (strcmp(*argv, "guard") == 0) {
            NEXT_ARG();
            if (!on_off("guard", &bpdu_guard, *argv))
                exit(-1);
        } else if (strcmp(*argv, "hairpin") == 0) {
            NEXT_ARG();
            if (!on_off("hairping", &hairpin, *argv))
                exit(-1);
        } else if (strcmp(*argv, "fastleave") == 0) {
            NEXT_ARG();
            if (!on_off("fastleave", &fast_leave, *argv))
                exit(-1);
        } else if (strcmp(*argv, "root_block") == 0) {
            NEXT_ARG();
            if (!on_off("root_block", &root_block, *argv))
                exit(-1);
        } else if (strcmp(*argv, "learning") == 0) {
            NEXT_ARG();
            if (!on_off("learning", &learning, *argv))
                exit(-1);
        } else if (strcmp(*argv, "learning_sync") == 0) {
            NEXT_ARG();
            if (!on_off("learning_sync", &learning_sync, *argv))
                exit(-1);
        } else if (strcmp(*argv, "flood") == 0) {
            NEXT_ARG();
            if (!on_off("flood", &flood, *argv))
                exit(-1);
        } else if (strcmp(*argv, "cost") == 0) {
            NEXT_ARG();
            cost = atoi(*argv);
        } else if (strcmp(*argv, "priority") == 0) {
            NEXT_ARG();
            priority = atoi(*argv);
        } else if (strcmp(*argv, "state") == 0) {
            NEXT_ARG();
            char *endptr;
            size_t nstates = sizeof(port_states) / sizeof(*port_states);
            state = strtol(*argv, &endptr, 10);
            if (!(**argv != '\0' && *endptr == '\0')) {
                for (state = 0; state < nstates; state++)
                    if (strcmp(port_states[state], *argv) == 0)
                        break;
                if (state == nstates) {
                    fprintf(stderr,
                            "Error: invalid STP port state\n");
                    exit(-1);
                }
            }
        } else if (strcmp(*argv, "hwmode") == 0) {
            NEXT_ARG();
            flags = BRIDGE_FLAGS_SELF;
            if (strcmp(*argv, "vepa") == 0)
                mode = BRIDGE_MODE_VEPA;
            else if (strcmp(*argv, "veb") == 0)
                mode = BRIDGE_MODE_VEB;
            else {
                fprintf(stderr,
                        "Mode argument must be \"vepa\" or "
                        "\"veb\".\n");
                exit(-1);
            }
        } else if (strcmp(*argv, "self") == 0) {
            flags = BRIDGE_FLAGS_SELF;
        } else {
            usage();
        }
        argc--;
        argv++;
    }
    if (d == NULL) {
        fprintf(stderr, "Device is a required argument.\n");
        exit(-1);
    }


    req.ifm.ifi_index = ll_name_to_index(d);
    if (req.ifm.ifi_index == 0) {
        fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
        exit(-1);
    }

    /* Nested PROTINFO attribute.  Contains: port flags, cost, priority and
     * state.
     */
    nest = addattr_nest(&req.n, sizeof(req),
                        IFLA_PROTINFO | NLA_F_NESTED);
    /* Flags first */
    if (bpdu_guard >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard);
    if (hairpin >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin);
    if (fast_leave >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE,
                 fast_leave);
    if (root_block >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block);
    if (flood >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood);
    if (learning >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning);
    if (learning_sync >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC,
                 learning_sync);

    if (cost > 0)
        addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost);

    if (priority >= 0)
        addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority);

    if (state >= 0)
        addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state);

    addattr_nest_end(&req.n, nest);

    /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that
     * designates master or self operation and IFLA_BRIDGE_MODE
     * for hw 'vepa' or 'veb' operation modes. The hwmodes are
     * only valid in 'self' mode on some devices so far.
     */
    if (mode >= 0 || flags > 0) {
        nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);

        if (flags > 0)
            addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);

        if (mode >= 0)
            addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);

        addattr_nest_end(&req.n, nest);
    }

    if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
        exit(2);

    return 0;
}
示例#16
0
文件: m_skbedit.c 项目: dtaht/tc-adv
static int
parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
	      struct nlmsghdr *n)
{
	int argc = *argc_p;
	char **argv = *argv_p;
	int ok = 0;
	struct rtattr *tail;
	unsigned int tmp;
	__u16 queue_mapping, ptype;
	__u32 flags = 0, priority, mark;
	struct tc_skbedit sel = { 0 };

	if (matches(*argv, "skbedit") != 0)
		return -1;

	NEXT_ARG();

	while (argc > 0) {
		if (matches(*argv, "queue_mapping") == 0) {
			flags |= SKBEDIT_F_QUEUE_MAPPING;
			NEXT_ARG();
			if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) {
				fprintf(stderr, "Illegal queue_mapping\n");
				return -1;
			}
			queue_mapping = tmp;
			ok++;
		} else if (matches(*argv, "priority") == 0) {
			flags |= SKBEDIT_F_PRIORITY;
			NEXT_ARG();
			if (get_tc_classid(&priority, *argv)) {
				fprintf(stderr, "Illegal priority\n");
				return -1;
			}
			ok++;
		} else if (matches(*argv, "mark") == 0) {
			flags |= SKBEDIT_F_MARK;
			NEXT_ARG();
			if (get_u32(&mark, *argv, 0)) {
				fprintf(stderr, "Illegal mark\n");
				return -1;
			}
			ok++;
		} else if (matches(*argv, "ptype") == 0) {

			NEXT_ARG();
			if (matches(*argv, "host") == 0) {
				ptype = PACKET_HOST;
			} else if (matches(*argv, "broadcast") == 0) {
				ptype = PACKET_BROADCAST;
			} else if (matches(*argv, "multicast") == 0) {
				ptype = PACKET_MULTICAST;
			} else if (matches(*argv, "otherhost") == 0) {
				ptype = PACKET_OTHERHOST;
			} else {
				fprintf(stderr, "Illegal ptype (%s)\n",
					*argv);
				return -1;
			}
			flags |= SKBEDIT_F_PTYPE;
			ok++;
		} else if (matches(*argv, "help") == 0) {
			usage();
		} else {
			break;
		}
		argc--;
		argv++;
	}

	parse_action_control_dflt(&argc, &argv, &sel.action,
				  false, TC_ACT_PIPE);

	if (argc) {
		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&sel.index, *argv, 10)) {
				fprintf(stderr, "Pedit: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
			ok++;
		}
	}

	if (!ok) {
		explain();
		return -1;
	}


	tail = addattr_nest(n, MAX_MSG, tca_id);
	addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel));
	if (flags & SKBEDIT_F_QUEUE_MAPPING)
		addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING,
			  &queue_mapping, sizeof(queue_mapping));
	if (flags & SKBEDIT_F_PRIORITY)
		addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY,
			  &priority, sizeof(priority));
	if (flags & SKBEDIT_F_MARK)
		addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK,
			  &mark, sizeof(mark));
	if (flags & SKBEDIT_F_PTYPE)
		addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE,
			  &ptype, sizeof(ptype));
	addattr_nest_end(n, tail);

	*argc_p = argc;
	*argv_p = argv;
	return 0;
}
示例#17
0
文件: m_mirred.c 项目: dtaht/tc-adv
static int
parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
		int tca_id, struct nlmsghdr *n)
{

	int argc = *argc_p;
	char **argv = *argv_p;
	int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
	struct tc_mirred p = {};
	struct rtattr *tail;
	char d[IFNAMSIZ] = {};

	while (argc > 0) {

		if (matches(*argv, "action") == 0) {
			NEXT_ARG();
			break;
		} else if (!egress && matches(*argv, "egress") == 0) {
			egress = 1;
			if (ingress) {
				fprintf(stderr,
					"Can't have both egress and ingress\n");
				return -1;
			}
			NEXT_ARG();
			ok++;
			continue;
		} else if (!ingress && matches(*argv, "ingress") == 0) {
			ingress = 1;
			if (egress) {
				fprintf(stderr,
					"Can't have both ingress and egress\n");
				return -1;
			}
			NEXT_ARG();
			ok++;
			continue;
		} else {

			if (matches(*argv, "index") == 0) {
				NEXT_ARG();
				if (get_u32(&p.index, *argv, 10)) {
					fprintf(stderr, "Illegal \"index\"\n");
					return -1;
				}
				iok++;
				if (!ok) {
					argc--;
					argv++;
					break;
				}
			} else if (!ok) {
				fprintf(stderr,
					"was expecting egress or ingress (%s)\n",
					*argv);
				break;

			} else if (!mirror && matches(*argv, "mirror") == 0) {
				mirror = 1;
				if (redir) {
					fprintf(stderr,
						"Can't have both mirror and redir\n");
					return -1;
				}
				p.eaction = egress ? TCA_EGRESS_MIRROR :
					TCA_INGRESS_MIRROR;
				p.action = TC_ACT_PIPE;
				ok++;
			} else if (!redir && matches(*argv, "redirect") == 0) {
				redir = 1;
				if (mirror) {
					fprintf(stderr,
						"Can't have both mirror and redir\n");
					return -1;
				}
				p.eaction = egress ? TCA_EGRESS_REDIR :
					TCA_INGRESS_REDIR;
				p.action = TC_ACT_STOLEN;
				ok++;
			} else if ((redir || mirror) &&
				   matches(*argv, "dev") == 0) {
				NEXT_ARG();
				if (strlen(d))
					duparg("dev", *argv);

				strncpy(d, *argv, sizeof(d)-1);
				argc--;
				argv++;

				break;

			}
		}

		NEXT_ARG();
	}

	if (!ok && !iok)
		return -1;

	if (d[0])  {
		int idx;

		ll_init_map(&rth);

		idx = ll_name_to_index(d);
		if (!idx)
			return nodev(d);

		p.ifindex = idx;
	}


	if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
		parse_action_control(&argc, &argv, &p.action, false);

	if (argc) {
		if (iok && matches(*argv, "index") == 0) {
			fprintf(stderr, "mirred: Illegal double index\n");
			return -1;
		}

		if (matches(*argv, "index") == 0) {
			NEXT_ARG();
			if (get_u32(&p.index, *argv, 10)) {
				fprintf(stderr,
					"mirred: Illegal \"index\"\n");
				return -1;
			}
			argc--;
			argv++;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
	addattr_nest_end(n, tail);

	*argc_p = argc;
	*argv_p = argv;
	return 0;
}
示例#18
0
static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
			   struct iplink_req *req, int dev_index)
{
	char new_rate_api = 0, count = 0, override_legacy_rate = 0;
	struct ifla_vf_rate tivt;
	int len, argc = *argcp;
	char **argv = *argvp;
	struct rtattr *vfinfo;

	tivt.min_tx_rate = -1;
	tivt.max_tx_rate = -1;

	vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);

	while (NEXT_ARG_OK()) {
		NEXT_ARG();
		count++;
		if (!matches(*argv, "max_tx_rate")) {
			/* new API in use */
			new_rate_api = 1;
			/* override legacy rate */
			override_legacy_rate = 1;
		} else if (!matches(*argv, "min_tx_rate")) {
			/* new API in use */
			new_rate_api = 1;
		}
	}

	while (count--) {
		/* rewind arg */
		PREV_ARG();
	}

	while (NEXT_ARG_OK()) {
		NEXT_ARG();
		if (matches(*argv, "mac") == 0) {
			struct ifla_vf_mac ivm;
			NEXT_ARG();
			ivm.vf = vf;
			len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
			if (len < 0)
				return -1;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
		} else if (matches(*argv, "vlan") == 0) {
			struct ifla_vf_vlan ivv;
			NEXT_ARG();
			if (get_unsigned(&ivv.vlan, *argv, 0)) {
				invarg("Invalid \"vlan\" value\n", *argv);
			}
			ivv.vf = vf;
			ivv.qos = 0;
			if (NEXT_ARG_OK()) {
				NEXT_ARG();
				if (matches(*argv, "qos") == 0) {
					NEXT_ARG();
					if (get_unsigned(&ivv.qos, *argv, 0)) {
						invarg("Invalid \"qos\" value\n", *argv);
					}
				} else {
					/* rewind arg */
					PREV_ARG();
				}
			}
			addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
		} else if (matches(*argv, "rate") == 0) {
			struct ifla_vf_tx_rate ivt;
			NEXT_ARG();
			if (get_unsigned(&ivt.rate, *argv, 0)) {
				invarg("Invalid \"rate\" value\n", *argv);
			}
			ivt.vf = vf;
			if (!new_rate_api)
				addattr_l(&req->n, sizeof(*req),
					  IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
			else if (!override_legacy_rate)
				tivt.max_tx_rate = ivt.rate;

		} else if (matches(*argv, "max_tx_rate") == 0) {
			NEXT_ARG();
			if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
				invarg("Invalid \"max tx rate\" value\n",
				       *argv);
			tivt.vf = vf;

		} else if (matches(*argv, "min_tx_rate") == 0) {
			NEXT_ARG();
			if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
				invarg("Invalid \"min tx rate\" value\n",
				       *argv);
			tivt.vf = vf;

		} else if (matches(*argv, "spoofchk") == 0) {
			struct ifla_vf_spoofchk ivs;
			NEXT_ARG();
			if (matches(*argv, "on") == 0)
				ivs.setting = 1;
			else if (matches(*argv, "off") == 0)
				ivs.setting = 0;
			else
				invarg("Invalid \"spoofchk\" value\n", *argv);
			ivs.vf = vf;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));

		} else if (matches(*argv, "state") == 0) {
			struct ifla_vf_link_state ivl;
			NEXT_ARG();
			if (matches(*argv, "auto") == 0)
				ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
			else if (matches(*argv, "enable") == 0)
				ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
			else if (matches(*argv, "disable") == 0)
				ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
			else
				invarg("Invalid \"state\" value\n", *argv);
			ivl.vf = vf;
			addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
		} else {
			/* rewind arg */
			PREV_ARG();
			break;
		}
	}

	if (new_rate_api) {
		int tmin, tmax;

		if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
			ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
			if (tivt.min_tx_rate == -1)
				tivt.min_tx_rate = tmin;
			if (tivt.max_tx_rate == -1)
				tivt.max_tx_rate = tmax;
		}
		addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
			  sizeof(tivt));
	}

	if (argc == *argcp)
		incomplete_command();

	addattr_nest_end(&req->n, vfinfo);

	*argcp = argc;
	*argvp = argv;
	return 0;
}
示例#19
0
文件: m_xt_old.c 项目: dtaht/tc-adv
static int parse_ipt(struct action_util *a, int *argc_p,
		     char ***argv_p, int tca_id, struct nlmsghdr *n)
{
	struct xtables_target *m = NULL;
	struct ipt_entry fw;
	struct rtattr *tail;
	int c;
	int rargc = *argc_p;
	char **argv = *argv_p;
	int argc = 0, iargc = 0;
	char k[FILTER_NAMESZ];
	int size = 0;
	int iok = 0, ok = 0;
	__u32 hook = 0, index = 0;

	set_lib_dir();

	{
		int i;

		for (i = 0; i < rargc; i++) {
			if (NULL == argv[i] || 0 == strcmp(argv[i], "action")) {
				break;
			}
		}
		iargc = argc = i;
	}

	if (argc <= 2) {
		fprintf(stderr, "bad arguments to ipt %d vs %d\n", argc, rargc);
		return -1;
	}

	while (1) {
		c = getopt_long(argc, argv, "j:", opts, NULL);
		if (c == -1)
			break;
		switch (c) {
		case 'j':
			m = find_target(optarg, TRY_LOAD);
			if (m != NULL) {

				if (build_st(m, NULL) < 0) {
					printf(" %s error\n", m->name);
					return -1;
				}
				opts =
				    merge_options(opts, m->extra_opts,
						  &m->option_offset);
			} else {
				fprintf(stderr, " failed to find target %s\n\n", optarg);
				return -1;
			}
			ok++;
			break;

		default:
			memset(&fw, 0, sizeof(fw));
			if (m) {
				m->parse(c - m->option_offset, argv, 0,
					 &m->tflags, NULL, &m->t);
			} else {
				fprintf(stderr, " failed to find target %s\n\n", optarg);
				return -1;

			}
			ok++;
			break;

		}
	}

	if (iargc > optind) {
		if (matches(argv[optind], "index") == 0) {
			if (get_u32(&index, argv[optind + 1], 10)) {
				fprintf(stderr, "Illegal \"index\"\n");
				free_opts(opts);
				return -1;
			}
			iok++;

			optind += 2;
		}
	}

	if (!ok && !iok) {
		fprintf(stderr, " ipt Parser BAD!! (%s)\n", *argv);
		return -1;
	}

	/* check that we passed the correct parameters to the target */
	if (m)
		m->final_check(m->tflags);

	{
		struct tcmsg *t = NLMSG_DATA(n);

		if (t->tcm_parent != TC_H_ROOT
		    && t->tcm_parent == TC_H_MAJ(TC_H_INGRESS)) {
			hook = NF_IP_PRE_ROUTING;
		} else {
			hook = NF_IP_POST_ROUTING;
		}
	}

	tail = addattr_nest(n, MAX_MSG, tca_id);
	fprintf(stdout, "tablename: %s hook: %s\n ", tname, ipthooks[hook]);
	fprintf(stdout, "\ttarget: ");

	if (m)
		m->print(NULL, m->t, 0);
	fprintf(stdout, " index %d\n", index);

	if (strlen(tname) > 16) {
		size = 16;
		k[15] = 0;
	} else {
		size = 1 + strlen(tname);
	}
	strncpy(k, tname, size);

	addattr_l(n, MAX_MSG, TCA_IPT_TABLE, k, size);
	addattr_l(n, MAX_MSG, TCA_IPT_HOOK, &hook, 4);
	addattr_l(n, MAX_MSG, TCA_IPT_INDEX, &index, 4);
	if (m)
		addattr_l(n, MAX_MSG, TCA_IPT_TARG, m->t, m->t->u.target_size);
	addattr_nest_end(n, tail);

	argc -= optind;
	argv += optind;
	*argc_p = rargc - iargc;
	*argv_p = argv;

	optind = 0;
	free_opts(opts);
	/* Clear flags if target will be used again */
        m->tflags = 0;
        m->used = 0;
	/* Free allocated memory */
	if (m->t)
	    free(m->t);


	return 0;

}
示例#20
0
文件: vlan.c 项目: idosch/iproute2
static int vlan_modify(int cmd, int argc, char **argv)
{
	struct {
		struct nlmsghdr	n;
		struct ifinfomsg	ifm;
		char			buf[1024];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
		.n.nlmsg_flags = NLM_F_REQUEST,
		.n.nlmsg_type = cmd,
		.ifm.ifi_family = PF_BRIDGE,
	};
	char *d = NULL;
	short vid = -1;
	short vid_end = -1;
	struct rtattr *afspec;
	struct bridge_vlan_info vinfo = {};
	unsigned short flags = 0;

	while (argc > 0) {
		if (strcmp(*argv, "dev") == 0) {
			NEXT_ARG();
			d = *argv;
		} else if (strcmp(*argv, "vid") == 0) {
			char *p;

			NEXT_ARG();
			p = strchr(*argv, '-');
			if (p) {
				*p = '\0';
				p++;
				vid = atoi(*argv);
				vid_end = atoi(p);
				vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
			} else {
				vid = atoi(*argv);
			}
		} else if (strcmp(*argv, "self") == 0) {
			flags |= BRIDGE_FLAGS_SELF;
		} else if (strcmp(*argv, "master") == 0) {
			flags |= BRIDGE_FLAGS_MASTER;
		} else if (strcmp(*argv, "pvid") == 0) {
			vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
		} else if (strcmp(*argv, "untagged") == 0) {
			vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
		} else {
			if (matches(*argv, "help") == 0) {
				NEXT_ARG();
			}
		}
		argc--; argv++;
	}

	if (d == NULL || vid == -1) {
		fprintf(stderr, "Device and VLAN ID are required arguments.\n");
		return -1;
	}

	req.ifm.ifi_index = ll_name_to_index(d);
	if (req.ifm.ifi_index == 0) {
		fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
		return -1;
	}

	if (vid >= 4096) {
		fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
		return -1;
	}

	if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
		if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
			fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
				vid, vid_end);
			return -1;
		}
		if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
			fprintf(stderr,
				"pvid cannot be configured for a vlan range\n");
			return -1;
		}
	}

	afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);

	if (flags)
		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);

	vinfo.vid = vid;
	if (vid_end != -1) {
		/* send vlan range start */
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
		vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;

		/* Now send the vlan range end */
		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
		vinfo.vid = vid_end;
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
	} else {
		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
			  sizeof(vinfo));
	}

	addattr_nest_end(&req.n, afspec);

	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
		return -1;

	return 0;
}

/* In order to use this function for both filtering and non-filtering cases
 * we need to make it a tristate:
 * return -1 - if filtering we've gone over so don't continue
 * return  0 - skip entry and continue (applies to range start or to entries
 *             which are less than filter_vlan)
 * return  1 - print the entry and continue
 */
static int filter_vlan_check(struct bridge_vlan_info *vinfo)
{
	/* if we're filtering we should stop on the first greater entry */
	if (filter_vlan && vinfo->vid > filter_vlan &&
	    !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
		return -1;
	if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
	    vinfo->vid < filter_vlan)
		return 0;

	return 1;
}

static void print_vlan_port(FILE *fp, int ifi_index)
{
	if (jw_global) {
		jsonw_pretty(jw_global, 1);
		jsonw_name(jw_global,
			   ll_index_to_name(ifi_index));
		jsonw_start_array(jw_global);
	} else {
		fprintf(fp, "%s",
			ll_index_to_name(ifi_index));
	}
}

static void start_json_vlan_flags_array(bool *vlan_flags)
{
	if (*vlan_flags)
		return;
	jsonw_name(jw_global, "flags");
	jsonw_start_array(jw_global);
	*vlan_flags = true;
}

static int print_vlan(const struct sockaddr_nl *who,
		      struct nlmsghdr *n,
		      void *arg)
{
	FILE *fp = arg;
	struct ifinfomsg *ifm = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *tb[IFLA_MAX+1];
	bool vlan_flags;

	if (n->nlmsg_type != RTM_NEWLINK) {
		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
		return 0;
	}

	len -= NLMSG_LENGTH(sizeof(*ifm));
	if (len < 0) {
		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
		return -1;
	}

	if (ifm->ifi_family != AF_BRIDGE)
		return 0;

	if (filter_index && filter_index != ifm->ifi_index)
		return 0;

	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);

	/* if AF_SPEC isn't there, vlan table is not preset for this port */
	if (!tb[IFLA_AF_SPEC]) {
		if (!filter_vlan)
			fprintf(fp, "%s\tNone\n",
				ll_index_to_name(ifm->ifi_index));
		return 0;
	} else {
		struct rtattr *i, *list = tb[IFLA_AF_SPEC];
		int rem = RTA_PAYLOAD(list);
		__u16 last_vid_start = 0;

		if (!filter_vlan)
			print_vlan_port(fp, ifm->ifi_index);

		for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
			struct bridge_vlan_info *vinfo;
			int vcheck_ret;

			if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
				continue;

			vinfo = RTA_DATA(i);

			if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
				last_vid_start = vinfo->vid;
			vcheck_ret = filter_vlan_check(vinfo);
			if (vcheck_ret == -1)
				break;
			else if (vcheck_ret == 0)
				continue;

			if (filter_vlan)
				print_vlan_port(fp, ifm->ifi_index);
			if (jw_global) {
				jsonw_start_object(jw_global);
				jsonw_uint_field(jw_global, "vlan",
						 last_vid_start);
				if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
					continue;
			} else {
				fprintf(fp, "\t %hu", last_vid_start);
			}
			if (last_vid_start != vinfo->vid) {
				if (jw_global)
					jsonw_uint_field(jw_global, "vlanEnd",
							 vinfo->vid);
				else
					fprintf(fp, "-%hu", vinfo->vid);
			}
			if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
				if (jw_global) {
					start_json_vlan_flags_array(&vlan_flags);
					jsonw_string(jw_global, "PVID");
				} else {
					fprintf(fp, " PVID");
				}
			}
			if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
				if (jw_global) {
					start_json_vlan_flags_array(&vlan_flags);
					jsonw_string(jw_global,
						     "Egress Untagged");
				} else {
					fprintf(fp, " Egress Untagged");
				}
			}
			if (vlan_flags) {
				jsonw_end_array(jw_global);
				vlan_flags = false;
			}

			if (jw_global)
				jsonw_end_object(jw_global);
			else
				fprintf(fp, "\n");
		}
	}
	if (!filter_vlan) {
		if (jw_global)
			jsonw_end_array(jw_global);
		else
			fprintf(fp, "\n");

	}
	fflush(fp);
	return 0;
}