All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2-next] ip fou: Support binding FOU ports
@ 2019-04-09 19:14 Kristian Evensen
  2019-04-17 21:19 ` David Ahern
  0 siblings, 1 reply; 2+ messages in thread
From: Kristian Evensen @ 2019-04-09 19:14 UTC (permalink / raw)
  To: netdev; +Cc: Kristian Evensen

This patch adds support for binding FOU ports using iproute2.
Kernel-support was added in 1713cb37bf67 ("fou: Support binding FoU
socket").

The parse function now handles new arguments for setting the
binding-related attributes, while the print function writes the new
attributes if they are set. Also, the man page has been updated.

Signed-off-by: Kristian Evensen <kristian.evensen@gmail.com>
---
 include/uapi/linux/fou.h |   6 +++
 ip/ipfou.c               | 106 +++++++++++++++++++++++++++++++++++++--
 man/man8/ip-fou.8        |  49 +++++++++++++++++-
 3 files changed, 155 insertions(+), 6 deletions(-)

diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h
index bf022c63..9f915118 100644
--- a/include/uapi/linux/fou.h
+++ b/include/uapi/linux/fou.h
@@ -16,6 +16,12 @@ enum {
 	FOU_ATTR_IPPROTO,			/* u8 */
 	FOU_ATTR_TYPE,				/* u8 */
 	FOU_ATTR_REMCSUM_NOPARTIAL,		/* flag */
+	FOU_ATTR_LOCAL_V4,			/* u32 */
+	FOU_ATTR_LOCAL_V6,			/* in6_addr */
+	FOU_ATTR_PEER_V4,			/* u32 */
+	FOU_ATTR_PEER_V6,			/* in6_addr */
+	FOU_ATTR_PEER_PORT,			/* u16 */
+	FOU_ATTR_IFINDEX,			/* s32 */
 
 	__FOU_ATTR_MAX,
 };
diff --git a/ip/ipfou.c b/ip/ipfou.c
index 346522dd..8bc62d78 100644
--- a/ip/ipfou.c
+++ b/ip/ipfou.c
@@ -28,11 +28,17 @@ static void usage(void)
 {
 	fprintf(stderr,
 		"Usage: ip fou add port PORT { ipproto PROTO  | gue } [ -6 ]\n"
-		"       ip fou del port PORT [ -6 ]\n"
+		"		   [ local IFADDR ] [ peer IFADDR ]\n"
+		"		   [ peer_port PORT ] [ index IDX ]\n"
+		"       ip fou del port PORT [ -6 ] [ local IFADDR ]\n"
+		"		   [ peer IFADDR ] [ peer_port PORT ]\n"
+		"		   [ index IDX ]\n"
 		"       ip fou show\n"
 		"\n"
 		"Where: PROTO { ipproto-name | 1..255 }\n"
-		"       PORT { 1..65535 }\n");
+		"       PORT { 1..65535 }\n"
+		"       IFADDR { addr }\n"
+		"       IDX { interface index }\n");
 
 	exit(-1);
 }
@@ -48,12 +54,14 @@ static int genl_family = -1;
 static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
 			 bool adding)
 {
-	__u16 port;
-	int port_set = 0;
+	__u16 port, peer_port;
+	int port_set = 0, peer_port_set = 0;
 	__u8 ipproto, type;
 	bool gue_set = false;
 	int ipproto_set = 0;
 	__u8 family = AF_INET;
+	const char *local = NULL, *peer = NULL;
+	int index, index_set = 0;
 
 	while (argc > 0) {
 		if (!matches(*argv, "port")) {
@@ -77,6 +85,26 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
 			gue_set = true;
 		} else if (!matches(*argv, "-6")) {
 			family = AF_INET6;
+		} else if (!matches(*argv, "local")) {
+			NEXT_ARG();
+
+			local = *argv;
+		} else if (!matches(*argv, "peer")) {
+			NEXT_ARG();
+
+			peer = *argv;
+		} else if (!matches(*argv, "peer_port")) {
+			NEXT_ARG();
+
+			if (get_be16(&peer_port, *argv, 0) || peer_port == 0)
+				invarg("invalid peer port", *argv);
+			peer_port_set = 1;
+		} else if (!matches(*argv, "index")) {
+			NEXT_ARG();
+
+			if (get_s32(&index, *argv, 0) || index == 0)
+				invarg("invalid interface index", *argv);
+			index_set = 1;
 		} else {
 			fprintf(stderr
 				, "fou: unknown command \"%s\"?\n", *argv);
@@ -101,6 +129,11 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
 		return -1;
 	}
 
+	if ((peer_port_set && !peer) || (peer && !peer_port_set)) {
+		fprintf(stderr, "fou: both peer and peer port must be set\n");
+		return -1;
+	}
+
 	type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT;
 
 	addattr16(n, 1024, FOU_ATTR_PORT, port);
@@ -110,6 +143,32 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
 	if (ipproto_set)
 		addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto);
 
+	if (local) {
+		inet_prefix local_addr;
+		__u8 attr_type = family == AF_INET ? FOU_ATTR_LOCAL_V4 :
+						     FOU_ATTR_LOCAL_V6;
+
+		get_addr(&local_addr, local, family);
+		addattr_l(n, 1024, attr_type, &local_addr.data,
+			  local_addr.bytelen);
+	}
+
+	if (peer) {
+		inet_prefix peer_addr;
+		__u8 attr_type = family == AF_INET ? FOU_ATTR_PEER_V4 :
+						     FOU_ATTR_PEER_V6;
+
+		get_addr(&peer_addr, peer, family);
+		addattr_l(n, 1024, attr_type, &peer_addr.data,
+			  peer_addr.bytelen);
+
+		if (peer_port_set)
+			addattr16(n, 1024, FOU_ATTR_PEER_PORT, peer_port);
+	}
+
+	if (index_set)
+		addattr32(n, 1024, FOU_ATTR_IFINDEX, index);
+
 	return 0;
 }
 
@@ -142,6 +201,8 @@ static int print_fou_mapping(struct nlmsghdr *n, void *arg)
 	struct genlmsghdr *ghdr;
 	struct rtattr *tb[FOU_ATTR_MAX + 1];
 	int len = n->nlmsg_len;
+	__u8 family = AF_INET, local_attr_type, peer_attr_type, byte_len;
+	__u8 empty_buf[16] = {0};
 
 	if (n->nlmsg_type != genl_family)
 		return 0;
@@ -166,7 +227,7 @@ static int print_fou_mapping(struct nlmsghdr *n, void *arg)
 			   " ipproto %u", rta_getattr_u8(tb[FOU_ATTR_IPPROTO]));
 
 	if (tb[FOU_ATTR_AF]) {
-		__u8 family = rta_getattr_u8(tb[FOU_ATTR_AF]);
+		family = rta_getattr_u8(tb[FOU_ATTR_AF]);
 
 		print_string(PRINT_JSON, "family", NULL,
 			     family_name(family));
@@ -175,6 +236,41 @@ static int print_fou_mapping(struct nlmsghdr *n, void *arg)
 			print_string(PRINT_FP, NULL,
 				     " -6", NULL);
 	}
+
+	local_attr_type = family == AF_INET ? FOU_ATTR_LOCAL_V4 :
+					      FOU_ATTR_LOCAL_V6;
+	peer_attr_type = family == AF_INET ? FOU_ATTR_PEER_V4 :
+					     FOU_ATTR_PEER_V6;
+	byte_len = af_bit_len(family) / 8;
+
+	if (tb[local_attr_type] && memcmp(RTA_DATA(tb[local_attr_type]),
+					  empty_buf, byte_len)) {
+		print_string(PRINT_ANY, "local", " local %s",
+			     format_host_rta(family, tb[local_attr_type]));
+	}
+
+	if (tb[peer_attr_type] && memcmp(RTA_DATA(tb[peer_attr_type]),
+					 empty_buf, byte_len)) {
+		print_string(PRINT_ANY, "peer", " peer %s",
+			     format_host_rta(family, tb[peer_attr_type]));
+	}
+
+	if (tb[FOU_ATTR_PEER_PORT]) {
+		__u16 p_port = ntohs(rta_getattr_u16(tb[FOU_ATTR_PEER_PORT]));
+
+		if (p_port)
+			print_uint(PRINT_ANY, "peer_port", " peer_port %u",
+				   p_port);
+
+	}
+
+	if (tb[FOU_ATTR_IFINDEX]) {
+		int index = rta_getattr_s32(tb[FOU_ATTR_IFINDEX]);
+
+		if (index)
+			print_int(PRINT_ANY, "index", " index %d", index);
+	}
+
 	print_string(PRINT_FP, NULL, "\n", NULL);
 	close_json_object();
 
diff --git a/man/man8/ip-fou.8 b/man/man8/ip-fou.8
index 81cab928..2f51c156 100644
--- a/man/man8/ip-fou.8
+++ b/man/man8/ip-fou.8
@@ -24,11 +24,43 @@ ip-gue \- Generic UDP Encapsulation receive port configuration
 .B ipproto
 .IR PROTO
 .RB " }"
+.RB "[ "
+.B local
+.IR IFADDR
+.RB " ]"
+.RB "[ "
+.B peer
+.IR IFADDR
+.RB " ]"
+.RB "[ "
+.B peer_port
+.IR PORT
+.RB " ]"
+.RB "[ "
+.B index
+.IR IDX
+.RB " ]"
 .br
 .ti -8
 .BR "ip fou del"
 .B port
 .IR PORT
+.RB "[ "
+.B local
+.IR IFADDR
+.RB " ]"
+.RB "[ "
+.B peer
+.IR IFADDR
+.RB " ]"
+.RB "[ "
+.B peer_port
+.IR PORT
+.RB " ]"
+.RB "[ "
+.B index
+.IR IDX
+.RB " ]"
 .br
 .ti -8
 .B ip fou show
@@ -50,11 +82,22 @@ When creating a FOU or GUE receive port, the port number is specified in
 .I PORT
 argument. If FOU is used, the IP protocol number associated with the port is specified in
 .I PROTO
+argument. You can bind a port to a local address/interface, by specifying the
+address in the local
+.I IFADDR
+argument or interface index in the
+.I IDX
+argument. If you would like to connect the port, you can specify the peer
+address in the peer
+.I IFADDR
+argument and peer port in the peer_port
+.I PORT
 argument.
 .PP
 A FOU or GUE receive port is deleted by specifying
 .I PORT
-in the delete command.
+in the delete command, as well as local address/interface or peer address/port
+(if set).
 .SH EXAMPLES
 .PP
 .SS Configure a FOU receive port for GRE bound to 7777
@@ -72,6 +115,10 @@ in the delete command.
 .SS Delete the GUE receive port bound to 9999
 .nf
 # ip fou del port 9999
+.SS Configure a FOU receive port for GRE bound to 1.2.3.4:7777
+.nf
+# ip fou add port 7777 ipproto 47 local 1.2.3.4
+.PP
 .SH SEE ALSO
 .br
 .BR ip (8)
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH iproute2-next] ip fou: Support binding FOU ports
  2019-04-09 19:14 [PATCH iproute2-next] ip fou: Support binding FOU ports Kristian Evensen
@ 2019-04-17 21:19 ` David Ahern
  0 siblings, 0 replies; 2+ messages in thread
