/* Add/Delete IP route to/from a specific interface */
static int
netlink_route(ip_route_t *iproute, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct rtmsg r;
		char buf[RTM_SIZE];
	} req;
	char buf[RTA_SIZE];
	struct rtattr *rta = (void*)buf;

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

	req.n.nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
	if (cmd == IPROUTE_DEL) {
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type  = RTM_DELROUTE;
	}
	else {
		req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
		if (cmd == IPROUTE_REPLACE)
			req.n.nlmsg_flags |= NLM_F_REPLACE;
		req.n.nlmsg_type  = RTM_NEWROUTE;
	}

	rta->rta_type = RTA_METRICS;
	rta->rta_len = RTA_LENGTH(0);

	req.r.rtm_family = iproute->family;
	if (iproute->table < 256)
		req.r.rtm_table = iproute->table;
	else {
		req.r.rtm_table = RT_TABLE_UNSPEC;
		addattr32(&req.n, sizeof(req), RTA_TABLE, iproute->table);
	}

	if (cmd == IPROUTE_DEL) {
		req.r.rtm_scope = RT_SCOPE_NOWHERE;
		if (iproute->mask & IPROUTE_BIT_TYPE)
			req.r.rtm_type = iproute->type;
	}
	else {
		req.r.rtm_protocol = RTPROT_BOOT;
		req.r.rtm_scope = RT_SCOPE_UNIVERSE;
		req.r.rtm_type = iproute->type;
	}

	if (iproute->mask & IPROUTE_BIT_PROTOCOL)
		req.r.rtm_protocol = iproute->protocol;

	if (iproute->mask & IPROUTE_BIT_SCOPE)
		req.r.rtm_scope = iproute->scope;

	if (iproute->dst) {
		req.r.rtm_dst_len = iproute->dst->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_DST, iproute->dst);
	}

	if (iproute->src) {
		req.r.rtm_src_len = iproute->src->ifa.ifa_prefixlen;
		add_addr2req(&req.n, sizeof(req), RTA_SRC, iproute->src);
	}

	if (iproute->pref_src)
		add_addr2req(&req.n, sizeof(req), RTA_PREFSRC, iproute->pref_src);

//#ifdef _HAVE_RTA_NEWDST_
//	if (iproute->as_to)
//		add_addr2req(&req.n, sizeof(req), RTA_NEWDST, iproute->as_to);
//#endif

	if (iproute->via) {
		if (iproute->via->ifa.ifa_family == iproute->family)
			add_addr2req(&req.n, sizeof(req), RTA_GATEWAY, iproute->via);
#ifdef _HAVE_RTA_VIA_
		else
			add_addr_fam2req(&req.n, sizeof(req), RTA_VIA, iproute->via);
#endif
	}

#ifdef _HAVE_RTA_ENCAP_
	if (iproute->encap.type != LWTUNNEL_ENCAP_NONE) {
		char encap_buf[ENCAP_RTA_SIZE];
		struct rtattr *encap_rta = (void *)encap_buf;

		encap_rta->rta_type = RTA_ENCAP;
		encap_rta->rta_len = RTA_LENGTH(0);
		add_encap(encap_rta, sizeof(encap_buf), &iproute->encap);

		if (encap_rta->rta_len > RTA_LENGTH(0))
			addraw_l(&req.n, sizeof(encap_buf), RTA_DATA(encap_rta), RTA_PAYLOAD(encap_rta));
	}
#endif

	if (iproute->mask & IPROUTE_BIT_DSFIELD)
		req.r.rtm_tos = iproute->tos;
	
	if (iproute->oif)
		addattr32(&req.n, sizeof(req), RTA_OIF, iproute->oif->ifindex);

	if (iproute->mask & IPROUTE_BIT_METRIC)
		addattr32(&req.n, sizeof(req), RTA_PRIORITY, iproute->metric);

	req.r.rtm_flags = iproute->flags;

	if (iproute->realms)
		addattr32(&req.n, sizeof(req), RTA_FLOW, iproute->realms);

#ifdef _HAVE_RTA_EXPIRES_
	if (iproute->mask & IPROUTE_BIT_EXPIRES)
		addattr32(&req.n, sizeof(req), RTA_EXPIRES, iproute->expires);
#endif

#ifdef RTAX_CC_ALGO
	if (iproute->congctl)
		rta_addattr_l(rta, sizeof(buf), RTAX_CC_ALGO, iproute->congctl, strlen(iproute->congctl));
#endif

	if (iproute->mask & IPROUTE_BIT_RTT)
		rta_addattr32(rta, sizeof(buf), RTAX_RTT, iproute->rtt);

	if (iproute->mask & IPROUTE_BIT_RTTVAR)
		rta_addattr32(rta, sizeof(buf), RTAX_RTTVAR, iproute->rttvar);

	if (iproute->mask & IPROUTE_BIT_RTO_MIN)
		rta_addattr32(rta, sizeof(buf), RTAX_RTO_MIN, iproute->rto_min);

#ifdef RTAX_FEATURES
	if (iproute->features)
		rta_addattr32(rta, sizeof(buf), RTAX_FEATURES, iproute->features);
#endif

	if (iproute->mask & IPROUTE_BIT_MTU)
		rta_addattr32(rta, sizeof(buf), RTAX_MTU, iproute->mtu);

	if (iproute->mask & IPROUTE_BIT_WINDOW)
		rta_addattr32(rta, sizeof(buf), RTAX_WINDOW, iproute->window);

	if (iproute->mask & IPROUTE_BIT_SSTHRESH)
		rta_addattr32(rta, sizeof(buf), RTAX_SSTHRESH, iproute->ssthresh);

	if (iproute->mask & IPROUTE_BIT_CWND)
		rta_addattr32(rta, sizeof(buf), RTAX_CWND, iproute->cwnd);

	if (iproute->mask & IPROUTE_BIT_ADVMSS)
		rta_addattr32(rta, sizeof(buf), RTAX_ADVMSS, iproute->advmss);

	if (iproute->mask & IPROUTE_BIT_REORDERING)
		rta_addattr32(rta, sizeof(buf), RTAX_REORDERING, iproute->reordering);

	if (iproute->mask & IPROUTE_BIT_HOPLIMIT)
		rta_addattr32(rta, sizeof(buf), RTAX_HOPLIMIT, iproute->hoplimit);

	if (iproute->mask & IPROUTE_BIT_INITCWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITCWND, iproute->initcwnd);

#ifdef RTAX_INITRWND
	if (iproute->mask & IPROUTE_BIT_INITRWND)
		rta_addattr32(rta, sizeof(buf), RTAX_INITRWND, iproute->initrwnd);
#endif

#ifdef RTAX_QUICKACK
	if (iproute->mask & IPROUTE_BIT_QUICKACK)
		rta_addattr32(rta, sizeof(buf), RTAX_QUICKACK, iproute->quickack);
#endif

#ifdef _HAVE_RTA_PREF_
	if (iproute->mask & IPROUTE_BIT_PREF)
		addattr8(&req.n, sizeof(req), RTA_PREF, iproute->pref);
#endif

	if (rta->rta_len > RTA_LENGTH(0)) {
		if (iproute->lock)
			rta_addattr32(rta, sizeof(buf), RTAX_LOCK, iproute->lock);
		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(rta), RTA_PAYLOAD(rta));
	}

	if (!LIST_ISEMPTY(iproute->nhs))
		add_nexthops(iproute, &req.n, &req.r);

#ifdef DEBUG_NETLINK_MSG
	size_t i, j;
	uint8_t *p;
	char lbuf[3072];
	char *op = lbuf;

	log_message(LOG_INFO, "rtmsg buffer used %lu, rtattr buffer used %d", req.n.nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)), rta->rta_len);

	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "nlmsghdr %p(%u):", &req.n, req.n.nlmsg_len);
	for (i = 0, p = (uint8_t*)&req.n; i < sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));
	log_message(LOG_INFO, "%s\n", lbuf);

	op = lbuf;
	op += snprintf(op, sizeof(lbuf) - (op - lbuf), "rtmsg %p(%lu):", &req.r, req.n.nlmsg_len - sizeof(struct nlmsghdr));
	for (i = 0, p = (uint8_t*)&req.r; i < + req.n.nlmsg_len - sizeof(struct nlmsghdr); i++)
		op += snprintf(op, sizeof(lbuf) - (op - lbuf), " %2.2hhx", *(p++));

	for (j = 0; lbuf + j < op; j+= MAX_LOG_MSG)
		log_message(LOG_INFO, "%.*\n", MAX_LOG_MSG, lbuf+j);
#endif

	/* This returns ESRCH if the address of via address doesn't exist */
	/* ENETDOWN if dev p33p1.40 for example is down */
	if (netlink_talk(&nl_cmd, &req.n) < 0) {
#ifdef _HAVE_RTA_EXPIRES_
		/* If an expiry was set on the route, it may have disappeared already */
		if (cmd != IPADDRESS_DEL || !(iproute->mask & IPROUTE_BIT_EXPIRES))
#endif
			status = -1;
	}

	return status;
}
Exemple #2
0
/* Add/Delete IP rule to/from a specific IP/network */
static int
netlink_rule(ip_rule_t *iprule, int cmd)
{
	int status = 1;
	struct {
		struct nlmsghdr n;
		struct fib_rule_hdr frh;
		char buf[1024];
	} req;

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

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST;

	if (cmd != IPRULE_DEL) {
		req.n.nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
		req.n.nlmsg_type = RTM_NEWRULE;
		req.frh.action = FR_ACT_UNSPEC;
	}
	else {
		req.frh.action = FR_ACT_UNSPEC;
		req.n.nlmsg_type = RTM_DELRULE;
	}
	req.frh.table = RT_TABLE_UNSPEC;
	req.frh.flags = 0;
	req.frh.tos = iprule->tos;	// Hex value - 0xnn <= 255, or name from rt_dsfield
	req.frh.family = iprule->family;

	if (iprule->action == FR_ACT_TO_TBL
#if HAVE_DECL_FRA_L3MDEV
	    && !iprule->l3mdev
#endif
					   ) {
		if (iprule->table < 256)	// "Table" or "lookup"
			req.frh.table = iprule->table ? iprule->table & 0xff : RT_TABLE_MAIN;
		else {
			req.frh.table = RT_TABLE_UNSPEC;
			addattr32(&req.n, sizeof(req), FRA_TABLE, iprule->table);
		}
	}

	if (iprule->invert)
		req.frh.flags |= FIB_RULE_INVERT;	// "not"

	/* Set rule entry */
	if (iprule->from_addr) {	// can be "default"/"any"/"all" - and to addr => bytelen == bitlen == 0
		add_addr2req(&req.n, sizeof(req), FRA_SRC, iprule->from_addr);
		req.frh.src_len = iprule->from_addr->ifa.ifa_prefixlen;
	}
	if (iprule->to_addr) {
		add_addr2req(&req.n, sizeof(req), FRA_DST, iprule->to_addr);
		req.frh.dst_len = iprule->to_addr->ifa.ifa_prefixlen;
	}

	if (iprule->mask & IPRULE_BIT_PRIORITY)	// "priority/order/preference"
		addattr32(&req.n, sizeof(req), FRA_PRIORITY, iprule->priority);

	if (iprule->mask & IPRULE_BIT_FWMARK)	// "fwmark"
		addattr32(&req.n, sizeof(req), FRA_FWMARK, iprule->fwmark);

	if (iprule->mask & IPRULE_BIT_FWMASK)	// "fwmark number followed by /nn"
		addattr32(&req.n, sizeof(req), FRA_FWMASK, iprule->fwmask);

	if (iprule->realms)	// "realms u16[/u16] using rt_realms. after / is 16 msb (src), pre slash is 16 lsb (dest)"
		addattr32(&req.n, sizeof(req), FRA_FLOW, iprule->realms);

#if HAVE_DECL_FRA_SUPPRESS_PREFIXLEN
	if (iprule->suppress_prefix_len != -1)	// "suppress_prefixlength" - only valid if table != 0
		addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, iprule->suppress_prefix_len);
