예제 #1
0
static int dsmark_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
	struct rtattr *tb[TCA_DSMARK_MAX+1];

	if (!opt) return 0;
	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, TCA_DSMARK_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt));
	if (tb[TCA_DSMARK_MASK]) {
		if (!RTA_PAYLOAD(tb[TCA_DSMARK_MASK]))
			fprintf(stderr,"dsmark: empty mask\n");
		else fprintf(f,"mask 0x%02x ",
			    rta_getattr_u8(tb[TCA_DSMARK_MASK]));
	}
	if (tb[TCA_DSMARK_VALUE]) {
		if (!RTA_PAYLOAD(tb[TCA_DSMARK_VALUE]))
			fprintf(stderr,"dsmark: empty value\n");
		else fprintf(f,"value 0x%02x ",
			    rta_getattr_u8(tb[TCA_DSMARK_VALUE]));
	}
	if (tb[TCA_DSMARK_INDICES]) {
		if (RTA_PAYLOAD(tb[TCA_DSMARK_INDICES]) < sizeof(__u16))
			fprintf(stderr,"dsmark: indices too short\n");
		else fprintf(f,"indices 0x%04x ",
			    rta_getattr_u16(tb[TCA_DSMARK_INDICES]));
	}
	if (tb[TCA_DSMARK_DEFAULT_INDEX]) {
		if (RTA_PAYLOAD(tb[TCA_DSMARK_DEFAULT_INDEX]) < sizeof(__u16))
			fprintf(stderr,"dsmark: default_index too short\n");
		else fprintf(f,"default_index 0x%04x ",
			    rta_getattr_u16(tb[TCA_DSMARK_DEFAULT_INDEX]));
	}
	if (tb[TCA_DSMARK_SET_TC_INDEX]) fprintf(f,"set_tc_index ");
	return 0;
}
예제 #2
0
static void ipoib_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	__u16 mode;

	if (!tb)
		return;

	if (!tb[IFLA_IPOIB_PKEY] ||
	    RTA_PAYLOAD(tb[IFLA_IPOIB_PKEY]) < sizeof(__u16))
		return;

	fprintf(f, "pkey  %#.4x ", rta_getattr_u16(tb[IFLA_IPOIB_PKEY]));

	if (!tb[IFLA_IPOIB_MODE] ||
	    RTA_PAYLOAD(tb[IFLA_IPOIB_MODE]) < sizeof(__u16))
		return;

	mode = rta_getattr_u16(tb[IFLA_IPOIB_MODE]);
	fprintf(f, "mode  %s ",
		mode == IPOIB_MODE_DATAGRAM ? "datagram" :
		mode == IPOIB_MODE_CONNECTED ? "connected" :
		"unknown");

	if (!tb[IFLA_IPOIB_UMCAST] ||
	    RTA_PAYLOAD(tb[IFLA_IPOIB_UMCAST]) < sizeof(__u16))
		return;

	fprintf(f, "umcast  %.4x ", rta_getattr_u16(tb[IFLA_IPOIB_UMCAST]));
}
예제 #3
0
파일: m_pedit.c 프로젝트: eworm-de/iproute2
static int pedit_keys_ex_getattr(struct rtattr *attr,
				 struct m_pedit_key_ex *keys_ex, int n)
{
	struct rtattr *i;
	int rem = RTA_PAYLOAD(attr);
	struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
	struct m_pedit_key_ex *k = keys_ex;

	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
		if (!n)
			return -1;

		if (i->rta_type != TCA_PEDIT_KEY_EX)
			return -1;

		parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i);

		k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
		k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]);

		k++;
		n--;
	}

	return !!n;
}
예제 #4
0
static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{

	if (!tb)
		return;

	if (tb[IFLA_IPVLAN_MODE]) {
		if (RTA_PAYLOAD(tb[IFLA_IPVLAN_MODE]) == sizeof(__u16)) {
			__u16 mode = rta_getattr_u16(tb[IFLA_IPVLAN_MODE]);
			const char *mode_str = mode == IPVLAN_MODE_L2 ? "l2" :
				mode == IPVLAN_MODE_L3 ? "l3" :
				mode == IPVLAN_MODE_L3S ? "l3s" : "unknown";

			print_string(PRINT_ANY, "mode", " mode %s ", mode_str);
		}
	}
	if (tb[IFLA_IPVLAN_FLAGS]) {
		if (RTA_PAYLOAD(tb[IFLA_IPVLAN_FLAGS]) == sizeof(__u16)) {
			__u16 flags = rta_getattr_u16(tb[IFLA_IPVLAN_FLAGS]);

			if (flags & IPVLAN_F_PRIVATE)
				print_bool(PRINT_ANY, "private", "private ",
					   true);
			else if (flags & IPVLAN_F_VEPA)
				print_bool(PRINT_ANY, "vepa", "vepa ",
					   true);
			else
				print_bool(PRINT_ANY, "bridge", "bridge ",
					   true);
		}
	}
}
예제 #5
0
static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	struct ifla_vlan_flags *flags;
	SPRINT_BUF(b1);

	if (!tb)
		return;

	if (tb[IFLA_VLAN_PROTOCOL] &&
	    RTA_PAYLOAD(tb[IFLA_VLAN_PROTOCOL]) < sizeof(__u16))
		return;
	if (!tb[IFLA_VLAN_ID] ||
	    RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
		return;

	if (tb[IFLA_VLAN_PROTOCOL])
		fprintf(f, "protocol %s ",
			ll_proto_n2a(rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
				     b1, sizeof(b1)));
	else
		fprintf(f, "protocol 802.1q ");

	fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));

	if (tb[IFLA_VLAN_FLAGS]) {
		if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
			return;
		flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
		vlan_print_flags(f, flags->flags);
	}
	if (tb[IFLA_VLAN_INGRESS_QOS])
		vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
	if (tb[IFLA_VLAN_EGRESS_QOS])
		vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
}
static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	SPRINT_BUF(b1);
	if (!tb)
		return;

	if (tb[IFLA_BOND_SLAVE_STATE])
		print_slave_state(f, tb[IFLA_BOND_SLAVE_STATE]);

	if (tb[IFLA_BOND_SLAVE_MII_STATUS])
		print_slave_mii_status(f, tb[IFLA_BOND_SLAVE_MII_STATUS]);

	if (tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT])
		fprintf(f, "link_failure_count %d ",
			rta_getattr_u32(tb[IFLA_BOND_SLAVE_LINK_FAILURE_COUNT]));

	if (tb[IFLA_BOND_SLAVE_PERM_HWADDR])
		fprintf(f, "perm_hwaddr %s ",
			ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
				    RTA_PAYLOAD(tb[IFLA_BOND_SLAVE_PERM_HWADDR]),
				    0, b1, sizeof(b1)));

	if (tb[IFLA_BOND_SLAVE_QUEUE_ID])
		fprintf(f, "queue_id %d ",
			rta_getattr_u16(tb[IFLA_BOND_SLAVE_QUEUE_ID]));

	if (tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID])
		fprintf(f, "ad_aggregator_id %d ",
			rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID]));
}
예제 #7
0
파일: f_tcindex.c 프로젝트: idosch/iproute2
static int tcindex_print_opt(struct filter_util *qu, FILE *f,
     struct rtattr *opt, __u32 handle)
{
	struct rtattr *tb[TCA_TCINDEX_MAX+1];

	if (opt == NULL)
		return 0;

	parse_rtattr_nested(tb, TCA_TCINDEX_MAX, opt);

	if (handle != ~0) fprintf(f, "handle 0x%04x ", handle);
	if (tb[TCA_TCINDEX_HASH]) {
		__u16 hash;

		if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH]) < sizeof(hash))
			return -1;
		hash = rta_getattr_u16(tb[TCA_TCINDEX_HASH]);
		fprintf(f, "hash %d ", hash);
	}
	if (tb[TCA_TCINDEX_MASK]) {
		__u16 mask;

		if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK]) < sizeof(mask))
			return -1;
		mask = rta_getattr_u16(tb[TCA_TCINDEX_MASK]);
		fprintf(f, "mask 0x%04x ", mask);
	}
	if (tb[TCA_TCINDEX_SHIFT]) {
		int shift;

		if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT]) < sizeof(shift))
			return -1;
		shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT]);
		fprintf(f, "shift %d ", shift);
	}
	if (tb[TCA_TCINDEX_FALL_THROUGH]) {
		int fall_through;

		if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH]) <
		    sizeof(fall_through))
			return -1;
		fall_through = *(int *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH]);
		fprintf(f, fall_through ? "fall_through " : "pass_on ");
	}
	if (tb[TCA_TCINDEX_CLASSID]) {
		SPRINT_BUF(b1);
		fprintf(f, "classid %s ", sprint_tc_classid(*(__u32 *)
		    RTA_DATA(tb[TCA_TCINDEX_CLASSID]), b1));
	}
	if (tb[TCA_TCINDEX_POLICE]) {
		fprintf(f, "\n");
		tc_print_police(f, tb[TCA_TCINDEX_POLICE]);
	}
	if (tb[TCA_TCINDEX_ACT]) {
		fprintf(f, "\n");
		tc_print_police(f, tb[TCA_TCINDEX_ACT]);
	}
	return 0;
}
예제 #8
0
파일: libgenl.c 프로젝트: dtaht/tc-adv
static int genl_parse_getfamily(struct nlmsghdr *nlh)
{
	struct rtattr *tb[CTRL_ATTR_MAX + 1];
	struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
	int len = nlh->nlmsg_len;
	struct rtattr *attrs;

	if (nlh->nlmsg_type != GENL_ID_CTRL) {
		fprintf(stderr, "Not a controller message, nlmsg_len=%d "
			"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
		return -1;
	}

	len -= NLMSG_LENGTH(GENL_HDRLEN);

	if (len < 0) {
		fprintf(stderr, "wrong controller message len %d\n", len);
		return -1;
	}

	if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
		fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
		return -1;
	}

	attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
	parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);

	if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
		fprintf(stderr, "Missing family id TLV\n");
		return -1;
	}

	return rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
}
void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
			  struct rtattr *encap)
{
	int et;