From: David Ahern @ 2019-04-17 21:19 UTC (permalink / raw)
  To: Kristian Evensen, netdev

On 4/9/19 1:14 PM, Kristian Evensen wrote:
> diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h
> index bf022c63..9f915118 100644
> --- a/include/uapi/linux/fou.h
> +++ b/include/uapi/linux/fou.h
> @@ -16,6 +16,12 @@ enum {
>  	FOU_ATTR_IPPROTO,			/* u8 */
>  	FOU_ATTR_TYPE,				/* u8 */
>  	FOU_ATTR_REMCSUM_NOPARTIAL,		/* flag */
> +	FOU_ATTR_LOCAL_V4,			/* u32 */
> +	FOU_ATTR_LOCAL_V6,			/* in6_addr */
> +	FOU_ATTR_PEER_V4,			/* u32 */
> +	FOU_ATTR_PEER_V6,			/* in6_addr */
> +	FOU_ATTR_PEER_PORT,			/* u16 */
> +	FOU_ATTR_IFINDEX,			/* s32 */
>  
>  	__FOU_ATTR_MAX,
>  };

I just updated the kernel headers, so you can drop the above.

> diff --git a/ip/ipfou.c b/ip/ipfou.c
> index 346522dd..8bc62d78 100644
> --- a/ip/ipfou.c
> +++ b/ip/ipfou.c
> @@ -28,11 +28,17 @@ static void usage(void)
>  {
>  	fprintf(stderr,
>  		"Usage: ip fou add port PORT { ipproto PROTO  | gue } [ -6 ]\n"
> -		"       ip fou del port PORT [ -6 ]\n"
> +		"		   [ local IFADDR ] [ peer IFADDR ]\n"
> +		"		   [ peer_port PORT ] [ index IDX ]\n"
> +		"       ip fou del port PORT [ -6 ] [ local IFADDR ]\n"
> +		"		   [ peer IFADDR ] [ peer_port PORT ]\n"
> +		"		   [ index IDX ]\n"

iproute2 allows users to specify a device by name; it is not very user
friendly to have to run 'ip li sh' to lookup a device to get the index
to run an 'ip' command.

>  		"       ip fou show\n"
>  		"\n"
>  		"Where: PROTO { ipproto-name | 1..255 }\n"
> -		"       PORT { 1..65535 }\n");
> +		"       PORT { 1..65535 }\n"
> +		"       IFADDR { addr }\n"
> +		"       IDX { interface index }\n");
>  
>  	exit(-1);
>  }
> @@ -48,12 +54,14 @@ static int genl_family = -1;
>  static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
>  			 bool adding)
>  {
> -	__u16 port;
> -	int port_set = 0;
> +	__u16 port, peer_port;
> +	int port_set = 0, peer_port_set = 0;
>  	__u8 ipproto, type;
>  	bool gue_set = false;
>  	int ipproto_set = 0;
>  	__u8 family = AF_INET;
> +	const char *local = NULL, *peer = NULL;
> +	int index, index_set = 0;

iproute2 follows the kernel; please order your new ones in reverse xmas
tree (ie., they all go to the top).

>  
>  	while (argc > 0) {
>  		if (!matches(*argv, "port")) {
> @@ -77,6 +85,26 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
>  			gue_set = true;
>  		} else if (!matches(*argv, "-6")) {
>  			family = AF_INET6;
> +		} else if (!matches(*argv, "local")) {
> +			NEXT_ARG();
> +
> +			local = *argv;
> +		} else if (!matches(*argv, "peer")) {
> +			NEXT_ARG();
> +
> +			peer = *argv;
> +		} else if (!matches(*argv, "peer_port")) {
> +			NEXT_ARG();
> +
> +			if (get_be16(&peer_port, *argv, 0) || peer_port == 0)
> +				invarg("invalid peer port", *argv);
> +			peer_port_set = 1;

since port == 0 is not valid, then peer_port_set is not needed; just use
'if (peer_port)'

> +		} else if (!matches(*argv, "index")) {
> +			NEXT_ARG();
> +
> +			if (get_s32(&index, *argv, 0) || index == 0)
> +				invarg("invalid interface index", *argv);
> +			index_set = 1;
>  		} else {
>  			fprintf(stderr
>  				, "fou: unknown command \"%s\"?\n", *argv);
> @@ -101,6 +129,11 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
>  		return -1;
>  	}
>  
> +	if ((peer_port_set && !peer) || (peer && !peer_port_set)) {
> +		fprintf(stderr, "fou: both peer and peer port must be set\n");
> +		return -1;
> +	}
> +
>  	type = gue_set ? FOU_ENCAP_GUE : FOU_ENCAP_DIRECT;
>  
>  	addattr16(n, 1024, FOU_ATTR_PORT, port);
> @@ -110,6 +143,32 @@ static int fou_parse_opt(int argc, char **argv, struct nlmsghdr *n,
>  	if (ipproto_set)
>  		addattr8(n, 1024, FOU_ATTR_IPPROTO, ipproto);
>  
> +	if (local) {
> +		inet_prefix local_addr;
> +		__u8 attr_type = family == AF_INET ? FOU_ATTR_LOCAL_V4 :
> +						     FOU_ATTR_LOCAL_V6;
> +
> +		get_addr(&local_addr, local, family);
> +		addattr_l(n, 1024, attr_type, &local_addr.data,
> +			  local_addr.bytelen);
> +	}
> +
> +	if (peer) {
> +		inet_prefix peer_addr;
> +		__u8 attr_type = family == AF_INET ? FOU_ATTR_PEER_V4 :
> +						     FOU_ATTR_PEER_V6;
> +
> +		get_addr(&peer_addr, peer, family);
> +		addattr_l(n, 1024, attr_type, &peer_addr.data,
> +			  peer_addr.bytelen);
> +
> +		if (peer_port_set)
> +			addattr16(n, 1024, FOU_ATTR_PEER_PORT, peer_port);

what ensures that peer and local are valid IPv4 or IPv6 addresses as
determined by the family? yes, get_addr calls exit(), but it should not
- it should be returning 1 instead. Check the return code on get_addr
and handle the error.


> +	}
> +
> +	if (index_set)
> +		addattr32(n, 1024, FOU_ATTR_IFINDEX, index);
> +
>  	return 0;
>  }
>  
> @@ -142,6 +201,8 @@ static int print_fou_mapping(struct nlmsghdr *n, void *arg)
>  	struct genlmsghdr *ghdr;
>  	struct rtattr *tb[FOU_ATTR_MAX + 1];
>  	int len = n->nlmsg_len;
> +	__u8 family = AF_INET, local_attr_type, peer_attr_type, byte_len;
> +	__u8 empty_buf[16] = {0};

reverse xmas tree.



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2019-04-17 21:19 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-09 19:14 [PATCH iproute2-next] ip fou: Support binding FOU ports Kristian Evensen
2019-04-17 21:19 ` David Ahern

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.