#endif

#if HAVE_DECL_FRA_SUPPRESS_IFGROUP
	if (iprule->mask & IPRULE_BIT_SUP_GROUP)	// "suppress_ifgroup" or "sup_group" int32 - only valid if table !=0
		addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, iprule->suppress_group);
#endif

	if (iprule->iif)	// "dev/iif"
		addattr_l(&req.n, sizeof(req), FRA_IFNAME, iprule->iif, strlen(iprule->iif->ifname)+1);

#if HAVE_DECL_FRA_OIFNAME
	if (iprule->oif)	// "oif"
		addattr_l(&req.n, sizeof(req), FRA_OIFNAME, iprule->oif, strlen(iprule->oif->ifname)+1);
#endif

#if HAVE_DECL_FRA_TUN_ID
	if (iprule->tunnel_id)
		addattr64(&req.n, sizeof(req), FRA_TUN_ID, htobe64(iprule->tunnel_id));
#endif

#if HAVE_DECL_FRA_UID_RANGE
	if (iprule->mask & IPRULE_BIT_UID_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &iprule->uid_range, sizeof(iprule->uid_range));
#endif

#if HAVE_DECL_FRA_L3MDEV
	if (iprule->l3mdev)
		addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1);
#endif

#if HAVE_DECL_FRA_PROTOCOL
	if (iprule->mask & IPRULE_BIT_PROTOCOL)
		addattr8(&req.n, sizeof(req), FRA_PROTOCOL, iprule->protocol);
#endif

#if HAVE_DECL_FRA_IP_PROTO
	if (iprule->mask & IPRULE_BIT_IP_PROTO)
		addattr8(&req.n, sizeof(req), FRA_IP_PROTO, iprule->ip_proto);
#endif

#if HAVE_DECL_FRA_SPORT_RANGE
	if (iprule->mask & IPRULE_BIT_SPORT_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_SPORT_RANGE, &iprule->src_port, sizeof(iprule->src_port));
#endif

#if HAVE_DECL_FRA_DPORT_RANGE
	if (iprule->mask & IPRULE_BIT_DPORT_RANGE)
		addattr_l(&req.n, sizeof(req), FRA_DPORT_RANGE, &iprule->dst_port, sizeof(iprule->dst_port));
#endif

	if (iprule->action == FR_ACT_GOTO) {	// "goto"
		addattr32(&req.n, sizeof(req), FRA_GOTO, iprule->goto_target);
		req.frh.action = FR_ACT_GOTO;
	}

	req.frh.action = iprule->action;

	if (netlink_talk(&nl_cmd, &req.n) < 0)
		status = -1;

	return status;
}
Exemple #3
0
static int macsec_parse_opt(struct link_util *lu, int argc, char **argv,
			    struct nlmsghdr *n)
{
	int ret;
	__u8 encoding_sa = 0xff;
	__u32 window = -1;
	struct cipher_args cipher = {0};
	enum macsec_validation_type validate;
	bool es = false, scb = false, send_sci = false;
	int replay_protect = -1;
	struct sci sci = { 0 };

	ret = get_sci_portaddr(&sci, &argc, &argv, true, true);
	if (ret < 0) {
		fprintf(stderr, "expected sci\n");
		return -1;
	}

	if (ret > 0) {
		if (sci.sci)
			addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_SCI,
				  &sci.sci, sizeof(sci.sci));
		else
			addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_PORT,
				  &sci.port, sizeof(sci.port));
	}

	while (argc > 0) {
		if (strcmp(*argv, "cipher") == 0) {
			NEXT_ARG();
			if (cipher.id)
				duparg("cipher", *argv);
			if (strcmp(*argv, "default") == 0 ||
			    strcmp(*argv, "gcm-aes-128") == 0 ||
			    strcmp(*argv, "GCM-AES-128") == 0)
				cipher.id = MACSEC_DEFAULT_CIPHER_ID;
			else
				invarg("expected: default or gcm-aes-128",
				       *argv);
		} else if (strcmp(*argv, "icvlen") == 0) {
			NEXT_ARG();
			if (cipher.icv_len)
				duparg("icvlen", *argv);
			get_icvlen(&cipher.icv_len, *argv);
		} else if (strcmp(*argv, "encrypt") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("encrypt", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCRYPT, i);
		} else if (strcmp(*argv, "send_sci") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("send_sci", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			send_sci = i;
			addattr8(n, MACSEC_BUFLEN,
				 IFLA_MACSEC_INC_SCI, send_sci);
		} else if (strcmp(*argv, "end_station") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("end_station", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			es = i;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_ES, es);
		} else if (strcmp(*argv, "scb") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("scb", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			scb = i;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_SCB, scb);
		} else if (strcmp(*argv, "protect") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("protect", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_PROTECT, i);
		} else if (strcmp(*argv, "replay") == 0) {
			NEXT_ARG();
			int i;

			ret = one_of("replay", *argv, values_on_off,
				     ARRAY_SIZE(values_on_off), &i);
			if (ret != 0)
				return ret;
			replay_protect = !!i;
		} else if (strcmp(*argv, "window") == 0) {
			NEXT_ARG();
			ret = get_u32(&window, *argv, 0);
			if (ret)
				invarg("expected replay window size", *argv);
		} else if (strcmp(*argv, "validate") == 0) {
			NEXT_ARG();
			ret = one_of("validate", *argv,
				     validate_str, ARRAY_SIZE(validate_str),
				     (int *)&validate);
			if (ret != 0)
				return ret;
			addattr8(n, MACSEC_BUFLEN,
				 IFLA_MACSEC_VALIDATION, validate);
		} else if (strcmp(*argv, "encodingsa") == 0) {
			if (encoding_sa != 0xff)
				duparg2("encodingsa", "encodingsa");
			NEXT_ARG();
			ret = get_an(&encoding_sa, *argv);
			if (ret)
				invarg("expected an { 0..3 }", *argv);
		} else {
			fprintf(stderr, "macsec: unknown command \"%s\"?\n",
				*argv);
			usage(stderr);
			return -1;
		}

		argv++; argc--;
	}

	if (!check_txsc_flags(es, scb, send_sci)) {
		fprintf(stderr,
			"invalid combination of send_sci/end_station/scb\n");
		return -1;
	}

	if (window != -1 && replay_protect == -1) {
		fprintf(stderr,
			"replay window set, but replay protection not enabled. did you mean 'replay on window %u'?\n",
			window);
		return -1;
	} else if (window == -1 && replay_protect == 1) {
		fprintf(stderr,
			"replay protection enabled, but no window set. did you mean 'replay on window VALUE'?\n");
		return -1;
	}

	if (cipher.id)
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_CIPHER_SUITE,
			  &cipher.id, sizeof(cipher.id));
	if (cipher.icv_len)
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ICV_LEN,
			  &cipher.icv_len, sizeof(cipher.icv_len));

	if (replay_protect != -1) {
		addattr32(n, MACSEC_BUFLEN, IFLA_MACSEC_WINDOW, window);
		addattr8(n, MACSEC_BUFLEN, IFLA_MACSEC_REPLAY_PROTECT,
			 replay_protect);
	}

	if (encoding_sa != 0xff) {
		addattr_l(n, MACSEC_BUFLEN, IFLA_MACSEC_ENCODING_SA,
			  &encoding_sa, sizeof(encoding_sa));
	}

	return 0;
}
Exemple #4
0
static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
			 bool adding)
{
	__u16 port;
	int port_set = 0;
	__u8 ipproto, type;
	bool gue_set = false;
	int ipproto_set = 0;

	while (argc > 0) {
		if (!matches(*argv, "port")) {
			NEXT_ARG();

			if (get_u16(&port, *argv, 0) || port == 0)
				invarg("invalid port", *argv);
			port = htons(port);
			port_set = 1;
		} else if (!matches(*argv, "ipproto")) {
			struct protoent *servptr;

			NEXT_ARG();

			servptr = getprotobyname(*argv);
			if (servptr)
				ipproto = servptr->p_proto;
			else if (get_u8(&ipproto, *argv, 0) || ipproto == 0)
				invarg("invalid ipproto", *argv);
			ipproto_set = 1;
		} else if (!matches(*argv, "gue")) {
			gue_set = true;
		} else {
			fprintf(stderr, "fou: unknown command \"%s\"?\n", *argv);
			usage();
			return -1;
		}
		argc--, argv++;
	}

	if (!port_set) {
		fprintf(stderr, "fou: missing port\n");
		return -1;
	}

	if (!ipproto_set && !gue_set && adding) {
		fprintf(stderr, "fou: must set ipproto or gue\n");
		return -1;
	}

	if (ipproto_set && gue_set) {
		fprintf(stderr, "fou: cannot set ipproto and gue\n");
		return -1;
	}

	type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT;

	addattr16(n, 1024, FOU_ATTR_PORT, port);
	addattr8(n, 1024, FOU_ATTR_TYPE, type);

	if (ipproto_set)
		addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto);

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

	*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 (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);
			len = iplink_parse_vf(vf, &argc, &argv, req);
			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;
		}
		argc--; argv++;
	}

	return ret - argc;
}
Exemple #6
0
static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
			    struct nlmsghdr *n)
{
	__u32 val;