	if (!encap_type)
		return;

	et = rta_getattr_u16(encap_type);

	fprintf(fp, " encap %s ", format_encap_type(et));

	switch (et) {
	case LWTUNNEL_ENCAP_MPLS:
		print_encap_mpls(fp, encap);
		break;
	case LWTUNNEL_ENCAP_IP:
		print_encap_ip(fp, encap);
		break;
	case LWTUNNEL_ENCAP_ILA:
		print_encap_ila(fp, encap);
		break;
	case LWTUNNEL_ENCAP_IP6:
		print_encap_ip6(fp, encap);
		break;
	}
}
예제 #10
0
static void macvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	__u32 mode;
	__u16 flags;

	if (!tb)
		return;

	if (!tb[IFLA_MACVLAN_MODE] ||
	    RTA_PAYLOAD(tb[IFLA_MACVLAN_MODE]) < sizeof(__u32))
		return;

	mode = rta_getattr_u32(tb[IFLA_MACVLAN_MODE]);
	fprintf(f, " mode %s ",
		  mode == MACVLAN_MODE_PRIVATE ? "private"
		: mode == MACVLAN_MODE_VEPA    ? "vepa"
		: mode == MACVLAN_MODE_BRIDGE  ? "bridge"
		: mode == MACVLAN_MODE_PASSTHRU  ? "passthru"
		:				 "unknown");

	if (!tb[IFLA_MACVLAN_FLAGS] ||
	    RTA_PAYLOAD(tb[IFLA_MACVLAN_FLAGS]) < sizeof(__u16))
		return;

	flags = rta_getattr_u16(tb[IFLA_MACVLAN_FLAGS]);
	if (flags & MACVLAN_FLAG_NOPROMISC)
		fprintf(f, "nopromisc ");
}
예제 #11
0
static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	if (!tb)
		return;

	if (tb[IFLA_BR_FORWARD_DELAY])
		fprintf(f, "forward_delay %u ",
			rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));

	if (tb[IFLA_BR_HELLO_TIME])
		fprintf(f, "hello_time %u ",
			rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));

	if (tb[IFLA_BR_MAX_AGE])
		fprintf(f, "max_age %u ",
			rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));

	if (tb[IFLA_BR_AGEING_TIME])
		fprintf(f, "ageing_time %u ",
			rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));

	if (tb[IFLA_BR_STP_STATE])
		fprintf(f, "stp_state %u ",
			rta_getattr_u32(tb[IFLA_BR_STP_STATE]));

	if (tb[IFLA_BR_PRIORITY])
		fprintf(f, "priority %u ",
			rta_getattr_u16(tb[IFLA_BR_PRIORITY]));

	if (tb[IFLA_BR_VLAN_FILTERING])
		fprintf(f, "vlan_filtering %u ",
			rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));

	if (tb[IFLA_BR_VLAN_PROTOCOL]) {
		SPRINT_BUF(b1);

		fprintf(f, "vlan_protocol %s ",
			ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
				     b1, sizeof(b1)));
	}
}
예제 #12
0
static uint16_t get_vlan_id(struct rtattr *linkinfo[])
{
	struct rtattr *vlaninfo[IFLA_VLAN_MAX + 1];
	if (!linkinfo[IFLA_INFO_DATA])
		return 0;
	parse_rtattr_nested(vlaninfo, IFLA_VLAN_MAX, linkinfo[IFLA_INFO_DATA]);
	if (vlaninfo[IFLA_VLAN_PROTOCOL]
		&& RTA_PAYLOAD(vlaninfo[IFLA_VLAN_PROTOCOL]) < sizeof(__u16))
		return 0;
	if (!vlaninfo[IFLA_VLAN_ID] ||
		RTA_PAYLOAD(vlaninfo[IFLA_VLAN_ID]) < sizeof(__u16))
		return 0;
#if 0
	if (vlaninfo[IFLA_VLAN_PROTOCOL])
		fprintf(stderr, "protocol id %d ",
				rta_getattr_u16(vlaninfo[IFLA_VLAN_PROTOCOL]));
	else
		fprintf(stderr, "protocol 802.1q ");
#endif
	return rta_getattr_u16(vlaninfo[IFLA_VLAN_ID]);
}
예제 #13
0
파일: iplink_hsr.c 프로젝트: 6WIND/iproute2
static void hsr_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	SPRINT_BUF(b1);

	if (!tb)
		return;

	if (tb[IFLA_HSR_SLAVE1] &&
	    RTA_PAYLOAD(tb[IFLA_HSR_SLAVE1]) < sizeof(__u32))
		return;
	if (tb[IFLA_HSR_SLAVE2] &&
	    RTA_PAYLOAD(tb[IFLA_HSR_SLAVE2]) < sizeof(__u32))
		return;
	if (tb[IFLA_HSR_SEQ_NR] &&
	    RTA_PAYLOAD(tb[IFLA_HSR_SEQ_NR]) < sizeof(__u16))
		return;
	if (tb[IFLA_HSR_SUPERVISION_ADDR] &&
	    RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]) < ETH_ALEN)
		return;

	if (tb[IFLA_HSR_SLAVE1])
		print_string(PRINT_ANY,
			     "slave1",
			     "slave1 %s ",
			     ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE1])));
	else
		print_null(PRINT_ANY, "slave1", "slave1 %s ", "<none>");

	if (tb[IFLA_HSR_SLAVE2])
		print_string(PRINT_ANY,
			     "slave2",
			     "slave2 %s ",
			     ll_index_to_name(rta_getattr_u32(tb[IFLA_HSR_SLAVE2])));
	else
		print_null(PRINT_ANY, "slave2", "slave2 %s ", "<none>");

	if (tb[IFLA_HSR_SEQ_NR])
		print_int(PRINT_ANY,
			  "seq_nr",
			  "sequence %d ",
			  rta_getattr_u16(tb[IFLA_HSR_SEQ_NR]));

	if (tb[IFLA_HSR_SUPERVISION_ADDR])
		print_string(PRINT_ANY,
			     "supervision_addr",
			     "supervision %s ",
			     ll_addr_n2a(RTA_DATA(tb[IFLA_HSR_SUPERVISION_ADDR]),
					 RTA_PAYLOAD(tb[IFLA_HSR_SUPERVISION_ADDR]),
					 ARPHRD_VOID,
					 b1, sizeof(b1)));
}
예제 #14
0
static void ipvlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{

	if (!tb)
		return;

	if (tb[IFLA_IPVLAN_MODE]) {
		if (RTA_PAYLOAD(tb[IFLA_IPVLAN_MODE]) == sizeof(__u16)) {
			__u16 mode = rta_getattr_u16(tb[IFLA_IPVLAN_MODE]);

			fprintf(f, " mode %s ",
				mode == IPVLAN_MODE_L2 ? "l2" :
				mode == IPVLAN_MODE_L3 ? "l3" : "unknown");
		}
	}
}
예제 #15
0
static int bpf_print_opt(struct action_util *au, FILE *f, struct rtattr *arg)
{
	struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
	struct tc_act_bpf *parm;

	SPRINT_BUF(action_buf);

	if (arg == NULL)
		return -1;

	parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);

	if (!tb[TCA_ACT_BPF_PARMS]) {
		fprintf(f, "[NULL bpf parameters]");
		return -1;
	}

	parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);
	fprintf(f, "bpf ");

	if (tb[TCA_ACT_BPF_NAME])
		fprintf(f, "%s ", rta_getattr_str(tb[TCA_ACT_BPF_NAME]));
	else if (tb[TCA_ACT_BPF_FD])
		fprintf(f, "pfd %u ", rta_getattr_u32(tb[TCA_ACT_BPF_FD]));

	if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN]) {
		bpf_print_ops(f, tb[TCA_ACT_BPF_OPS],
			      rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));
		fprintf(f, " ");
	}

	fprintf(f, "default-action %s\n", action_n2a(parm->action, action_buf,
		sizeof(action_buf)));
	fprintf(f, "\tindex %d ref %d bind %d", parm->index, parm->refcnt,
		parm->bindcnt);

	if (show_stats) {
		if (tb[TCA_ACT_BPF_TM]) {
			struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);

			print_tm(f, tm);
		}
	}

	fprintf(f, "\n ");
	return 0;
}
예제 #16
0
파일: ipmacsec.c 프로젝트: dtaht/tc-adv
static __u64 getattr_u64(struct rtattr *stat)
{
	switch (RTA_PAYLOAD(stat)) {
	case sizeof(__u64):
		return rta_getattr_u64(stat);
	case sizeof(__u32):
		return rta_getattr_u32(stat);
	case sizeof(__u16):
		return rta_getattr_u16(stat);
	case sizeof(__u8):
		return rta_getattr_u8(stat);
	default:
		fprintf(stderr, "invalid attribute length %lu\n",
			RTA_PAYLOAD(stat));
		exit(-1);
	}
}
예제 #17
0
static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	struct ifla_vlan_flags *flags;
	if (!tb)
		return;

	if (!tb[IFLA_VLAN_ID] ||
	    RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
		return;

	fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));

	if (tb[IFLA_VLAN_FLAGS]) {
		if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
			return;
		flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
		vlan_print_flags(f, flags->flags);
	}
	if (tb[IFLA_VLAN_INGRESS_QOS])
		vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
	if (tb[IFLA_VLAN_EGRESS_QOS])
		vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
}
예제 #18
0
static int print_bpf(struct action_util *au, FILE *f, struct rtattr *arg)
{
	struct rtattr *tb[TCA_ACT_BPF_MAX + 1];
	struct tc_act_bpf *parm;

	if (arg == NULL)
		return -1;

	parse_rtattr_nested(tb, TCA_ACT_BPF_MAX, arg);

	if (!tb[TCA_ACT_BPF_PARMS]) {
		fprintf(f, "[NULL bpf parameters]");
		return -1;
	}
	parm = RTA_DATA(tb[TCA_ACT_BPF_PARMS]);

	fprintf(f, " bpf ");

	if (tb[TCA_ACT_BPF_OPS] && tb[TCA_ACT_BPF_OPS_LEN])
		bpf_print_ops(f, tb[TCA_ACT_BPF_OPS],
			      rta_getattr_u16(tb[TCA_ACT_BPF_OPS_LEN]));

	fprintf(f, "\n\tindex %d ref %d bind %d", parm->index, parm->refcnt,
		parm->bindcnt);

	if (show_stats) {
		if (tb[TCA_ACT_BPF_TM]) {
			struct tcf_t *tm = RTA_DATA(tb[TCA_ACT_BPF_TM]);
			print_tm(f, tm);
		}
	}

	fprintf(f, "\n ");

	return 0;
}
예제 #19
0
파일: link_gre6.c 프로젝트: AllardJ/Tomato
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
			 struct nlmsghdr *n)
{
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
		char buf[1024];
	} req;
	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
	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 ikey = 0;
	unsigned okey = 0;
	struct in6_addr raddr = IN6ADDR_ANY_INIT;
	struct in6_addr laddr = IN6ADDR_ANY_INIT;
	unsigned link = 0;
	unsigned flowinfo = 0;
	unsigned flags = 0;
	__u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
	__u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
	int len;

	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(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])
			memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));

		if (greinfo[IFLA_GRE_REMOTE])
			memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));

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

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

		if (greinfo[IFLA_GRE_ENCAP_LIMIT])
			encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]);

		if (greinfo[IFLA_GRE_FLOWINFO])
			flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]);

		if (greinfo[IFLA_GRE_FLAGS])
			flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]);
	}

	while (argc > 0) {
		if (!matches(*argv, "key")) {
			unsigned 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\"\n");
					exit(-1);
				}
				uval = htonl(uval);
			}

			ikey = okey = uval;
		} else if (!matches(*argv, "ikey")) {
			unsigned 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 of \"ikey\"\n");
					exit(-1);
				}
				uval = htonl(uval);
			}
			ikey = uval;
		} else if (!matches(*argv, "okey")) {
			unsigned 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 of \"okey\"\n");
					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, "remote")) {
			inet_prefix addr;
			NEXT_ARG();
			get_prefix(&addr, *argv, preferred_family);
			if (addr.family == AF_UNSPEC)
				invarg("\"remote\" address family is AF_UNSPEC", *argv);
			memcpy(&raddr, &addr.data, sizeof(raddr));
		} else if (!matches(*argv, "local")) {
			inet_prefix addr;
			NEXT_ARG();
			get_prefix(&addr, *argv, preferred_family);
			if (addr.family == AF_UNSPEC)
				invarg("\"local\" address family is AF_UNSPEC", *argv);
			memcpy(&laddr, &addr.data, sizeof(laddr));
		} 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")) {
			__u8 uval;
			NEXT_ARG();
			if (get_u8(&uval, *argv, 0))
				invarg("invalid TTL", *argv);
			hop_limit = uval;
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "tclass") ||
			   !matches(*argv, "dsfield")) {
			__u8 uval;
			NEXT_ARG();
			if (strcmp(*argv, "inherit") == 0)
				flags |= IP6_TNL_F_USE_ORIG_TCLASS;
			else {
				if (get_u8(&uval, *argv, 16))
					invarg("invalid TClass", *argv);
				flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
				flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
			}
		} else if (strcmp(*argv, "flowlabel") == 0 ||
			   strcmp(*argv, "fl") == 0) {
			__u32 uval;
			NEXT_ARG();
			if (strcmp(*argv, "inherit") == 0)
				flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
			else {
				if (get_u32(&uval, *argv, 16))
					invarg("invalid Flowlabel", *argv);
				if (uval > 0xFFFFF)
					invarg("invalid Flowlabel", *argv);
				flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
				flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
			}
		} else if (strcmp(*argv, "dscp") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0)
				invarg("not inherit", *argv);
			flags |= IP6_TNL_F_RCV_DSCP_COPY;
		} else
			usage();
		argc--; argv++;
	}

	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, &laddr, sizeof(laddr));
	addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
	if (link)
		addattr32(n, 1024, IFLA_GRE_LINK, link);
	addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
	addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
	addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
	addattr_l(n, 1024, IFLA_GRE_FLAGS, &flowinfo, 4);

	return 0;
}
예제 #20
0
파일: link_gre6.c 프로젝트: AllardJ/Tomato
static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	char s1[1024];
	char s2[64];
	const char *local = "any";
	const char *remote = "any";
	unsigned iflags = 0;
	unsigned oflags = 0;
	unsigned flags = 0;
	unsigned flowinfo = 0;
	struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;

	if (!tb)
		return;

	if (tb[IFLA_GRE_FLAGS])
		flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);

	if (tb[IFLA_GRE_FLOWINFO])
		flags = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]);

	if (tb[IFLA_GRE_REMOTE]) {
		struct in6_addr addr;
		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr));

		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
			remote = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
	}

	fprintf(f, "remote %s ", remote);

	if (tb[IFLA_GRE_LOCAL]) {
		struct in6_addr addr;
		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr));

		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
			local = format_host(AF_INET6, sizeof(addr), &addr, s1, sizeof(s1));
	}

	fprintf(f, "local %s ", local);

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

		if (n)
			fprintf(f, "dev %s ", n);
		else
			fprintf(f, "dev %u ", link);
	}

	if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
		fprintf(f, "hoplimit %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));

	if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
		fprintf(f, "encaplimit none ");
	else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
		int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);

		fprintf(f, "encaplimit %d ", encap_limit);
	}

	if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
		fprintf(f, "flowlabel inherit ");
	else
		fprintf(f, "flowlabel 0x%05x ", ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));

	if (flags & IP6_TNL_F_RCV_DSCP_COPY)
		fprintf(f, "dscp inherit ");

	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));
		fprintf(f, "ikey %s ", s2);
	}

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

	if (iflags & GRE_SEQ)
		fputs("iseq ", f);
	if (oflags & GRE_SEQ)
		fputs("oseq ", f);
	if (iflags & GRE_CSUM)
		fputs("icsum ", f);
	if (oflags & GRE_CSUM)
		fputs("ocsum ", f);
}
예제 #21
0
파일: ipl2tp.c 프로젝트: AllardJ/Tomato
static int get_response(struct nlmsghdr *n, void *arg)
{
	struct genlmsghdr *ghdr;
	struct l2tp_data *data = arg;
	struct l2tp_parm *p = &data->config;
	struct rtattr *attrs[L2TP_ATTR_MAX + 1];
	struct rtattr *nla_stats;
	int len;

	/* Validate message and parse attributes */
	if (n->nlmsg_type == NLMSG_ERROR)
		return -EBADMSG;

	ghdr = NLMSG_DATA(n);
	len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
	if (len < 0)
		return -1;

	parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);

	if (attrs[L2TP_ATTR_PW_TYPE])
		p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
	if (attrs[L2TP_ATTR_ENCAP_TYPE])
		p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
	if (attrs[L2TP_ATTR_OFFSET])
		p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]);
	if (attrs[L2TP_ATTR_DATA_SEQ])
		p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]);
	if (attrs[L2TP_ATTR_CONN_ID])
		p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
	if (attrs[L2TP_ATTR_PEER_CONN_ID])
		p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
	if (attrs[L2TP_ATTR_SESSION_ID])
		p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
	if (attrs[L2TP_ATTR_PEER_SESSION_ID])
		p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
	if (attrs[L2TP_ATTR_L2SPEC_TYPE])
		p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
	if (attrs[L2TP_ATTR_L2SPEC_LEN])
		p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);

	p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
	if (attrs[L2TP_ATTR_COOKIE])
		memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
		       p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));

	if (attrs[L2TP_ATTR_PEER_COOKIE])
		memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
		       p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));

	p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ];
	p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ];

	if (attrs[L2TP_ATTR_RECV_TIMEOUT])
		p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
	if (attrs[L2TP_ATTR_IP_SADDR]) {
		p->local_ip.family = AF_INET;
		p->local_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]);
		p->local_ip.bytelen = 4;
		p->local_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP_DADDR]) {
		p->peer_ip.family = AF_INET;
		p->peer_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]);
		p->peer_ip.bytelen = 4;
		p->peer_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP6_SADDR]) {
		p->local_ip.family = AF_INET6;
		memcpy(&p->local_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_SADDR]),
			p->local_ip.bytelen = 16);
		p->local_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_IP6_DADDR]) {
		p->peer_ip.family = AF_INET6;
		memcpy(&p->peer_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_DADDR]),
			p->peer_ip.bytelen = 16);
		p->peer_ip.bitlen = -1;
	}
	if (attrs[L2TP_ATTR_UDP_SPORT])
		p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
	if (attrs[L2TP_ATTR_UDP_DPORT])
		p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
	if (attrs[L2TP_ATTR_MTU])
		p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]);
	if (attrs[L2TP_ATTR_IFNAME])
		p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);

	nla_stats = attrs[L2TP_ATTR_STATS];
	if (nla_stats) {
		struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];

		parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);

		if (tb[L2TP_ATTR_TX_PACKETS])
			data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
		if (tb[L2TP_ATTR_TX_BYTES])
			data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
		if (tb[L2TP_ATTR_TX_ERRORS])
			data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
		if (tb[L2TP_ATTR_RX_PACKETS])
			data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
		if (tb[L2TP_ATTR_RX_BYTES])
			data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
		if (tb[L2TP_ATTR_RX_ERRORS])
			data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
		if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
			data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
		if (tb[L2TP_ATTR_RX_OOS_PACKETS])
			data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
	}

	return 0;
}
예제 #22
0
static void bridge_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	if (!tb)
		return;

	if (tb[IFLA_BR_FORWARD_DELAY])
		fprintf(f, "forward_delay %u ",
			rta_getattr_u32(tb[IFLA_BR_FORWARD_DELAY]));

	if (tb[IFLA_BR_HELLO_TIME])
		fprintf(f, "hello_time %u ",
			rta_getattr_u32(tb[IFLA_BR_HELLO_TIME]));

	if (tb[IFLA_BR_MAX_AGE])
		fprintf(f, "max_age %u ",
			rta_getattr_u32(tb[IFLA_BR_MAX_AGE]));

	if (tb[IFLA_BR_AGEING_TIME])
		fprintf(f, "ageing_time %u ",
			rta_getattr_u32(tb[IFLA_BR_AGEING_TIME]));

	if (tb[IFLA_BR_STP_STATE])
		fprintf(f, "stp_state %u ",
			rta_getattr_u32(tb[IFLA_BR_STP_STATE]));

	if (tb[IFLA_BR_PRIORITY])
		fprintf(f, "priority %u ",
			rta_getattr_u16(tb[IFLA_BR_PRIORITY]));

	if (tb[IFLA_BR_VLAN_FILTERING])
		fprintf(f, "vlan_filtering %u ",
			rta_getattr_u8(tb[IFLA_BR_VLAN_FILTERING]));

	if (tb[IFLA_BR_VLAN_PROTOCOL]) {
		SPRINT_BUF(b1);

		fprintf(f, "vlan_protocol %s ",
			ll_proto_n2a(rta_getattr_u16(tb[IFLA_BR_VLAN_PROTOCOL]),
				     b1, sizeof(b1)));
	}

	if (tb[IFLA_BR_BRIDGE_ID]) {
		char bridge_id[32];

		br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), bridge_id,
				  sizeof(bridge_id));
		fprintf(f, "bridge_id %s ", bridge_id);
	}

	if (tb[IFLA_BR_ROOT_ID]) {
		char root_id[32];

		br_dump_bridge_id(RTA_DATA(tb[IFLA_BR_BRIDGE_ID]), root_id,
				  sizeof(root_id));
		fprintf(f, "designated_root %s ", root_id);
	}

	if (tb[IFLA_BR_ROOT_PORT])
		fprintf(f, "root_port %u ",
			rta_getattr_u16(tb[IFLA_BR_ROOT_PORT]));

	if (tb[IFLA_BR_ROOT_PATH_COST])
		fprintf(f, "root_path_cost %u ",
			rta_getattr_u32(tb[IFLA_BR_ROOT_PATH_COST]));

	if (tb[IFLA_BR_TOPOLOGY_CHANGE])
		fprintf(f, "topology_change %u ",
			rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE]));

	if (tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED])
		fprintf(f, "topology_change_detected %u ",
			rta_getattr_u8(tb[IFLA_BR_TOPOLOGY_CHANGE_DETECTED]));

	if (tb[IFLA_BR_HELLO_TIMER]) {
		struct timeval tv;

		__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_HELLO_TIMER]));
		fprintf(f, "hello_timer %4i.%.2i ", (int)tv.tv_sec,
			(int)tv.tv_usec/10000);
	}

	if (tb[IFLA_BR_TCN_TIMER]) {
		struct timeval tv;

		__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_TCN_TIMER]));
		fprintf(f, "tcn_timer %4i.%.2i ", (int)tv.tv_sec,
			(int)tv.tv_usec/10000);
	}

	if (tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]) {
		unsigned long jiffies;
		struct timeval tv;

		jiffies = rta_getattr_u64(tb[IFLA_BR_TOPOLOGY_CHANGE_TIMER]);
		__jiffies_to_tv(&tv, jiffies);
		fprintf(f, "topology_change_timer %4i.%.2i ", (int)tv.tv_sec,
			(int)tv.tv_usec/10000);
	}

	if (tb[IFLA_BR_GC_TIMER]) {
		struct timeval tv;

		__jiffies_to_tv(&tv, rta_getattr_u64(tb[IFLA_BR_GC_TIMER]));
		fprintf(f, "gc_timer %4i.%.2i ", (int)tv.tv_sec,
			(int)tv.tv_usec/10000);
	}

	if (tb[IFLA_BR_VLAN_DEFAULT_PVID])
		fprintf(f, "vlan_default_pvid %u ",
			rta_getattr_u16(tb[IFLA_BR_VLAN_DEFAULT_PVID]));

	if (tb[IFLA_BR_GROUP_FWD_MASK])
		fprintf(f, "group_fwd_mask %#x ",
			rta_getattr_u16(tb[IFLA_BR_GROUP_FWD_MASK]));

	if (tb[IFLA_BR_GROUP_ADDR]) {
		SPRINT_BUF(mac);

		fprintf(f, "group_address %s ",
			ll_addr_n2a(RTA_DATA(tb[IFLA_BR_GROUP_ADDR]),
				    RTA_PAYLOAD(tb[IFLA_BR_GROUP_ADDR]),
				    1 /*ARPHDR_ETHER*/, mac, sizeof(mac)));
	}

	if (tb[IFLA_BR_MCAST_SNOOPING])
		fprintf(f, "mcast_snooping %u ",
			rta_getattr_u8(tb[IFLA_BR_MCAST_SNOOPING]));

	if (tb[IFLA_BR_MCAST_ROUTER])
		fprintf(f, "mcast_router %u ",
			rta_getattr_u8(tb[IFLA_BR_MCAST_ROUTER]));

	if (tb[IFLA_BR_MCAST_QUERY_USE_IFADDR])
		fprintf(f, "mcast_query_use_ifaddr %u ",
			rta_getattr_u8(tb[IFLA_BR_MCAST_QUERY_USE_IFADDR]));

	if (tb[IFLA_BR_MCAST_QUERIER])
		fprintf(f, "mcast_querier %u ",
			rta_getattr_u8(tb[IFLA_BR_MCAST_QUERIER]));

	if (tb[IFLA_BR_MCAST_HASH_ELASTICITY])
		fprintf(f, "mcast_hash_elasticity %u ",
			rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_ELASTICITY]));

	if (tb[IFLA_BR_MCAST_HASH_MAX])
		fprintf(f, "mcast_hash_max %u ",
			rta_getattr_u32(tb[IFLA_BR_MCAST_HASH_MAX]));

	if (tb[IFLA_BR_MCAST_LAST_MEMBER_CNT])
		fprintf(f, "mcast_last_member_count %u ",
			rta_getattr_u32(tb[IFLA_BR_MCAST_LAST_MEMBER_CNT]));

	if (tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT])
		fprintf(f, "mcast_startup_query_count %u ",
			rta_getattr_u32(tb[IFLA_BR_MCAST_STARTUP_QUERY_CNT]));

	if (tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL])
		fprintf(f, "mcast_last_member_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_LAST_MEMBER_INTVL]));

	if (tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL])
		fprintf(f, "mcast_membership_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_MEMBERSHIP_INTVL]));

	if (tb[IFLA_BR_MCAST_QUERIER_INTVL])
		fprintf(f, "mcast_querier_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_QUERIER_INTVL]));

	if (tb[IFLA_BR_MCAST_QUERY_INTVL])
		fprintf(f, "mcast_query_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_INTVL]));

	if (tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL])
		fprintf(f, "mcast_query_response_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]));

	if (tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL])
		fprintf(f, "mcast_startup_query_interval %llu ",
			rta_getattr_u64(tb[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]));

	if (tb[IFLA_BR_NF_CALL_IPTABLES])
		fprintf(f, "nf_call_iptables %u ",
			rta_getattr_u8(tb[IFLA_BR_NF_CALL_IPTABLES]));

	if (tb[IFLA_BR_NF_CALL_IP6TABLES])
		fprintf(f, "nf_call_ip6tables %u ",
			rta_getattr_u8(tb[IFLA_BR_NF_CALL_IP6TABLES]));

	if (tb[IFLA_BR_NF_CALL_ARPTABLES])
		fprintf(f, "nf_call_arptables %u ",
			rta_getattr_u8(tb[IFLA_BR_NF_CALL_ARPTABLES]));
}
예제 #23
0
파일: link_gre6.c 프로젝트: hannes/iproute2
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;
	} 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 nlmsghdr *answer;
	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;
	__be32 ikey = 0;
	__be32 okey = 0;
	struct in6_addr raddr = IN6ADDR_ANY_INIT;
	struct in6_addr laddr = IN6ADDR_ANY_INIT;
	unsigned int link = 0;
	unsigned int flowinfo = 0;
	unsigned int flags = 0;
	__u8 hop_limit = DEFAULT_TNL_HOP_LIMIT;
	__u8 encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT;
	__u16 encaptype = 0;
	__u16 encapflags = TUNNEL_ENCAP_FLAG_CSUM6;
	__u16 encapsport = 0;
	__u16 encapdport = 0;
	int len;
	__u32 fwmark = 0;
	__u32 erspan_idx = 0;

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

		len = answer->nlmsg_len;
		len -= NLMSG_LENGTH(sizeof(*ifi));
		if (len < 0)
			goto get_failed;

		parse_rtattr(tb, IFLA_MAX, IFLA_RTA(NLMSG_DATA(answer)), 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])
			memcpy(&laddr, RTA_DATA(greinfo[IFLA_GRE_LOCAL]), sizeof(laddr));

		if (greinfo[IFLA_GRE_REMOTE])
			memcpy(&raddr, RTA_DATA(greinfo[IFLA_GRE_REMOTE]), sizeof(raddr));

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

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

		if (greinfo[IFLA_GRE_ENCAP_LIMIT])
			encap_limit = rta_getattr_u8(greinfo[IFLA_GRE_ENCAP_LIMIT]);

		if (greinfo[IFLA_GRE_FLOWINFO])
			flowinfo = rta_getattr_u32(greinfo[IFLA_GRE_FLOWINFO]);

		if (greinfo[IFLA_GRE_FLAGS])
			flags = rta_getattr_u32(greinfo[IFLA_GRE_FLAGS]);

		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_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]);

		free(answer);
	}

	while (argc > 0) {
		if (!matches(*argv, "key")) {
			NEXT_ARG();
			iflags |= GRE_KEY;
			oflags |= GRE_KEY;
			ikey = okey = tnl_parse_key("key", *argv);
		} else if (!matches(*argv, "ikey")) {
			NEXT_ARG();
			iflags |= GRE_KEY;
			ikey = tnl_parse_key("ikey", *argv);
		} else if (!matches(*argv, "okey")) {
			NEXT_ARG();
			oflags |= GRE_KEY;
			okey = tnl_parse_key("okey", *argv);
		} 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, "remote")) {
			inet_prefix addr;

			NEXT_ARG();
			get_addr(&addr, *argv, AF_INET6);
			memcpy(&raddr, &addr.data, sizeof(raddr));
		} else if (!matches(*argv, "local")) {
			inet_prefix addr;

			NEXT_ARG();
			get_addr(&addr, *argv, AF_INET6);
			memcpy(&laddr, &addr.data, sizeof(laddr));
		} 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")) {
			__u8 uval;

			NEXT_ARG();
			if (get_u8(&uval, *argv, 0))
				invarg("invalid TTL", *argv);
			hop_limit = uval;
		} else if (!matches(*argv, "tos") ||
			   !matches(*argv, "tclass") ||
			   !matches(*argv, "dsfield")) {
			__u8 uval;

			NEXT_ARG();
			flowinfo &= ~IP6_FLOWINFO_TCLASS;
			if (strcmp(*argv, "inherit") == 0)
				flags |= IP6_TNL_F_USE_ORIG_TCLASS;
			else {
				if (get_u8(&uval, *argv, 16))
					invarg("invalid TClass", *argv);
				flowinfo |= htonl((__u32)uval << 20) & IP6_FLOWINFO_TCLASS;
				flags &= ~IP6_TNL_F_USE_ORIG_TCLASS;
			}
		} else if (strcmp(*argv, "flowlabel") == 0 ||
			   strcmp(*argv, "fl") == 0) {
			__u32 uval;

			NEXT_ARG();
			flowinfo &= ~IP6_FLOWINFO_FLOWLABEL;
			if (strcmp(*argv, "inherit") == 0)
				flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL;
			else {
				if (get_u32(&uval, *argv, 16))
					invarg("invalid Flowlabel", *argv);
				if (uval > 0xFFFFF)
					invarg("invalid Flowlabel", *argv);
				flowinfo |= htonl(uval) & IP6_FLOWINFO_FLOWLABEL;
				flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL;
			}
		} else if (strcmp(*argv, "dscp") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "inherit") != 0)
				invarg("not inherit", *argv);
			flags |= IP6_TNL_F_RCV_DSCP_COPY;
		} 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, "fwmark") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "inherit") == 0) {
				flags |= IP6_TNL_F_USE_ORIG_FWMARK;
				fwmark = 0;
			} else {
				if (get_u32(&fwmark, *argv, 0))
					invarg("invalid fwmark\n", *argv);
				flags &= ~IP6_TNL_F_USE_ORIG_FWMARK;
			}
		} else if (strcmp(*argv, "encaplimit") == 0) {
			NEXT_ARG();
			if (strcmp(*argv, "none") == 0) {
				flags |= IP6_TNL_F_IGN_ENCAP_LIMIT;
			} else {
				__u8 uval;

				if (get_u8(&uval, *argv, 0))
					invarg("invalid ELIM", *argv);
				encap_limit = uval;
				flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT;
			}
		} 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
			usage();
		argc--; argv++;
	}

	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, &laddr, sizeof(laddr));
	addattr_l(n, 1024, IFLA_GRE_REMOTE, &raddr, sizeof(raddr));
	if (link)
		addattr32(n, 1024, IFLA_GRE_LINK, link);
	addattr_l(n, 1024, IFLA_GRE_TTL, &hop_limit, 1);
	addattr_l(n, 1024, IFLA_GRE_ENCAP_LIMIT, &encap_limit, 1);
	addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
	addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
	addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
	if (erspan_idx != 0)
		addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);

	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));

	return 0;
}