	while (argc > 0) {
		if (matches(*argv, "forward_delay") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid forward_delay", *argv);

			addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
		} else if (matches(*argv, "hello_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid hello_time", *argv);

			addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
		} else if (matches(*argv, "max_age") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid max_age", *argv);

			addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
		} else if (matches(*argv, "ageing_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid ageing_time", *argv);

			addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
		} else if (matches(*argv, "stp_state") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid stp_state", *argv);

			addattr32(n, 1024, IFLA_BR_STP_STATE, val);
		} else if (matches(*argv, "priority") == 0) {
			__u16 prio;

			NEXT_ARG();
			if (get_u16(&prio, *argv, 0))
				invarg("invalid priority", *argv);

			addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
		} else if (matches(*argv, "vlan_filtering") == 0) {
			__u8 vlan_filter;

			NEXT_ARG();
			if (get_u8(&vlan_filter, *argv, 0))
				invarg("invalid vlan_filtering", *argv);

			addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
		} else if (matches(*argv, "vlan_protocol") == 0) {
			__u16 vlan_proto;

			NEXT_ARG();
			if (ll_proto_a2n(&vlan_proto, *argv))
				invarg("invalid vlan_protocol", *argv);

			addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
		} else if (matches(*argv, "group_fwd_mask") == 0) {
			__u16 fwd_mask;

			NEXT_ARG();
			if (get_u16(&fwd_mask, *argv, 0))
				invarg("invalid group_fwd_mask", *argv);

			addattr16(n, 1024, IFLA_BR_GROUP_FWD_MASK, fwd_mask);
		} else if (matches(*argv, "group_address") == 0) {
			char llabuf[32];
			int len;

			NEXT_ARG();
			len = ll_addr_a2n(llabuf, sizeof(llabuf), *argv);
			if (len < 0)
				return -1;
			addattr_l(n, 1024, IFLA_BR_GROUP_ADDR, llabuf, len);
		} else if (matches(*argv, "fdb_flush") == 0) {
			addattr(n, 1024, IFLA_BR_FDB_FLUSH);
		} else if (matches(*argv, "vlan_default_pvid") == 0) {
			__u16 default_pvid;

			NEXT_ARG();
			if (get_u16(&default_pvid, *argv, 0))
				invarg("invalid vlan_default_pvid", *argv);

			addattr16(n, 1024, IFLA_BR_VLAN_DEFAULT_PVID,
				  default_pvid);
		} else if (matches(*argv, "vlan_stats_enabled") == 0) {
			__u8 vlan_stats_enabled;

			NEXT_ARG();
			if (get_u8(&vlan_stats_enabled, *argv, 0))
				invarg("invalid vlan_stats_enabled", *argv);
			addattr8(n, 1024, IFLA_BR_VLAN_STATS_ENABLED,
				  vlan_stats_enabled);
		} else if (matches(*argv, "mcast_router") == 0) {
			__u8 mcast_router;

			NEXT_ARG();
			if (get_u8(&mcast_router, *argv, 0))
				invarg("invalid mcast_router", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_ROUTER, mcast_router);
		} else if (matches(*argv, "mcast_snooping") == 0) {
			__u8 mcast_snoop;

			NEXT_ARG();
			if (get_u8(&mcast_snoop, *argv, 0))
				invarg("invalid mcast_snooping", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_SNOOPING, mcast_snoop);
		} else if (matches(*argv, "mcast_query_use_ifaddr") == 0) {
			__u8 mcast_qui;

			NEXT_ARG();
			if (get_u8(&mcast_qui, *argv, 0))
				invarg("invalid mcast_query_use_ifaddr",
				       *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_QUERY_USE_IFADDR,
				 mcast_qui);
		} else if (matches(*argv, "mcast_querier") == 0) {
			__u8 mcast_querier;

			NEXT_ARG();
			if (get_u8(&mcast_querier, *argv, 0))
				invarg("invalid mcast_querier", *argv);

			addattr8(n, 1024, IFLA_BR_MCAST_QUERIER, mcast_querier);
		} else if (matches(*argv, "mcast_hash_elasticity") == 0) {
			__u32 mcast_hash_el;

			NEXT_ARG();
			if (get_u32(&mcast_hash_el, *argv, 0))
				invarg("invalid mcast_hash_elasticity",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_HASH_ELASTICITY,
				  mcast_hash_el);
		} else if (matches(*argv, "mcast_hash_max") == 0) {
			__u32 mcast_hash_max;

			NEXT_ARG();
			if (get_u32(&mcast_hash_max, *argv, 0))
				invarg("invalid mcast_hash_max", *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_HASH_MAX,
				  mcast_hash_max);
		} else if (matches(*argv, "mcast_last_member_count") == 0) {
			__u32 mcast_lmc;

			NEXT_ARG();
			if (get_u32(&mcast_lmc, *argv, 0))
				invarg("invalid mcast_last_member_count",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_CNT,
				  mcast_lmc);
		} else if (matches(*argv, "mcast_startup_query_count") == 0) {
			__u32 mcast_sqc;

			NEXT_ARG();
			if (get_u32(&mcast_sqc, *argv, 0))
				invarg("invalid mcast_startup_query_count",
				       *argv);

			addattr32(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
				  mcast_sqc);
		} else if (matches(*argv, "mcast_last_member_interval") == 0) {
			__u64 mcast_last_member_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_last_member_intvl, *argv, 0))
				invarg("invalid mcast_last_member_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_LAST_MEMBER_INTVL,
				  mcast_last_member_intvl);
		} else if (matches(*argv, "mcast_membership_interval") == 0) {
			__u64 mcast_membership_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_membership_intvl, *argv, 0))
				invarg("invalid mcast_membership_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_MEMBERSHIP_INTVL,
				  mcast_membership_intvl);
		} else if (matches(*argv, "mcast_querier_interval") == 0) {
			__u64 mcast_querier_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_querier_intvl, *argv, 0))
				invarg("invalid mcast_querier_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERIER_INTVL,
				  mcast_querier_intvl);
		} else if (matches(*argv, "mcast_query_interval") == 0) {
			__u64 mcast_query_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_query_intvl, *argv, 0))
				invarg("invalid mcast_query_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERY_INTVL,
				  mcast_query_intvl);
		} else if (!matches(*argv, "mcast_query_response_interval")) {
			__u64 mcast_query_resp_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_query_resp_intvl, *argv, 0))
				invarg("invalid mcast_query_response_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL,
				  mcast_query_resp_intvl);
		} else if (!matches(*argv, "mcast_startup_query_interval")) {
			__u64 mcast_startup_query_intvl;

			NEXT_ARG();
			if (get_u64(&mcast_startup_query_intvl, *argv, 0))
				invarg("invalid mcast_startup_query_interval",
				       *argv);

			addattr64(n, 1024, IFLA_BR_MCAST_STARTUP_QUERY_INTVL,
				  mcast_startup_query_intvl);
		} else if (matches(*argv, "mcast_stats_enabled") == 0) {
			__u8 mcast_stats_enabled;

			NEXT_ARG();
			if (get_u8(&mcast_stats_enabled, *argv, 0))
				invarg("invalid mcast_stats_enabled", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_STATS_ENABLED,
				  mcast_stats_enabled);
		} else if (matches(*argv, "mcast_igmp_version") == 0) {
			__u8 igmp_version;

			NEXT_ARG();
			if (get_u8(&igmp_version, *argv, 0))
				invarg("invalid mcast_igmp_version", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_IGMP_VERSION,
				  igmp_version);
		} else if (matches(*argv, "mcast_mld_version") == 0) {
			__u8 mld_version;

			NEXT_ARG();
			if (get_u8(&mld_version, *argv, 0))
				invarg("invalid mcast_mld_version", *argv);
			addattr8(n, 1024, IFLA_BR_MCAST_MLD_VERSION,
				  mld_version);
		} else if (matches(*argv, "nf_call_iptables") == 0) {
			__u8 nf_call_ipt;

			NEXT_ARG();
			if (get_u8(&nf_call_ipt, *argv, 0))
				invarg("invalid nf_call_iptables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_IPTABLES,
				 nf_call_ipt);
		} else if (matches(*argv, "nf_call_ip6tables") == 0) {
			__u8 nf_call_ip6t;

			NEXT_ARG();
			if (get_u8(&nf_call_ip6t, *argv, 0))
				invarg("invalid nf_call_ip6tables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_IP6TABLES,
				 nf_call_ip6t);
		} else if (matches(*argv, "nf_call_arptables") == 0) {
			__u8 nf_call_arpt;

			NEXT_ARG();
			if (get_u8(&nf_call_arpt, *argv, 0))
				invarg("invalid nf_call_arptables", *argv);

			addattr8(n, 1024, IFLA_BR_NF_CALL_ARPTABLES,
				 nf_call_arpt);
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	return 0;
}
Exemple #7
0
static int bridge_parse_opt(struct link_util *lu, int argc, char **argv,
			    struct nlmsghdr *n)
{
	__u32 val;

	while (argc > 0) {
		if (matches(*argv, "forward_delay") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid forward_delay", *argv);

			addattr32(n, 1024, IFLA_BR_FORWARD_DELAY, val);
		} else if (matches(*argv, "hello_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid hello_time", *argv);

			addattr32(n, 1024, IFLA_BR_HELLO_TIME, val);
		} else if (matches(*argv, "max_age") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid max_age", *argv);

			addattr32(n, 1024, IFLA_BR_MAX_AGE, val);
		} else if (matches(*argv, "ageing_time") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid ageing_time", *argv);

			addattr32(n, 1024, IFLA_BR_AGEING_TIME, val);
		} else if (matches(*argv, "stp_state") == 0) {
			NEXT_ARG();
			if (get_u32(&val, *argv, 0))
				invarg("invalid stp_state", *argv);

			addattr32(n, 1024, IFLA_BR_STP_STATE, val);
		} else if (matches(*argv, "priority") == 0) {
			__u16 prio;

			NEXT_ARG();
			if (get_u16(&prio, *argv, 0))
				invarg("invalid priority", *argv);

			addattr16(n, 1024, IFLA_BR_PRIORITY, prio);
		} else if (matches(*argv, "vlan_filtering") == 0) {
			__u8 vlan_filter;

			NEXT_ARG();
			if (get_u8(&vlan_filter, *argv, 0)) {
				invarg("invalid vlan_filtering", *argv);
				return -1;
			}
			addattr8(n, 1024, IFLA_BR_VLAN_FILTERING, vlan_filter);
		} else if (matches(*argv, "vlan_protocol") == 0) {
			__u16 vlan_proto;

			NEXT_ARG();
			if (ll_proto_a2n(&vlan_proto, *argv)) {
				invarg("invalid vlan_protocol", *argv);
				return -1;
			}
			addattr16(n, 1024, IFLA_BR_VLAN_PROTOCOL, vlan_proto);
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "bridge: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	return 0;
}
Exemple #8
0
static int iptunnel_parse_opt(struct link_util *lu, int argc, char **argv,
			      struct nlmsghdr *n)
{
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
		char buf[2048];
	} req;
	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
	struct rtattr *tb[IFLA_MAX + 1];
	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
	struct rtattr *iptuninfo[IFLA_IPTUN_MAX + 1];
	int len;
	__u32 link = 0;
	__u32 laddr = 0;
	__u32 raddr = 0;
	__u8 ttl = 0;
	__u8 tos = 0;
	__u8 pmtudisc = 1;
	__u16 iflags = 0;
	__u8 proto = 0;
	struct in6_addr ip6rdprefix;
	__u16 ip6rdprefixlen = 0;
	__u32 ip6rdrelayprefix = 0;
	__u16 ip6rdrelayprefixlen = 0;

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

	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
		memset(&req, 0, sizeof(req));

		req.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
		req.n.nlmsg_flags = NLM_F_REQUEST;
		req.n.nlmsg_type = RTM_GETLINK;
		req.i.ifi_family = preferred_family;
		req.i.ifi_index = ifi->ifi_index;

		if (rtnl_talk(&rth, &req.n, 0, 0, &req.n) < 0) {
get_failed:
			fprintf(stderr,
				"Failed to get existing tunnel info.\n");
			return -1;
		}

		len = req.n.nlmsg_len;
		len -= NLMSG_LENGTH(sizeof(*ifi));
		if (len < 0)
			goto get_failed;

		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);