static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	char s2[64];
	const char *local = "any";
	const char *remote = "any";
	unsigned int iflags = 0;
	unsigned int oflags = 0;
	unsigned int flags = 0;
	unsigned int flowinfo = 0;
	struct in6_addr in6_addr_any = IN6ADDR_ANY_INIT;

	if (!tb)
		return;

	if (tb[IFLA_GRE_FLAGS])
		flags = rta_getattr_u32(tb[IFLA_GRE_FLAGS]);

	if (tb[IFLA_GRE_FLOWINFO])
		flowinfo = rta_getattr_u32(tb[IFLA_GRE_FLOWINFO]);

	if (tb[IFLA_GRE_REMOTE]) {
		struct in6_addr addr;

		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_REMOTE]), sizeof(addr));

		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
			remote = format_host(AF_INET6, sizeof(addr), &addr);
	}

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

	if (tb[IFLA_GRE_LOCAL]) {
		struct in6_addr addr;

		memcpy(&addr, RTA_DATA(tb[IFLA_GRE_LOCAL]), sizeof(addr));

		if (memcmp(&addr, &in6_addr_any, sizeof(addr)))
			local = format_host(AF_INET6, sizeof(addr), &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", "hoplimit %d ", ttl);
		else
			print_int(PRINT_JSON, "ttl", NULL, ttl);
	}

	if (flags & IP6_TNL_F_IGN_ENCAP_LIMIT)
		print_bool(PRINT_ANY,
			   "ip6_tnl_f_ign_encap_limit",
			   "encaplimit none ",
			   true);
	else if (tb[IFLA_GRE_ENCAP_LIMIT]) {
		int encap_limit = rta_getattr_u8(tb[IFLA_GRE_ENCAP_LIMIT]);

		print_int(PRINT_ANY,
			  "encap_limit",
			  "encaplimit %d ",
			  encap_limit);
	}

	if (flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) {
		print_bool(PRINT_ANY,
			   "ip6_tnl_f_use_orig_flowlabel",
			   "flowlabel inherit ",
			   true);
	} else {
		if (is_json_context()) {
			SPRINT_BUF(b1);

			snprintf(b1, sizeof(b1), "0x%05x",
				 ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
			print_string(PRINT_JSON, "flowlabel", NULL, b1);

		} else {
			fprintf(f, "flowlabel 0x%05x ",
				ntohl(flowinfo & IP6_FLOWINFO_FLOWLABEL));
		}
	}

	if (flags & IP6_TNL_F_USE_ORIG_TCLASS) {
		print_bool(PRINT_ANY,
			   "ip6_tnl_f_use_orig_tclass",
			   "tclass inherit ",
			   true);
	} else {
		if (is_json_context()) {
			SPRINT_BUF(b1);

			snprintf(b1, sizeof(b1), "0x%05x",
				 ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20);
			print_string(PRINT_JSON, "tclass", NULL, b1);
		} else {
			fprintf(f, "tclass 0x%02x ",
				 ntohl(flowinfo & IP6_FLOWINFO_TCLASS) >> 20);
		}
	}
예제 #24
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 nopmtudisc 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;
}
예제 #25
0
static void iptunnel_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
    char s1[1024];
    char s2[64];
    const char *local = "any";
    const char *remote = "any";

    if (!tb)
        return;

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

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

    fprintf(f, "remote %s ", remote);

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

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

    fprintf(f, "local %s ", local);

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

        if (n)
            fprintf(f, "dev %s ", n);
        else
            fprintf(f, "dev %u ", link);
    }

    if (tb[IFLA_IPTUN_TTL] && rta_getattr_u8(tb[IFLA_IPTUN_TTL]))
        fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_IPTUN_TTL]));
    else
        fprintf(f, "ttl inherit ");

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

        fputs("tos ", f);
        if (tos == 1)
            fputs("inherit ", f);
        else
            fprintf(f, "0x%x ", tos);
    }

    if (tb[IFLA_IPTUN_PMTUDISC] && rta_getattr_u8(tb[IFLA_IPTUN_PMTUDISC]))
        fprintf(f, "pmtudisc ");
    else
        fprintf(f, "nopmtudisc ");

    if (tb[IFLA_IPTUN_FLAGS]) {
        __u16 iflags = rta_getattr_u16(tb[IFLA_IPTUN_FLAGS]);

        if (iflags & SIT_ISATAP)
            fprintf(f, "isatap ");
    }

    if (tb[IFLA_IPTUN_6RD_PREFIXLEN] &&
            *(__u16 *)RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIXLEN])) {
        __u16 prefixlen = rta_getattr_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]);
        __u16 relayprefixlen =
            rta_getattr_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]);
        __u32 relayprefix =
            rta_getattr_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]);

        printf("6rd-prefix %s/%u ",
               inet_ntop(AF_INET6, RTA_DATA(tb[IFLA_IPTUN_6RD_PREFIX]),
                         s1, sizeof(s1)),
               prefixlen);
        if (relayprefix) {
            printf("6rd-relay_prefix %s/%u ",
                   format_host(AF_INET, 4, &relayprefix, s1,
                               sizeof(s1)),
                   relayprefixlen);
        }
    }
}
예제 #26
0
static void bond_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	unsigned ifindex;

	if (!tb)
		return;

	if (tb[IFLA_BOND_MODE]) {
		const char *mode = get_name(mode_tbl,
			rta_getattr_u8(tb[IFLA_BOND_MODE]));
		fprintf(f, "mode %s ", mode);
	}

	if (tb[IFLA_BOND_ACTIVE_SLAVE] &&
	    (ifindex = rta_getattr_u32(tb[IFLA_BOND_ACTIVE_SLAVE]))) {
		char buf[IFNAMSIZ];
		const char *n = if_indextoname(ifindex, buf);

		if (n)
			fprintf(f, "active_slave %s ", n);
		else
			fprintf(f, "active_slave %u ", ifindex);
	}

	if (tb[IFLA_BOND_MIIMON])
		fprintf(f, "miimon %u ", rta_getattr_u32(tb[IFLA_BOND_MIIMON]));

	if (tb[IFLA_BOND_UPDELAY])
		fprintf(f, "updelay %u ", rta_getattr_u32(tb[IFLA_BOND_UPDELAY]));

	if (tb[IFLA_BOND_DOWNDELAY])
		fprintf(f, "downdelay %u ",
			rta_getattr_u32(tb[IFLA_BOND_DOWNDELAY]));

	if (tb[IFLA_BOND_USE_CARRIER])
		fprintf(f, "use_carrier %u ",
			rta_getattr_u8(tb[IFLA_BOND_USE_CARRIER]));

	if (tb[IFLA_BOND_ARP_INTERVAL])
		fprintf(f, "arp_interval %u ",
			rta_getattr_u32(tb[IFLA_BOND_ARP_INTERVAL]));

	if (tb[IFLA_BOND_ARP_IP_TARGET]) {
		struct rtattr *iptb[BOND_MAX_ARP_TARGETS + 1];
		char buf[INET_ADDRSTRLEN];
		int i;

		parse_rtattr_nested(iptb, BOND_MAX_ARP_TARGETS,
			tb[IFLA_BOND_ARP_IP_TARGET]);

		if (iptb[0])
			fprintf(f, "arp_ip_target ");

		for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
			if (iptb[i])
				fprintf(f, "%s",
					rt_addr_n2a(AF_INET,
						    RTA_PAYLOAD(iptb[i]),
						    RTA_DATA(iptb[i]),
						    buf,
						    INET_ADDRSTRLEN));
			if (i < BOND_MAX_ARP_TARGETS-1 && iptb[i+1])
				fprintf(f, ",");
		}

		if (iptb[0])
			fprintf(f, " ");
	}

	if (tb[IFLA_BOND_ARP_VALIDATE]) {
		const char *arp_validate = get_name(arp_validate_tbl,
			rta_getattr_u32(tb[IFLA_BOND_ARP_VALIDATE]));
		fprintf(f, "arp_validate %s ", arp_validate);
	}

	if (tb[IFLA_BOND_ARP_ALL_TARGETS]) {
		const char *arp_all_targets = get_name(arp_all_targets_tbl,
			rta_getattr_u32(tb[IFLA_BOND_ARP_ALL_TARGETS]));
		fprintf(f, "arp_all_targets %s ", arp_all_targets);
	}

	if (tb[IFLA_BOND_PRIMARY] &&
	    (ifindex = rta_getattr_u32(tb[IFLA_BOND_PRIMARY]))) {
		char buf[IFNAMSIZ];
		const char *n = if_indextoname(ifindex, buf);

		if (n)
			fprintf(f, "primary %s ", n);
		else
			fprintf(f, "primary %u ", ifindex);
	}

	if (tb[IFLA_BOND_PRIMARY_RESELECT]) {
		const char *primary_reselect = get_name(primary_reselect_tbl,
			rta_getattr_u8(tb[IFLA_BOND_PRIMARY_RESELECT]));
		fprintf(f, "primary_reselect %s ", primary_reselect);
	}

	if (tb[IFLA_BOND_FAIL_OVER_MAC]) {
		const char *fail_over_mac = get_name(fail_over_mac_tbl,
			rta_getattr_u8(tb[IFLA_BOND_FAIL_OVER_MAC]));
		fprintf(f, "fail_over_mac %s ", fail_over_mac);
	}

	if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
		const char *xmit_hash_policy = get_name(xmit_hash_policy_tbl,
			rta_getattr_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]));
		fprintf(f, "xmit_hash_policy %s ", xmit_hash_policy);
	}

	if (tb[IFLA_BOND_RESEND_IGMP])
		fprintf(f, "resend_igmp %u ",
			rta_getattr_u32(tb[IFLA_BOND_RESEND_IGMP]));

	if (tb[IFLA_BOND_NUM_PEER_NOTIF])
		fprintf(f, "num_grat_arp %u ",
			rta_getattr_u8(tb[IFLA_BOND_NUM_PEER_NOTIF]));

	if (tb[IFLA_BOND_ALL_SLAVES_ACTIVE])
		fprintf(f, "all_slaves_active %u ",
			rta_getattr_u8(tb[IFLA_BOND_ALL_SLAVES_ACTIVE]));

	if (tb[IFLA_BOND_MIN_LINKS])
		fprintf(f, "min_links %u ",
			rta_getattr_u32(tb[IFLA_BOND_MIN_LINKS]));

	if (tb[IFLA_BOND_LP_INTERVAL])
		fprintf(f, "lp_interval %u ",
			rta_getattr_u32(tb[IFLA_BOND_LP_INTERVAL]));

	if (tb[IFLA_BOND_PACKETS_PER_SLAVE])
		fprintf(f, "packets_per_slave %u ",
			rta_getattr_u32(tb[IFLA_BOND_PACKETS_PER_SLAVE]));

	if (tb[IFLA_BOND_AD_LACP_RATE]) {
		const char *lacp_rate = get_name(lacp_rate_tbl,
			rta_getattr_u8(tb[IFLA_BOND_AD_LACP_RATE]));
		fprintf(f, "lacp_rate %s ", lacp_rate);
	}

	if (tb[IFLA_BOND_AD_SELECT]) {
		const char *ad_select = get_name(ad_select_tbl,
			rta_getattr_u8(tb[IFLA_BOND_AD_SELECT]));
		fprintf(f, "ad_select %s ", ad_select);
	}

	if (tb[IFLA_BOND_AD_INFO]) {
		struct rtattr *adtb[IFLA_BOND_AD_INFO_MAX + 1];

		parse_rtattr_nested(adtb, IFLA_BOND_AD_INFO_MAX,
			tb[IFLA_BOND_AD_INFO]);

		if (adtb[IFLA_BOND_AD_INFO_AGGREGATOR])
			fprintf(f, "ad_aggregator %d ",
			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_AGGREGATOR]));

		if (adtb[IFLA_BOND_AD_INFO_NUM_PORTS])
			fprintf(f, "ad_num_ports %d ",
			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_NUM_PORTS]));

		if (adtb[IFLA_BOND_AD_INFO_ACTOR_KEY])
			fprintf(f, "ad_actor_key %d ",
			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_ACTOR_KEY]));

		if (adtb[IFLA_BOND_AD_INFO_PARTNER_KEY])
			fprintf(f, "ad_partner_key %d ",
			  rta_getattr_u16(adtb[IFLA_BOND_AD_INFO_PARTNER_KEY]));

		if (adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]) {
			unsigned char *p =
				RTA_DATA(adtb[IFLA_BOND_AD_INFO_PARTNER_MAC]);
			SPRINT_BUF(b);
			fprintf(f, "ad_partner_mac %s ",
				ll_addr_n2a(p, ETH_ALEN, 0, b, sizeof(b)));
		}
	}

	if (tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]) {
		fprintf(f, "ad_actor_sys_prio %u ",
			rta_getattr_u16(tb[IFLA_BOND_AD_ACTOR_SYS_PRIO]));
	}

	if (tb[IFLA_BOND_AD_USER_PORT_KEY]) {
		fprintf(f, "ad_user_port_key %u ",
			rta_getattr_u16(tb[IFLA_BOND_AD_USER_PORT_KEY]));
	}

	if (tb[IFLA_BOND_AD_ACTOR_SYSTEM]) {
		/* We assume the l2 address is an Ethernet MAC address */
		SPRINT_BUF(b1);
		fprintf(f, "ad_actor_system %s ",
			ll_addr_n2a(RTA_DATA(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
				    RTA_PAYLOAD(tb[IFLA_BOND_AD_ACTOR_SYSTEM]),
				    1 /*ARPHDR_ETHER*/, b1, sizeof(b1)));
	}

	if (tb[IFLA_BOND_TLB_DYNAMIC_LB]) {
		fprintf(f, "tlb_dynamic_lb %u ",
			rta_getattr_u8(tb[IFLA_BOND_TLB_DYNAMIC_LB]));
	}
}
예제 #27
0
파일: ctrl.c 프로젝트: Distrotech/iproute2
int genl_ctrl_resolve_family(const char *family)
{
	struct rtnl_handle rth;
	struct nlmsghdr *nlh;
	struct genlmsghdr *ghdr;
	int ret = 0;
	struct {
		struct nlmsghdr         n;
		char                    buf[4096];
	} req;

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

	nlh = &req.n;
	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
	nlh->nlmsg_type = GENL_ID_CTRL;

	ghdr = NLMSG_DATA(&req.n);
	ghdr->cmd = CTRL_CMD_GETFAMILY;

	if (rtnl_open_byproto(&rth, 0, NETLINK_GENERIC) < 0) {
		fprintf(stderr, "Cannot open generic netlink socket\n");
		exit(1);
	}

	addattr_l(nlh, 128, CTRL_ATTR_FAMILY_NAME, family, strlen(family) + 1);

	if (rtnl_talk(&rth, nlh, nlh, sizeof(req)) < 0) {
		fprintf(stderr, "Error talking to the kernel\n");
		goto errout;
	}

	{
		struct rtattr *tb[CTRL_ATTR_MAX + 1];
		struct genlmsghdr *ghdr = NLMSG_DATA(nlh);
		int len = nlh->nlmsg_len;
		struct rtattr *attrs;

		if (nlh->nlmsg_type !=  GENL_ID_CTRL) {
			fprintf(stderr, "Not a controller message, nlmsg_len=%d "
				"nlmsg_type=0x%x\n", nlh->nlmsg_len, nlh->nlmsg_type);
			goto errout;
		}

		if (ghdr->cmd != CTRL_CMD_NEWFAMILY) {
			fprintf(stderr, "Unknown controller command %d\n", ghdr->cmd);
			goto errout;
		}

		len -= NLMSG_LENGTH(GENL_HDRLEN);

		if (len < 0) {
			fprintf(stderr, "wrong controller message len %d\n", len);
			return -1;
		}

		attrs = (struct rtattr *) ((char *) ghdr + GENL_HDRLEN);
		parse_rtattr(tb, CTRL_ATTR_MAX, attrs, len);

		if (tb[CTRL_ATTR_FAMILY_ID] == NULL) {
			fprintf(stderr, "Missing family id TLV\n");
			goto errout;
		}

		ret = rta_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]);
	}

errout:
	rtnl_close(&rth);
	return ret;
}
예제 #28
0
static int gre_parse_opt(struct link_util *lu, int argc, char **argv,
			 struct nlmsghdr *n)
{
	struct {
		struct nlmsghdr n;
		struct ifinfomsg i;
		char buf[16384];
	} req;
	struct ifinfomsg *ifi = (struct ifinfomsg *)(n + 1);
	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 ikey = 0;
	unsigned okey = 0;
	unsigned saddr = 0;
	unsigned daddr = 0;
	unsigned 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;

	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, &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]);
	}

	while (argc > 0) {
		if (!matches(*argv, "key")) {
			unsigned 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 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 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 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
			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;
	}

	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);

	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));

	return 0;
}
예제 #29
0
static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
{
	char s1[1024];
	char s2[64];
	const char *local = "any";
	const char *remote = "any";
	unsigned iflags = 0;
	unsigned oflags = 0;

	if (!tb)
		return;

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

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

	fprintf(f, "remote %s ", remote);

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

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

	fprintf(f, "local %s ", local);

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

		if (n)
			fprintf(f, "dev %s ", n);
		else
			fprintf(f, "dev %u ", link);
	}

	if (tb[IFLA_GRE_TTL] && rta_getattr_u8(tb[IFLA_GRE_TTL]))
		fprintf(f, "ttl %d ", rta_getattr_u8(tb[IFLA_GRE_TTL]));
	else
		fprintf(f, "ttl inherit ");

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

		fputs("tos ", f);
		if (tos == 1)
			fputs("inherit ", f);
		else
			fprintf(f, "0x%x ", tos);
	}

	if (tb[IFLA_GRE_PMTUDISC] &&
	    !rta_getattr_u8(tb[IFLA_GRE_PMTUDISC]))
		fputs("nopmtudisc ", f);

	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));
		fprintf(f, "ikey %s ", s2);
	}

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

	if (iflags & GRE_SEQ)
		fputs("iseq ", f);
	if (oflags & GRE_SEQ)
		fputs("oseq ", f);
	if (iflags & GRE_CSUM)
		fputs("icsum ", f);
	if (oflags & GRE_CSUM)
		fputs("ocsum ", f);

	if (tb[IFLA_GRE_ENCAP_TYPE] &&
	    *(__u16 *)RTA_DATA(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
		__u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]);
		__u16 flags = rta_getattr_u16(tb[IFLA_GRE_ENCAP_FLAGS]);
		__u16 sport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_SPORT]);
		__u16 dport = rta_getattr_u16(tb[IFLA_GRE_ENCAP_DPORT]);

		fputs("encap ", f);
		switch (type) {
		case TUNNEL_ENCAP_FOU:
			fputs("fou ", f);
			break;
		case TUNNEL_ENCAP_GUE:
			fputs("gue ", f);
			break;
		default:
			fputs("unknown ", f);
			break;
		}

		if (sport == 0)
			fputs("encap-sport auto ", f);
		else
			fprintf(f, "encap-sport %u", ntohs(sport));

		fprintf(f, "encap-dport %u ", ntohs(dport));

		if (flags & TUNNEL_ENCAP_FLAG_CSUM)
			fputs("encap-csum ", f);
		else
			fputs("noencap-csum ", f);

		if (flags & TUNNEL_ENCAP_FLAG_CSUM6)
			fputs("encap-csum6 ", f);
		else
			fputs("noencap-csum6 ", f);

		if (flags & TUNNEL_ENCAP_FLAG_REMCSUM)
			fputs("encap-remcsum ", f);
		else
			fputs("noencap-remcsum ", f);
	}
}
예제 #30
0
static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n,
		       void *arg)
{
	FILE *fp = (FILE *) arg;
	struct genlmsghdr *ghdr;
	struct rtattr *attrs[TCP_METRICS_ATTR_MAX + 1], *a;
	int len = n->nlmsg_len;
	inet_prefix daddr, saddr;
	int family, i, atype, stype, dlen = 0, slen = 0;

	if (n->nlmsg_type != genl_family)
		return -1;

	len -= NLMSG_LENGTH(GENL_HDRLEN);
	if (len < 0)
		return -1;

	ghdr = NLMSG_DATA(n);
	if (ghdr->cmd != TCP_METRICS_CMD_GET)
		return 0;

	parse_rtattr(attrs, TCP_METRICS_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
		     len);

	if (attrs[TCP_METRICS_ATTR_ADDR_IPV4]) {
		if (f.daddr.family && f.daddr.family != AF_INET)
			return 0;
		a = attrs[TCP_METRICS_ATTR_ADDR_IPV4];
		memcpy(&daddr.data, RTA_DATA(a), 4);
		daddr.bytelen = 4;
		family = AF_INET;
		atype = TCP_METRICS_ATTR_ADDR_IPV4;
		dlen = RTA_PAYLOAD(a);
	} else if (attrs[TCP_METRICS_ATTR_ADDR_IPV6]) {
		if (f.daddr.family && f.daddr.family != AF_INET6)
			return 0;
		a = attrs[TCP_METRICS_ATTR_ADDR_IPV6];
		memcpy(&daddr.data, RTA_DATA(a), 16);
		daddr.bytelen = 16;
		family = AF_INET6;
		atype = TCP_METRICS_ATTR_ADDR_IPV6;
		dlen = RTA_PAYLOAD(a);
	} else {
		return 0;
	}

	if (attrs[TCP_METRICS_ATTR_SADDR_IPV4]) {
		if (f.saddr.family && f.saddr.family != AF_INET)
			return 0;
		a = attrs[TCP_METRICS_ATTR_SADDR_IPV4];
		memcpy(&saddr.data, RTA_DATA(a), 4);
		saddr.bytelen = 4;
		stype = TCP_METRICS_ATTR_SADDR_IPV4;
		slen = RTA_PAYLOAD(a);
	} else if (attrs[TCP_METRICS_ATTR_SADDR_IPV6]) {
		if (f.saddr.family && f.saddr.family != AF_INET6)
			return 0;
		a = attrs[TCP_METRICS_ATTR_SADDR_IPV6];
		memcpy(&saddr.data, RTA_DATA(a), 16);
		saddr.bytelen = 16;
		stype = TCP_METRICS_ATTR_SADDR_IPV6;
		slen = RTA_PAYLOAD(a);
	}

	if (f.daddr.family && f.daddr.bitlen >= 0 &&
	    inet_addr_match(&daddr, &f.daddr, f.daddr.bitlen))
	       return 0;
	/* Only check for the source-address if the kernel supports it,
	 * meaning slen != 0.
	 */
	if (slen && f.saddr.family && f.saddr.bitlen >= 0 &&
	    inet_addr_match(&saddr, &f.saddr, f.saddr.bitlen))
		return 0;

	if (f.flushb) {
		struct nlmsghdr *fn;

		TCPM_REQUEST(req2, 128, TCP_METRICS_CMD_DEL, NLM_F_REQUEST);

		addattr_l(&req2.n, sizeof(req2), atype, &daddr.data,
			  daddr.bytelen);
		if (slen)
			addattr_l(&req2.n, sizeof(req2), stype, &saddr.data,
				  saddr.bytelen);

		if (NLMSG_ALIGN(f.flushp) + req2.n.nlmsg_len > f.flushe) {
			if (flush_update())
				return -1;
		}
		fn = (struct nlmsghdr *) (f.flushb + NLMSG_ALIGN(f.flushp));
		memcpy(fn, &req2.n, req2.n.nlmsg_len);
		fn->nlmsg_seq = ++grth.seq;
		f.flushp = (((char *) fn) + req2.n.nlmsg_len) - f.flushb;
		f.flushed++;
		if (show_stats < 2)
			return 0;
	}

	if (f.cmd & (CMD_DEL | CMD_FLUSH))
		fprintf(fp, "Deleted ");

	fprintf(fp, "%s",
		format_host(family, dlen, &daddr.data));

	a = attrs[TCP_METRICS_ATTR_AGE];
	if (a) {
		unsigned long long val = rta_getattr_u64(a);

		fprintf(fp, " age %llu.%03llusec",
			val / 1000, val % 1000);
	}

	a = attrs[TCP_METRICS_ATTR_TW_TS_STAMP];
	if (a) {
		__s32 val = (__s32) rta_getattr_u32(a);
		__u32 tsval;

		a = attrs[TCP_METRICS_ATTR_TW_TSVAL];
		tsval = a ? rta_getattr_u32(a) : 0;
		fprintf(fp, " tw_ts %u/%dsec ago", tsval, val);
	}

	a = attrs[TCP_METRICS_ATTR_VALS];
	if (a) {
		struct rtattr *m[TCP_METRIC_MAX + 1 + 1];
		unsigned long rtt = 0, rttvar = 0;

		parse_rtattr_nested(m, TCP_METRIC_MAX + 1, a);

		for (i = 0; i < TCP_METRIC_MAX + 1; i++) {
			unsigned long val;

			a = m[i + 1];
			if (!a)
				continue;
			if (i != TCP_METRIC_RTT &&
			    i != TCP_METRIC_RTT_US &&
			    i != TCP_METRIC_RTTVAR &&
			    i != TCP_METRIC_RTTVAR_US) {
				if (metric_name[i])
					fprintf(fp, " %s ", metric_name[i]);
				else
					fprintf(fp, " metric_%d ", i);
			}
			val = rta_getattr_u32(a);
			switch (i) {
			case TCP_METRIC_RTT:
				if (!rtt)
					rtt = (val * 1000UL) >> 3;
				break;
			case TCP_METRIC_RTTVAR:
				if (!rttvar)
					rttvar = (val * 1000UL) >> 2;
				break;
			case TCP_METRIC_RTT_US:
				rtt = val >> 3;
				break;
			case TCP_METRIC_RTTVAR_US:
				rttvar = val >> 2;
				break;
			case TCP_METRIC_SSTHRESH:
			case TCP_METRIC_CWND:
			case TCP_METRIC_REORDERING:
			default:
				fprintf(fp, "%lu", val);
				break;
			}
		}
		if (rtt)
			fprintf(fp, " rtt %luus", rtt);
		if (rttvar)
			fprintf(fp, " rttvar %luus", rttvar);
	}

	a = attrs[TCP_METRICS_ATTR_FOPEN_MSS];
	if (a)
		fprintf(fp, " fo_mss %u", rta_getattr_u16(a));

	a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROPS];
	if (a) {
		__u16 syn_loss = rta_getattr_u16(a);
		unsigned long long ts;

		a = attrs[TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS];
		ts = a ? rta_getattr_u64(a) : 0;

		fprintf(fp, " fo_syn_drops %u/%llu.%03llusec ago",
			syn_loss, ts / 1000, ts % 1000);
	}

	a = attrs[TCP_METRICS_ATTR_FOPEN_COOKIE];
	if (a) {
		char cookie[32 + 1];
		unsigned char *ptr = RTA_DATA(a);
		int i, max = RTA_PAYLOAD(a);

		if (max > 16)
			max = 16;
		cookie[0] = 0;
		for (i = 0; i < max; i++)
			sprintf(cookie + i + i, "%02x", ptr[i]);
		fprintf(fp, " fo_cookie %s", cookie);
	}

	if (slen) {
		fprintf(fp, " source %s",
			format_host(family, slen, &saddr.data));
	}

	fprintf(fp, "\n");

	fflush(fp);
	return 0;
}