		if (!tb[IFLA_LINKINFO])
			goto get_failed;

		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (!linkinfo[IFLA_INFO_DATA])
			goto get_failed;

		parse_rtattr_nested(iptuninfo, IFLA_IPTUN_MAX,
				    linkinfo[IFLA_INFO_DATA]);

		if (iptuninfo[IFLA_IPTUN_LOCAL])
			laddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LOCAL]);

		if (iptuninfo[IFLA_IPTUN_REMOTE])
			raddr = rta_getattr_u32(iptuninfo[IFLA_IPTUN_REMOTE]);

		if (iptuninfo[IFLA_IPTUN_TTL])
			ttl = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TTL]);

		if (iptuninfo[IFLA_IPTUN_TOS])
			tos = rta_getattr_u8(iptuninfo[IFLA_IPTUN_TOS]);

		if (iptuninfo[IFLA_IPTUN_PMTUDISC])
			pmtudisc =
				rta_getattr_u8(iptuninfo[IFLA_IPTUN_PMTUDISC]);

		if (iptuninfo[IFLA_IPTUN_FLAGS])
			iflags = rta_getattr_u16(iptuninfo[IFLA_IPTUN_FLAGS]);

		if (iptuninfo[IFLA_IPTUN_LINK])
			link = rta_getattr_u32(iptuninfo[IFLA_IPTUN_LINK]);

		if (iptuninfo[IFLA_IPTUN_PROTO])
			proto = rta_getattr_u8(iptuninfo[IFLA_IPTUN_PROTO]);

		if (iptuninfo[IFLA_IPTUN_6RD_PREFIX])
			memcpy(&ip6rdprefix,
			       RTA_DATA(iptuninfo[IFLA_IPTUN_6RD_PREFIX]),
			       sizeof(laddr));

		if (iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN])
			ip6rdprefixlen =
				rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_PREFIXLEN]);

		if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX])
			ip6rdrelayprefix =
				rta_getattr_u32(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIX]);

		if (iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN])
			ip6rdrelayprefixlen =
				rta_getattr_u16(iptuninfo[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
	}

	while (argc > 0) {
		if (strcmp(*argv, "remote") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				raddr = get_addr32(*argv);
			else
				raddr = 0;
		} else if (strcmp(*argv, "local") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				laddr = get_addr32(*argv);
			else
				laddr = 0;
		} else if (matches(*argv, "dev") == 0) {
			NEXT_ARG();
			link = if_nametoindex(*argv);
			if (link == 0)
				invarg("\"dev\" is invalid", *argv);
		} else if (strcmp(*argv, "ttl") == 0 ||
			   strcmp(*argv, "hoplimit") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_u8(&ttl, *argv, 0))
					invarg("invalid TTL\n", *argv);
			} else
				ttl = 0;
		} else if (strcmp(*argv, "tos") == 0 ||
			   strcmp(*argv, "tclass") == 0 ||
			   matches(*argv, "dsfield") == 0) {
			__u32 uval;
			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else if (strcmp(*argv, "nopmtudisc") == 0) {
			pmtudisc = 0;
		} else if (strcmp(*argv, "pmtudisc") == 0) {
			pmtudisc = 1;
		} else if (strcmp(lu->id, "sit") == 0 &&
			   strcmp(*argv, "isatap") == 0) {
			iflags |= SIT_ISATAP;
		} else if (strcmp(lu->id, "sit") == 0 &&
			   strcmp(*argv, "mode") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "ipv6/ipv4") == 0 ||
			    strcmp(*argv, "ip6ip") == 0)
				proto = IPPROTO_IPV6;
			else if (strcmp(*argv, "ipv4/ipv4") == 0 ||
				 strcmp(*argv, "ipip") == 0 ||
				 strcmp(*argv, "ip4ip4") == 0)
				proto = IPPROTO_IPIP;
			else if (strcmp(*argv, "any/ipv4") == 0 ||
				 strcmp(*argv, "any") == 0)
				proto = 0;
			else
				invarg("Cannot guess tunnel mode.", *argv);
		} else if (strcmp(*argv, "6rd-prefix") == 0) {
			inet_prefix prefix;
			NEXT_ARG();
			if (get_prefix(&prefix, *argv, AF_INET6))
				invarg("invalid 6rd_prefix\n", *argv);
			memcpy(&ip6rdprefix, prefix.data, 16);
			ip6rdprefixlen = prefix.bitlen;
		} else if (strcmp(*argv, "6rd-relay_prefix") == 0) {
			inet_prefix prefix;
			NEXT_ARG();
			if (get_prefix(&prefix, *argv, AF_INET))
				invarg("invalid 6rd-relay_prefix\n", *argv);
			memcpy(&ip6rdrelayprefix, prefix.data, 4);
			ip6rdrelayprefixlen = prefix.bitlen;
		} else if (strcmp(*argv, "6rd-reset") == 0) {
			inet_prefix prefix;
			get_prefix(&prefix, "2002::", AF_INET6);
			memcpy(&ip6rdprefix, prefix.data, 16);
			ip6rdprefixlen = 16;
			ip6rdrelayprefix = 0;
			ip6rdrelayprefixlen = 0;
		} else
			usage(strcmp(lu->id, "sit") == 0);
		argc--, argv++;
	}

	if (ttl && pmtudisc == 0) {
		fprintf(stderr, "ttl != 0 and noptmudisc are incompatible\n");
		exit(-1);
	}

	addattr32(n, 1024, IFLA_IPTUN_LINK, link);
	addattr32(n, 1024, IFLA_IPTUN_LOCAL, laddr);
	addattr32(n, 1024, IFLA_IPTUN_REMOTE, raddr);
	addattr8(n, 1024, IFLA_IPTUN_TTL, ttl);
	addattr8(n, 1024, IFLA_IPTUN_TOS, tos);
	addattr8(n, 1024, IFLA_IPTUN_PMTUDISC, pmtudisc);
	if (strcmp(lu->id, "sit") == 0) {
		addattr16(n, 1024, IFLA_IPTUN_FLAGS, iflags);
		addattr8(n, 1024, IFLA_IPTUN_PROTO, proto);
		if (ip6rdprefixlen) {
			addattr_l(n, 1024, IFLA_IPTUN_6RD_PREFIX,
				  &ip6rdprefix, sizeof(ip6rdprefix));
			addattr16(n, 1024, IFLA_IPTUN_6RD_PREFIXLEN,
				  ip6rdprefixlen);
			addattr32(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIX,
				  ip6rdrelayprefix);
			addattr16(n, 1024, IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
				  ip6rdrelayprefixlen);
		}
	}

	return 0;
}
Exemple #9
0
static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
			  struct nlmsghdr *n)
{
	__u32 vni = 0;
	__u32 gaddr = 0;
	__u32 daddr = 0;
	struct in6_addr gaddr6 = IN6ADDR_ANY_INIT;
	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
	__u8 learning = 1;
	__u16 dstport = 0;
	__u8 metadata = 0;
	__u64 attrs = 0;
	bool set_op = (n->nlmsg_type == RTM_NEWLINK &&
		       !(n->nlmsg_flags & NLM_F_CREATE));

	while (argc > 0) {
		if (!matches(*argv, "id") ||
		    !matches(*argv, "vni")) {
			/* We will add ID attribute outside of the loop since we
			 * need to consider metadata information as well.
			 */
			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_ID, "id", *argv);
			if (get_u32(&vni, *argv, 0) ||
			    vni >= 1u << 24)
				invarg("invalid id", *argv);
		} else if (!matches(*argv, "group")) {
			if (daddr || !IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
				fprintf(stderr, "vxlan: both group and remote");
				fprintf(stderr, " cannot be specified\n");
				return -1;
			}
			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_GROUP, "group", *argv);
			if (!inet_get_addr(*argv, &gaddr, &gaddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
				invarg("invalid group address", *argv);
		} else if (!matches(*argv, "remote")) {
			if (gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) {
				fprintf(stderr, "vxlan: both group and remote");
				fprintf(stderr, " cannot be specified\n");
				return -1;
			}
			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_GROUP, "remote", *argv);
			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
				invarg("invalid remote address", *argv);
		} else if (!matches(*argv, "local")) {
			__u32 saddr = 0;
			struct in6_addr saddr6 = IN6ADDR_ANY_INIT;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_LOCAL, "local", *argv);
			if (strcmp(*argv, "any")) {
				if (!inet_get_addr(*argv, &saddr, &saddr6)) {
					fprintf(stderr, "Invalid address \"%s\"\n", *argv);
					return -1;
				}
			}

			if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
				invarg("invalid local address", *argv);

			if (saddr)
				addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
			else if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6))
				addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6,
					  sizeof(struct in6_addr));
		} else if (!matches(*argv, "dev")) {
			unsigned int link;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_LINK, "dev", *argv);
			link = if_nametoindex(*argv);
			if (link == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n",
					*argv);
				exit(-1);
			}
			addattr32(n, 1024, IFLA_VXLAN_LINK, link);
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned int uval;
			__u8 ttl = 0;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_TTL, "ttl", *argv);
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255", *argv);
				ttl = uval;
			}
			addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;
			__u8 tos;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_TOS, "tos", *argv);
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
			addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
		} else if (!matches(*argv, "label") ||
			   !matches(*argv, "flowlabel")) {
			__u32 uval;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_LABEL, "flowlabel",
				     *argv);
			if (get_u32(&uval, *argv, 0) ||
			    (uval & ~LABEL_MAX_MASK))
				invarg("invalid flowlabel", *argv);
			addattr32(n, 1024, IFLA_VXLAN_LABEL, htonl(uval));
		} else if (!matches(*argv, "ageing")) {
			__u32 age;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_AGEING, "ageing",
				     *argv);
			if (strcmp(*argv, "none") == 0)
				age = 0;
			else if (get_u32(&age, *argv, 0))
				invarg("ageing timer", *argv);
			addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
		} else if (!matches(*argv, "maxaddress")) {
			__u32 maxaddr;

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_LIMIT,
				     "maxaddress", *argv);
			if (strcmp(*argv, "unlimited") == 0)
				maxaddr = 0;
			else if (get_u32(&maxaddr, *argv, 0))
				invarg("max addresses", *argv);
			addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
		} else if (!matches(*argv, "port") ||
			   !matches(*argv, "srcport")) {
			struct ifla_vxlan_port_range range = { 0, 0 };

			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_PORT_RANGE, "srcport",
				     *argv);
			if (get_be16(&range.low, *argv, 0))
				invarg("min port", *argv);
			NEXT_ARG();
			if (get_be16(&range.high, *argv, 0))
				invarg("max port", *argv);
			if (range.low || range.high) {
				addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
					  &range, sizeof(range));
			}
		} else if (!matches(*argv, "dstport")) {
			NEXT_ARG();
			check_duparg(&attrs, IFLA_VXLAN_PORT, "dstport", *argv);
			if (get_u16(&dstport, *argv, 0))
				invarg("dst port", *argv);
		} else if (!matches(*argv, "nolearning")) {
			check_duparg(&attrs, IFLA_VXLAN_LEARNING, *argv, *argv);
			learning = 0;
		} else if (!matches(*argv, "learning")) {
			check_duparg(&attrs, IFLA_VXLAN_LEARNING, *argv, *argv);
			learning = 1;
		} else if (!matches(*argv, "noproxy")) {
			check_duparg(&attrs, IFLA_VXLAN_PROXY, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_PROXY, 0);
		} else if (!matches(*argv, "proxy")) {
			check_duparg(&attrs, IFLA_VXLAN_PROXY, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_PROXY, 1);
		} else if (!matches(*argv, "norsc")) {
			check_duparg(&attrs, IFLA_VXLAN_RSC, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_RSC, 0);
		} else if (!matches(*argv, "rsc")) {
			check_duparg(&attrs, IFLA_VXLAN_RSC, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_RSC, 1);
		} else if (!matches(*argv, "nol2miss")) {
			check_duparg(&attrs, IFLA_VXLAN_L2MISS, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_L2MISS, 0);
		} else if (!matches(*argv, "l2miss")) {
			check_duparg(&attrs, IFLA_VXLAN_L2MISS, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_L2MISS, 1);
		} else if (!matches(*argv, "nol3miss")) {
			check_duparg(&attrs, IFLA_VXLAN_L3MISS, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_L3MISS, 0);
		} else if (!matches(*argv, "l3miss")) {
			check_duparg(&attrs, IFLA_VXLAN_L3MISS, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_L3MISS, 1);
		} else if (!matches(*argv, "udpcsum")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_CSUM, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, 1);
		} else if (!matches(*argv, "noudpcsum")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_CSUM, *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, 0);
		} else if (!matches(*argv, "udp6zerocsumtx")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 1);
		} else if (!matches(*argv, "noudp6zerocsumtx")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, 0);
		} else if (!matches(*argv, "udp6zerocsumrx")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 1);
		} else if (!matches(*argv, "noudp6zerocsumrx")) {
			check_duparg(&attrs, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, 0);
		} else if (!matches(*argv, "remcsumtx")) {
			check_duparg(&attrs, IFLA_VXLAN_REMCSUM_TX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, 1);
		} else if (!matches(*argv, "noremcsumtx")) {
			check_duparg(&attrs, IFLA_VXLAN_REMCSUM_TX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, 0);
		} else if (!matches(*argv, "remcsumrx")) {
			check_duparg(&attrs, IFLA_VXLAN_REMCSUM_RX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, 1);
		} else if (!matches(*argv, "noremcsumrx")) {
			check_duparg(&attrs, IFLA_VXLAN_REMCSUM_RX,
				     *argv, *argv);
			addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, 0);
		} else if (!matches(*argv, "external")) {
			check_duparg(&attrs, IFLA_VXLAN_COLLECT_METADATA,
				     *argv, *argv);
			metadata = 1;
			learning = 0;
			/* we will add LEARNING attribute outside of the loop */
			addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA,
				 metadata);
		} else if (!matches(*argv, "noexternal")) {
			check_duparg(&attrs, IFLA_VXLAN_COLLECT_METADATA,
				     *argv, *argv);
			metadata = 0;
			addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA,
				 metadata);
		} else if (!matches(*argv, "gbp")) {
			check_duparg(&attrs, IFLA_VXLAN_GBP, *argv, *argv);
			addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
		} else if (!matches(*argv, "gpe")) {
			check_duparg(&attrs, IFLA_VXLAN_GPE, *argv, *argv);
			addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0);
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	if (metadata && VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) {
		fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n");
		return -1;
	}

	if (!metadata && !VXLAN_ATTRSET(attrs, IFLA_VXLAN_ID)) {
		fprintf(stderr, "vxlan: missing virtual network identifier\n");
		return -1;
	}

	if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) &&
	    !VXLAN_ATTRSET(attrs, IFLA_VXLAN_LINK)) {
		fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n");
		return -1;
	}

	if (!VXLAN_ATTRSET(attrs, IFLA_VXLAN_PORT) &&
	    VXLAN_ATTRSET(attrs, IFLA_VXLAN_GPE)) {
		dstport = 4790;
	} else if (!VXLAN_ATTRSET(attrs, IFLA_VXLAN_PORT) && !set_op) {
		fprintf(stderr, "vxlan: destination port not specified\n"
			"Will use Linux kernel default (non-standard value)\n");
		fprintf(stderr,
			"Use 'dstport 4789' to get the IANA assigned value\n"
			"Use 'dstport 0' to get default and quiet this message\n");
	}

	addattr32(n, 1024, IFLA_VXLAN_ID, vni);
	if (gaddr)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
	else if (daddr)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
	else if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6))
		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr));
	else if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));
	else if (preferred_family == AF_INET)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
	else if (preferred_family == AF_INET6)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));

	if (!set_op || VXLAN_ATTRSET(attrs, IFLA_VXLAN_LEARNING))
		addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);

	if (dstport)
		addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));

	return 0;
}
Exemple #10
0
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
			 struct nlmsghdr *n)
{
	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
		char buf[16384];
	} req = {
		.n.nlmsg_len = NLMSG_LENGTH(sizeof(*ifi)),
		.n.nlmsg_flags = NLM_F_REQUEST,
		.n.nlmsg_type = RTM_GETLINK,
		.i.ifi_family = preferred_family,
		.i.ifi_index = ifi->ifi_index,
	};
	struct rtattr *tb[IFLA_MAX + 1];
	struct rtattr *linkinfo[IFLA_INFO_MAX+1];
	struct rtattr *greinfo[IFLA_GRE_MAX + 1];
	__u16 iflags = 0;
	__u16 oflags = 0;
	unsigned int ikey = 0;
	unsigned int okey = 0;
	unsigned int saddr = 0;
	unsigned int daddr = 0;
	unsigned int link = 0;
	__u8 pmtudisc = 1;
	__u8 ttl = 0;
	__u8 tos = 0;
	int len;
	__u16 encaptype = 0;
	__u16 encapflags = 0;
	__u16 encapsport = 0;
	__u16 encapdport = 0;
	__u8 metadata = 0;
	__u8 ignore_df = 0;
	__u32 fwmark = 0;
	__u32 erspan_idx = 0;
	__u8 keepalive_ret = 0;
	__u32 keepalive_interv = 0;

	if (!(n->nlmsg_flags & NLM_F_CREATE)) {
		if (rtnl_talk(&rth, &req.n, &req.n, sizeof(req)) < 0) {
get_failed:
			fprintf(stderr,
				"Failed to get existing tunnel info.\n");
			return -1;
		}

		len = req.n.nlmsg_len;
		len -= NLMSG_LENGTH(sizeof(*ifi));
		if (len < 0)
			goto get_failed;

		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(&req.i), len);

		if (!tb[IFLA_LINKINFO])
			goto get_failed;

		parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);

		if (!linkinfo[IFLA_INFO_DATA])
			goto get_failed;

		parse_rtattr_nested(greinfo, IFLA_GRE_MAX,
				    linkinfo[IFLA_INFO_DATA]);

		if (greinfo[IFLA_GRE_IKEY])
			ikey = rta_getattr_u32(greinfo[IFLA_GRE_IKEY]);

		if (greinfo[IFLA_GRE_OKEY])
			okey = rta_getattr_u32(greinfo[IFLA_GRE_OKEY]);

		if (greinfo[IFLA_GRE_IFLAGS])
			iflags = rta_getattr_u16(greinfo[IFLA_GRE_IFLAGS]);

		if (greinfo[IFLA_GRE_OFLAGS])
			oflags = rta_getattr_u16(greinfo[IFLA_GRE_OFLAGS]);

		if (greinfo[IFLA_GRE_LOCAL])
			saddr = rta_getattr_u32(greinfo[IFLA_GRE_LOCAL]);

		if (greinfo[IFLA_GRE_REMOTE])
			daddr = rta_getattr_u32(greinfo[IFLA_GRE_REMOTE]);

		if (greinfo[IFLA_GRE_PMTUDISC])
			pmtudisc = rta_getattr_u8(
				greinfo[IFLA_GRE_PMTUDISC]);

		if (greinfo[IFLA_GRE_TTL])
			ttl = rta_getattr_u8(greinfo[IFLA_GRE_TTL]);

		if (greinfo[IFLA_GRE_TOS])
			tos = rta_getattr_u8(greinfo[IFLA_GRE_TOS]);

		if (greinfo[IFLA_GRE_LINK])
			link = rta_getattr_u8(greinfo[IFLA_GRE_LINK]);

		if (greinfo[IFLA_GRE_ENCAP_TYPE])
			encaptype = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_TYPE]);
		if (greinfo[IFLA_GRE_ENCAP_FLAGS])
			encapflags = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_FLAGS]);
		if (greinfo[IFLA_GRE_ENCAP_SPORT])
			encapsport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_SPORT]);
		if (greinfo[IFLA_GRE_ENCAP_DPORT])
			encapdport = rta_getattr_u16(greinfo[IFLA_GRE_ENCAP_DPORT]);

		if (greinfo[IFLA_GRE_COLLECT_METADATA])
			metadata = 1;

		if (greinfo[IFLA_GRE_IGNORE_DF])
			ignore_df =
				!!rta_getattr_u8(greinfo[IFLA_GRE_IGNORE_DF]);

		if (greinfo[IFLA_GRE_FWMARK])
			fwmark = rta_getattr_u32(greinfo[IFLA_GRE_FWMARK]);

		if (greinfo[IFLA_GRE_ERSPAN_INDEX])
			erspan_idx = rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
	}

	while (argc > 0) {
		if (!matches(*argv, "key")) {
			unsigned int uval;

			NEXT_ARG();
			iflags |= GRE_KEY;
			oflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0) < 0) {
					fprintf(stderr,
						"Invalid value for \"key\": \"%s\"; it should be an unsigned integer\n", *argv);
					exit(-1);
				}
				uval = htonl(uval);
			}

			ikey = okey = uval;
		} else if (!matches(*argv, "ikey")) {
			unsigned int uval;

			NEXT_ARG();
			iflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0) < 0) {
					fprintf(stderr, "invalid value for \"ikey\": \"%s\"; it should be an unsigned integer\n", *argv);
					exit(-1);
				}
				uval = htonl(uval);
			}
			ikey = uval;
		} else if (!matches(*argv, "okey")) {
			unsigned int uval;

			NEXT_ARG();
			oflags |= GRE_KEY;
			if (strchr(*argv, '.'))
				uval = get_addr32(*argv);
			else {
				if (get_unsigned(&uval, *argv, 0) < 0) {
					fprintf(stderr, "invalid value for \"okey\": \"%s\"; it should be an unsigned integer\n", *argv);
					exit(-1);
				}
				uval = htonl(uval);
			}
			okey = uval;
		} else if (!matches(*argv, "seq")) {
			iflags |= GRE_SEQ;
			oflags |= GRE_SEQ;
		} else if (!matches(*argv, "iseq")) {
			iflags |= GRE_SEQ;
		} else if (!matches(*argv, "oseq")) {
			oflags |= GRE_SEQ;
		} else if (!matches(*argv, "csum")) {
			iflags |= GRE_CSUM;
			oflags |= GRE_CSUM;
		} else if (!matches(*argv, "icsum")) {
			iflags |= GRE_CSUM;
		} else if (!matches(*argv, "ocsum")) {
			oflags |= GRE_CSUM;
		} else if (!matches(*argv, "nopmtudisc")) {
			pmtudisc = 0;
		} else if (!matches(*argv, "pmtudisc")) {
			pmtudisc = 1;
		} else if (!matches(*argv, "remote")) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				daddr = get_addr32(*argv);
		} else if (!matches(*argv, "local")) {
			NEXT_ARG();
			if (strcmp(*argv, "any"))
				saddr = get_addr32(*argv);
		} else if (!matches(*argv, "dev")) {
			NEXT_ARG();
			link = if_nametoindex(*argv);
			if (link == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n",
					*argv);
				exit(-1);
			}
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned int uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL\n", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255\n", *argv);
				ttl = uval;
			}
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "tclass") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else if (strcmp(*argv, "noencap") == 0) {
			encaptype = TUNNEL_ENCAP_NONE;
		} else if (strcmp(*argv, "encap") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "fou") == 0)
				encaptype = TUNNEL_ENCAP_FOU;
			else if (strcmp(*argv, "gue") == 0)
				encaptype = TUNNEL_ENCAP_GUE;
			else if (strcmp(*argv, "none") == 0)
				encaptype = TUNNEL_ENCAP_NONE;
			else
				invarg("Invalid encap type.", *argv);
		} else if (strcmp(*argv, "encap-sport") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "auto") == 0)
				encapsport = 0;
			else if (get_u16(&encapsport, *argv, 0))
				invarg("Invalid source port.", *argv);
		} else if (strcmp(*argv, "encap-dport") == 0) {
			NEXT_ARG();
			if (get_u16(&encapdport, *argv, 0))
				invarg("Invalid destination port.", *argv);
		} else if (strcmp(*argv, "encap-csum") == 0) {
			encapflags |= TUNNEL_ENCAP_FLAG_CSUM;
		} else if (strcmp(*argv, "noencap-csum") == 0) {
			encapflags &= ~TUNNEL_ENCAP_FLAG_CSUM;
		} else if (strcmp(*argv, "encap-udp6-csum") == 0) {
			encapflags |= TUNNEL_ENCAP_FLAG_CSUM6;
		} else if (strcmp(*argv, "noencap-udp6-csum") == 0) {
			encapflags |= ~TUNNEL_ENCAP_FLAG_CSUM6;
		} else if (strcmp(*argv, "encap-remcsum") == 0) {
			encapflags |= TUNNEL_ENCAP_FLAG_REMCSUM;
		} else if (strcmp(*argv, "noencap-remcsum") == 0) {
			encapflags |= ~TUNNEL_ENCAP_FLAG_REMCSUM;
		} else if (strcmp(*argv, "external") == 0) {
			metadata = 1;
		} else if (strcmp(*argv, "ignore-df") == 0) {
			ignore_df = 1;
		} else if (strcmp(*argv, "noignore-df") == 0) {
			/*
			 *only the lsb is significant, use 2 for presence
			 */
			ignore_df = 2;
		} else if (strcmp(*argv, "fwmark") == 0) {
			NEXT_ARG();
			if (get_u32(&fwmark, *argv, 0))
				invarg("invalid fwmark\n", *argv);
		} else if (strcmp(*argv, "erspan") == 0) {
			NEXT_ARG();
			if (get_u32(&erspan_idx, *argv, 0))
				invarg("invalid erspan index\n", *argv);
			if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
				invarg("erspan index must be > 0 and <= 20-bit\n", *argv);
		} else if (!matches(*argv, "keepalive")) {
			__u64 interv;
			__u32 ret;

			NEXT_ARG();
			if (strcmp(*argv, "auto") != 0) {
				if (get_u32(&interv, *argv, 0))
					invarg("invalid KeepAlive time interval\n", *argv);
				keepalive_interv = interv;
			}
			NEXT_ARG();
			if (strcmp(*argv, "auto") != 0) {
				if (get_unsigned(&ret, *argv, 0))
					invarg("invalid KeepAlive retries\n", *argv);
				if (ret > 255)
					invarg("KeepAlive retries must be <= 255\n", *argv);
				keepalive_ret = ret;
			}
		} else
			usage();
		argc--; argv++;
	}

	if (!ikey && IN_MULTICAST(ntohl(daddr))) {
		ikey = daddr;
		iflags |= GRE_KEY;
	}
	if (!okey && IN_MULTICAST(ntohl(daddr))) {
		okey = daddr;
		oflags |= GRE_KEY;
	}
	if (IN_MULTICAST(ntohl(daddr)) && !saddr) {
		fprintf(stderr, "A broadcast tunnel requires a source address.\n");
		return -1;
	}

	if (!metadata) {
		addattr32(n, 1024, IFLA_GRE_IKEY, ikey);
		addattr32(n, 1024, IFLA_GRE_OKEY, okey);
		addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2);
		addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2);
		addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4);
		addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4);
		addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1);
		if (link)
			addattr32(n, 1024, IFLA_GRE_LINK, link);
		addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
		addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
		addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
		if (erspan_idx != 0)
			addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
		if (keepalive_interv) {
			addattr32(n, 1024, IFLA_GRE_KEEPALIVE_INTERVAL,
				  keepalive_interv);
			addattr8(n, 1024, IFLA_GRE_KEEPALIVE_RETRIES,
				 keepalive_ret);
		}
	} else {
		addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
	}

	addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
	addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
	addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
	addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport));

	if (ignore_df)
		addattr8(n, 1024, IFLA_GRE_IGNORE_DF, ignore_df & 1);

	return 0;
}

static void gre_print_direct_opt(FILE *f, struct rtattr *tb[])
{
	char s2[64];
	const char *local = "any";
	const char *remote = "any";
	unsigned int iflags = 0;
	unsigned int oflags = 0;

	if (tb[IFLA_GRE_REMOTE]) {
		unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]);

		if (addr)
			remote = format_host(AF_INET, 4, &addr);
	}

	print_string(PRINT_ANY, "remote", "remote %s ", remote);

	if (tb[IFLA_GRE_LOCAL]) {
		unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_LOCAL]);

		if (addr)
			local = format_host(AF_INET, 4, &addr);
	}

	print_string(PRINT_ANY, "local", "local %s ", local);

	if (tb[IFLA_GRE_LINK] && rta_getattr_u32(tb[IFLA_GRE_LINK])) {
		unsigned int link = rta_getattr_u32(tb[IFLA_GRE_LINK]);
		const char *n = if_indextoname(link, s2);

		if (n)
			print_string(PRINT_ANY, "link", "dev %s ", n);
		else
			print_uint(PRINT_ANY, "link_index", "dev %u ", link);
	}

	if (tb[IFLA_GRE_TTL]) {
		__u8 ttl = rta_getattr_u8(tb[IFLA_GRE_TTL]);

		if (ttl)
			print_int(PRINT_ANY, "ttl", "ttl %d ", ttl);
		else
			print_int(PRINT_JSON, "ttl", NULL, ttl);
	} else {
		print_string(PRINT_FP, NULL, "ttl %s ", "inherit");
	}

	if (tb[IFLA_GRE_TOS] && rta_getattr_u8(tb[IFLA_GRE_TOS])) {
		int tos = rta_getattr_u8(tb[IFLA_GRE_TOS]);

		if (is_json_context()) {
			SPRINT_BUF(b1);

			snprintf(b1, sizeof(b1), "0x%x", tos);
			print_string(PRINT_JSON, "tos", NULL, b1);
		} else {
			fputs("tos ", f);
			if (tos == 1)
				fputs("inherit ", f);
			else
				fprintf(f, "0x%x ", tos);
		}
	}

	if (tb[IFLA_GRE_KEEPALIVE_INTERVAL]) {
		unsigned long interval;
		unsigned int retries;

		interval  = rta_getattr_u64(tb[IFLA_GRE_KEEPALIVE_INTERVAL]);
		retries  = rta_getattr_u8(tb[IFLA_GRE_KEEPALIVE_RETRIES]);

		if (interval) {
			print_int(PRINT_ANY, "keepalive",
				  "keepalive interval %d ",
				  interval);
			print_int(PRINT_ANY, "keepalive",
				  "retries %d ",
				  retries);
		} else {
			print_int(PRINT_JSON, "keepalive", NULL, interval);
		}
	} else {
		print_string(PRINT_FP, NULL, "keepalive %s ", "auto");
	}

	if (tb[IFLA_GRE_PMTUDISC]) {
		if (!rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
			print_bool(PRINT_ANY, "pmtudisc", "nopmtudisc ", false);
		else
			print_bool(PRINT_JSON, "pmtudisc", NULL, true);
	}

	if (tb[IFLA_GRE_IFLAGS])
		iflags = rta_getattr_u16(tb[IFLA_GRE_IFLAGS]);

	if (tb[IFLA_GRE_OFLAGS])
		oflags = rta_getattr_u16(tb[IFLA_GRE_OFLAGS]);

	if ((iflags & GRE_KEY) && tb[IFLA_GRE_IKEY]) {
		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_IKEY]), s2, sizeof(s2));
		print_string(PRINT_ANY, "ikey", "ikey %s ", s2);
	}

	if ((oflags & GRE_KEY) && tb[IFLA_GRE_OKEY]) {
		inet_ntop(AF_INET, RTA_DATA(tb[IFLA_GRE_OKEY]), s2, sizeof(s2));
		print_string(PRINT_ANY, "okey", "okey %s ", s2);
	}

	if (iflags & GRE_SEQ)
		print_bool(PRINT_ANY, "iseq", "iseq ", true);
	if (oflags & GRE_SEQ)
		print_bool(PRINT_ANY, "oseq", "oseq ", true);
	if (iflags & GRE_CSUM)
		print_bool(PRINT_ANY, "icsum", "icsum ", true);
	if (oflags & GRE_CSUM)
		print_bool(PRINT_ANY, "ocsum", "ocsum ", true);

	if (tb[IFLA_GRE_FWMARK]) {
		__u32 fwmark = rta_getattr_u32(tb[IFLA_GRE_FWMARK]);

		if (fwmark) {
			snprintf(s2, sizeof(s2), "0x%x", fwmark);

			print_string(PRINT_ANY, "fwmark", "fwmark %s ", s2);
		}
	}
}
static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
			  struct nlmsghdr *n)
{
	__u32 vni = 0;
	int vni_set = 0;
	__u32 saddr = 0;
	__u32 gaddr = 0;
	__u32 daddr = 0;
	struct in6_addr saddr6 = IN6ADDR_ANY_INIT;
	struct in6_addr gaddr6 = IN6ADDR_ANY_INIT;
	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
	unsigned int link = 0;
	__u8 tos = 0;
	__u8 ttl = 0;
	__u32 label = 0;
	__u8 learning = 1;
	__u8 proxy = 0;
	__u8 rsc = 0;
	__u8 l2miss = 0;
	__u8 l3miss = 0;
	__u8 noage = 0;
	__u32 age = 0;
	__u32 maxaddr = 0;
	__u16 dstport = 0;
	__u8 udpcsum = 0;
	bool udpcsum_set = false;
	__u8 udp6zerocsumtx = 0;
	bool udp6zerocsumtx_set = false;
	__u8 udp6zerocsumrx = 0;
	bool udp6zerocsumrx_set = false;
	__u8 remcsumtx = 0;
	__u8 remcsumrx = 0;
	__u8 metadata = 0;
	__u8 gbp = 0;
	__u8 gpe = 0;
	int dst_port_set = 0;
	struct ifla_vxlan_port_range range = { 0, 0 };

	while (argc > 0) {
		if (!matches(*argv, "id") ||
		    !matches(*argv, "vni")) {
			NEXT_ARG();
			if (get_u32(&vni, *argv, 0) ||
			    vni >= 1u << 24)
				invarg("invalid id", *argv);
			vni_set = 1;
		} else if (!matches(*argv, "group")) {
			NEXT_ARG();
			if (!inet_get_addr(*argv, &gaddr, &gaddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (!IN6_IS_ADDR_MULTICAST(&gaddr6) && !IN_MULTICAST(ntohl(gaddr)))
				invarg("invalid group address", *argv);
		} else if (!matches(*argv, "remote")) {
			NEXT_ARG();
			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
				invarg("invalid remote address", *argv);
		} else if (!matches(*argv, "local")) {
			NEXT_ARG();
			if (strcmp(*argv, "any")) {
				if (!inet_get_addr(*argv, &saddr, &saddr6)) {
					fprintf(stderr, "Invalid address \"%s\"\n", *argv);
					return -1;
				}
			}

			if (IN_MULTICAST(ntohl(saddr)) || IN6_IS_ADDR_MULTICAST(&saddr6))
				invarg("invalid local address", *argv);
		} else if (!matches(*argv, "dev")) {
			NEXT_ARG();
			link = if_nametoindex(*argv);
			if (link == 0) {
				fprintf(stderr, "Cannot find device \"%s\"\n",
					*argv);
				exit(-1);
			}
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned int uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255", *argv);
				ttl = uval;
			}
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else if (!matches(*argv, "label") ||
			   !matches(*argv, "flowlabel")) {
			__u32 uval;

			NEXT_ARG();
			if (get_u32(&uval, *argv, 0) ||
			    (uval & ~LABEL_MAX_MASK))
				invarg("invalid flowlabel", *argv);
			label = htonl(uval);
		} else if (!matches(*argv, "ageing")) {
			NEXT_ARG();
			if (strcmp(*argv, "none") == 0)
				noage = 1;
			else if (get_u32(&age, *argv, 0))
				invarg("ageing timer", *argv);
		} else if (!matches(*argv, "maxaddress")) {
			NEXT_ARG();
			if (strcmp(*argv, "unlimited") == 0)
				maxaddr = 0;
			else if (get_u32(&maxaddr, *argv, 0))
				invarg("max addresses", *argv);
		} else if (!matches(*argv, "port") ||
			   !matches(*argv, "srcport")) {
			NEXT_ARG();
			if (get_be16(&range.low, *argv, 0))
				invarg("min port", *argv);
			NEXT_ARG();
			if (get_be16(&range.high, *argv, 0))
				invarg("max port", *argv);
		} else if (!matches(*argv, "dstport")) {
			NEXT_ARG();
			if (get_u16(&dstport, *argv, 0))
				invarg("dst port", *argv);
			dst_port_set = 1;
		} else if (!matches(*argv, "nolearning")) {
			learning = 0;
		} else if (!matches(*argv, "learning")) {
			learning = 1;
		} else if (!matches(*argv, "noproxy")) {
			proxy = 0;
		} else if (!matches(*argv, "proxy")) {
			proxy = 1;
		} else if (!matches(*argv, "norsc")) {
			rsc = 0;
		} else if (!matches(*argv, "rsc")) {
			rsc = 1;
		} else if (!matches(*argv, "nol2miss")) {
			l2miss = 0;
		} else if (!matches(*argv, "l2miss")) {
			l2miss = 1;
		} else if (!matches(*argv, "nol3miss")) {
			l3miss = 0;
		} else if (!matches(*argv, "l3miss")) {
			l3miss = 1;
		} else if (!matches(*argv, "udpcsum")) {
			udpcsum = 1;
			udpcsum_set = true;
		} else if (!matches(*argv, "noudpcsum")) {
			udpcsum = 0;
			udpcsum_set = true;
		} else if (!matches(*argv, "udp6zerocsumtx")) {
			udp6zerocsumtx = 1;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumtx")) {
			udp6zerocsumtx = 0;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "udp6zerocsumrx")) {
			udp6zerocsumrx = 1;
			udp6zerocsumrx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumrx")) {
			udp6zerocsumrx = 0;
			udp6zerocsumrx_set = true;
		} else if (!matches(*argv, "remcsumtx")) {
			remcsumtx = 1;
		} else if (!matches(*argv, "noremcsumtx")) {
			remcsumtx = 0;
		} else if (!matches(*argv, "remcsumrx")) {
			remcsumrx = 1;
		} else if (!matches(*argv, "noremcsumrx")) {
			remcsumrx = 0;
		} else if (!matches(*argv, "external")) {
			metadata = 1;
			learning = 0;
		} else if (!matches(*argv, "noexternal")) {
			metadata = 0;
		} else if (!matches(*argv, "gbp")) {
			gbp = 1;
		} else if (!matches(*argv, "gpe")) {
			gpe = 1;
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "vxlan: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	if (metadata && vni_set) {
		fprintf(stderr, "vxlan: both 'external' and vni cannot be specified\n");
		return -1;
	}

	if (!metadata && !vni_set) {
		fprintf(stderr, "vxlan: missing virtual network identifier\n");
		return -1;
	}

	if ((gaddr && daddr) ||
	    (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6) &&
	     !IN6_IS_ADDR_UNSPECIFIED(&daddr6))) {
		fprintf(stderr, "vxlan: both group and remote cannot be specified\n");
		return -1;
	}

	if ((gaddr || !IN6_IS_ADDR_UNSPECIFIED(&gaddr6)) && !link) {
		fprintf(stderr, "vxlan: 'group' requires 'dev' to be specified\n");
		return -1;
	}

	if (!dst_port_set && gpe) {
		dstport = 4790;
	} else if (!dst_port_set) {
		fprintf(stderr, "vxlan: destination port not specified\n"
			"Will use Linux kernel default (non-standard value)\n");
		fprintf(stderr,
			"Use 'dstport 4789' to get the IANA assigned value\n"
			"Use 'dstport 0' to get default and quiet this message\n");
	}

	addattr32(n, 1024, IFLA_VXLAN_ID, vni);
	if (gaddr)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &gaddr, 4);
	else if (daddr)
		addattr_l(n, 1024, IFLA_VXLAN_GROUP, &daddr, 4);
	if (!IN6_IS_ADDR_UNSPECIFIED(&gaddr6))
		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &gaddr6, sizeof(struct in6_addr));
	else if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
		addattr_l(n, 1024, IFLA_VXLAN_GROUP6, &daddr6, sizeof(struct in6_addr));

	if (saddr)
		addattr_l(n, 1024, IFLA_VXLAN_LOCAL, &saddr, 4);
	else if (!IN6_IS_ADDR_UNSPECIFIED(&saddr6))
		addattr_l(n, 1024, IFLA_VXLAN_LOCAL6, &saddr6, sizeof(struct in6_addr));

	if (link)
		addattr32(n, 1024, IFLA_VXLAN_LINK, link);
	addattr32(n, 1024, IFLA_VXLAN_LABEL, label);
	addattr8(n, 1024, IFLA_VXLAN_TTL, ttl);
	addattr8(n, 1024, IFLA_VXLAN_TOS, tos);
	addattr8(n, 1024, IFLA_VXLAN_LEARNING, learning);
	addattr8(n, 1024, IFLA_VXLAN_PROXY, proxy);
	addattr8(n, 1024, IFLA_VXLAN_RSC, rsc);
	addattr8(n, 1024, IFLA_VXLAN_L2MISS, l2miss);
	addattr8(n, 1024, IFLA_VXLAN_L3MISS, l3miss);
	addattr8(n, 1024, IFLA_VXLAN_REMCSUM_TX, remcsumtx);
	addattr8(n, 1024, IFLA_VXLAN_REMCSUM_RX, remcsumrx);
	addattr8(n, 1024, IFLA_VXLAN_COLLECT_METADATA, metadata);

	if (udpcsum_set)
		addattr8(n, 1024, IFLA_VXLAN_UDP_CSUM, udpcsum);
	if (udp6zerocsumtx_set)
		addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, udp6zerocsumtx);
	if (udp6zerocsumrx_set)
		addattr8(n, 1024, IFLA_VXLAN_UDP_ZERO_CSUM6_RX, udp6zerocsumrx);
	if (noage)
		addattr32(n, 1024, IFLA_VXLAN_AGEING, 0);
	else if (age)
		addattr32(n, 1024, IFLA_VXLAN_AGEING, age);
	if (maxaddr)
		addattr32(n, 1024, IFLA_VXLAN_LIMIT, maxaddr);
	if (range.low || range.high)
		addattr_l(n, 1024, IFLA_VXLAN_PORT_RANGE,
			  &range, sizeof(range));
	if (dstport)
		addattr16(n, 1024, IFLA_VXLAN_PORT, htons(dstport));

	if (gbp)
		addattr_l(n, 1024, IFLA_VXLAN_GBP, NULL, 0);
	if (gpe)
		addattr_l(n, 1024, IFLA_VXLAN_GPE, NULL, 0);


	return 0;
}
Exemple #12
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;
}
static int geneve_parse_opt(struct link_util *lu, int argc, char **argv,
			  struct nlmsghdr *n)
{
	__u32 vni = 0;
	int vni_set = 0;
	__u32 daddr = 0;
	struct in6_addr daddr6 = IN6ADDR_ANY_INIT;
	__u32 label = 0;
	__u8 ttl = 0;
	__u8 tos = 0;
	__u16 dstport = 0;
	bool metadata = 0;
	__u8 udpcsum = 0;
	bool udpcsum_set = false;
	__u8 udp6zerocsumtx = 0;
	bool udp6zerocsumtx_set = false;
	__u8 udp6zerocsumrx = 0;
	bool udp6zerocsumrx_set = false;

	while (argc > 0) {
		if (!matches(*argv, "id") ||
		    !matches(*argv, "vni")) {
			NEXT_ARG();
			if (get_u32(&vni, *argv, 0) ||
			    vni >= 1u << 24)
				invarg("invalid id", *argv);
			vni_set = 1;
		} else if (!matches(*argv, "remote")) {
			NEXT_ARG();
			if (!inet_get_addr(*argv, &daddr, &daddr6)) {
				fprintf(stderr, "Invalid address \"%s\"\n", *argv);
				return -1;
			}
			if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr)))
				invarg("invalid remote address", *argv);
		} else if (!matches(*argv, "ttl") ||
			   !matches(*argv, "hoplimit")) {
			unsigned int uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (get_unsigned(&uval, *argv, 0))
					invarg("invalid TTL", *argv);
				if (uval > 255)
					invarg("TTL must be <= 255", *argv);
				ttl = uval;
			}
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "dsfield")) {
			__u32 uval;

			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0) {
				if (rtnl_dsfield_a2n(&uval, *argv))
					invarg("bad TOS value", *argv);
				tos = uval;
			} else
				tos = 1;
		} else if (!matches(*argv, "label") ||
			   !matches(*argv, "flowlabel")) {
			__u32 uval;

			NEXT_ARG();
			if (get_u32(&uval, *argv, 0) ||
			    (uval & ~LABEL_MAX_MASK))
				invarg("invalid flowlabel", *argv);
			label = htonl(uval);
		} else if (!matches(*argv, "dstport")) {
			NEXT_ARG();
			if (get_u16(&dstport, *argv, 0))
				invarg("dstport", *argv);
		} else if (!matches(*argv, "external")) {
			metadata = true;
		} else if (!matches(*argv, "noexternal")) {
			metadata = false;
		} else if (!matches(*argv, "udpcsum")) {
			udpcsum = 1;
			udpcsum_set = true;
		} else if (!matches(*argv, "noudpcsum")) {
			udpcsum = 0;
			udpcsum_set = true;
		} else if (!matches(*argv, "udp6zerocsumtx")) {
			udp6zerocsumtx = 1;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumtx")) {
			udp6zerocsumtx = 0;
			udp6zerocsumtx_set = true;
		} else if (!matches(*argv, "udp6zerocsumrx")) {
			udp6zerocsumrx = 1;
			udp6zerocsumrx_set = true;
		} else if (!matches(*argv, "noudp6zerocsumrx")) {
			udp6zerocsumrx = 0;
			udp6zerocsumrx_set = true;
		} else if (matches(*argv, "help") == 0) {
			explain();
			return -1;
		} else {
			fprintf(stderr, "geneve: unknown command \"%s\"?\n", *argv);
			explain();
			return -1;
		}
		argc--, argv++;
	}

	if (metadata && vni_set) {
		fprintf(stderr, "geneve: both 'external' and vni cannot be specified\n");
		return -1;
	}

	if (!metadata) {
		/* parameter checking make sense only for full geneve tunnels */
		if (!vni_set) {
			fprintf(stderr, "geneve: missing virtual network identifier\n");
			return -1;
		}

		if (!daddr && IN6_IS_ADDR_UNSPECIFIED(&daddr6)) {
			fprintf(stderr, "geneve: remote link partner not specified\n");
			return -1;
		}
	}

	addattr32(n, 1024, IFLA_GENEVE_ID, vni);
	if (daddr)
		addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4);
	if (!IN6_IS_ADDR_UNSPECIFIED(&daddr6))
		addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr));
	addattr32(n, 1024, IFLA_GENEVE_LABEL, label);
	addattr8(n, 1024, IFLA_GENEVE_TTL, ttl);
	addattr8(n, 1024, IFLA_GENEVE_TOS, tos);
	if (dstport)
		addattr16(n, 1024, IFLA_GENEVE_PORT, htons(dstport));
	if (metadata)
		addattr(n, 1024, IFLA_GENEVE_COLLECT_METADATA);
	if (udpcsum_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_CSUM, udpcsum);
	if (udp6zerocsumtx_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, udp6zerocsumtx);
	if (udp6zerocsumrx_set)
		addattr8(n, 1024, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, udp6zerocsumrx);

	return 0;
}
Exemple #14
0
static int ila_parse_opt(int argc, char **argv, struct nlmsghdr *n,
			 bool adding)
{
	__u64 locator = 0;
	__u64 locator_match = 0;
	int ifindex = 0;
	int csum_mode = 0;
	int ident_type = 0;
	bool loc_set = false;
	bool loc_match_set = false;
	bool ifindex_set = false;
	bool csum_mode_set = false;
	bool ident_type_set = false;

	while (argc > 0) {
		if (!matches(*argv, "loc")) {
			NEXT_ARG();

			if (get_addr64(&locator, *argv) < 0) {
				fprintf(stderr, "Bad locator: %s\n", *argv);
				return -1;
			}
			loc_set = true;
		} else if (!matches(*argv, "loc_match")) {
			NEXT_ARG();

			if (get_addr64(&locator_match, *argv) < 0) {
				fprintf(stderr, "Bad locator to match: %s\n",
					*argv);
				return -1;
			}
			loc_match_set = true;
		} else if (!matches(*argv, "csum-mode")) {
			NEXT_ARG();

			csum_mode = ila_csum_name2mode(*argv);
			if (csum_mode < 0) {
				fprintf(stderr, "Bad csum-mode: %s\n",
					*argv);
				return -1;
			}
			csum_mode_set = true;
		} else if (!matches(*argv, "ident-type")) {
			NEXT_ARG();

			ident_type = ila_ident_name2type(*argv);
			if (ident_type < 0) {
				fprintf(stderr, "Bad ident-type: %s\n",
					*argv);
				return -1;
			}
			ident_type_set = true;
		} else if (!matches(*argv, "dev")) {
			NEXT_ARG();

			ifindex = ll_name_to_index(*argv);
			if (ifindex == 0) {
				fprintf(stderr, "No such interface: %s\n",
					*argv);
				return -1;
			}
			ifindex_set = true;
		} else {
			usage();
			return -1;
		}
		argc--, argv++;
	}

	if (adding) {
		if (!loc_set) {
			fprintf(stderr, "ila: missing locator\n");
			return -1;
		}
		if (!loc_match_set) {
			fprintf(stderr, "ila: missing locator0match\n");
			return -1;
		}
	}

	if (loc_match_set)
		addattr64(n, 1024, ILA_ATTR_LOCATOR_MATCH, locator_match);

	if (loc_set)
		addattr64(n, 1024, ILA_ATTR_LOCATOR, locator);

	if (ifindex_set)
		addattr32(n, 1024, ILA_ATTR_IFINDEX, ifindex);

	if (csum_mode_set)
		addattr8(n, 1024, ILA_ATTR_CSUM_MODE, csum_mode);

	if (ident_type_set)
		addattr8(n, 1024, ILA_ATTR_IDENT_TYPE, ident_type);

	return 0;
}
Exemple #15
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;
	__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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			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);
				return -1;
			}
			ad_select = get_index(ad_select_tbl, *argv);
			addattr8(n, 1024, IFLA_BOND_AD_SELECT, ad_select);
		} 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;
}
Exemple #16
0
static int seg6_do_cmd(void)
{
	SEG6_REQUEST(req, 1024, opts.cmd, NLM_F_REQUEST);
	int repl = 0, dump = 0;

	if (genl_family < 0) {
		if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
			fprintf(stderr, "Cannot open generic netlink socket\n");
			exit(1);
		}
		genl_family = genl_resolve_family(&grth, SEG6_GENL_NAME);
		if (genl_family < 0)
			exit(1);
		req.n.nlmsg_type = genl_family;
	}

	switch (opts.cmd) {
	case SEG6_CMD_SETHMAC:
	{
		addattr32(&req.n, sizeof(req), SEG6_ATTR_HMACKEYID, opts.keyid);
		addattr8(&req.n, sizeof(req), SEG6_ATTR_SECRETLEN,
			 strlen(opts.pass));
		addattr8(&req.n, sizeof(req), SEG6_ATTR_ALGID, opts.alg_id);
		if (strlen(opts.pass))
			addattr_l(&req.n, sizeof(req), SEG6_ATTR_SECRET,
				  opts.pass, strlen(opts.pass));
		break;
	}
	case SEG6_CMD_SET_TUNSRC:
		addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr,
			  sizeof(struct in6_addr));
		break;
	case SEG6_CMD_DUMPHMAC:
		dump = 1;
		break;
	case SEG6_CMD_GET_TUNSRC:
		repl = 1;
		break;
	}

	if (!repl && !dump) {
		if (rtnl_talk(&grth, &req.n, NULL, 0) < 0)
			return -1;
	} else if (repl) {
		if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0)
			return -2;
		if (process_msg(NULL, &req.n, stdout) < 0) {
			fprintf(stderr, "Error parsing reply\n");
			exit(1);
		}
	} else {
		req.n.nlmsg_flags |= NLM_F_DUMP;
		req.n.nlmsg_seq = grth.dump = ++grth.seq;
		if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
			perror("Failed to send dump request");
			exit(1);
		}

		if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
			fprintf(stderr, "Dump terminated\n");
			exit(1);
		}
	}

	return 0;
}