All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH iproute2-next  0/4] Allow 'ip rule' command to use protocol
@ 2018-02-21  1:53 Donald Sharp
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 0/3] " Donald Sharp
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-21  1:53 UTC (permalink / raw)
  To: netdev, dsahern

Fix iprule.c to use the actual `struct fib_rule_hdr` and to
allow the end user to see and use the protocol keyword
for rule manipulations.

Donald Sharp (4):
  ip: Use the `struct fib_rule_hdr` for rules
  ip: Display ip rule protocol used
  ip: Allow rules to accept a specified protocol
  ip: Add ability to flush a rule based upon protocol

 include/uapi/linux/fib_rules.h |   2 +-
 ip/iprule.c                    | 167 ++++++++++++++++++++++++-----------------
 man/man8/ip-rule.8             |  18 ++++-
 3 files changed, 117 insertions(+), 70 deletions(-)

-- 
2.14.3

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

* [PATCH v2 iproute2-next 0/3] Allow 'ip rule' command to use protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
@ 2018-02-22  2:12 ` Donald Sharp
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-22  2:12 UTC (permalink / raw)
  To: netdev, dsahern

Fix iprule.c to use the actual `struct fib_rule_hdr` and to
allow the end user to see and use the protocol keyword
for rule manipulations.

v2: Rearrange and code changes as per David Ahern

Donald Sharp (3):
  ip: Use the `struct fib_rule_hdr` for rules
  ip: Display ip rule protocol used
  ip: Allow rules to accept a specified protocol

 include/uapi/linux/fib_rules.h |   2 +-
 ip/iprule.c                    | 164 ++++++++++++++++++++++++-----------------
 man/man8/ip-rule.8             |  18 ++++-
 3 files changed, 114 insertions(+), 70 deletions(-)

-- 
2.14.3

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

* [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 0/3] " Donald Sharp
@ 2018-02-22  2:12 ` Donald Sharp
  2018-02-22 17:23   ` David Ahern
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Donald Sharp @ 2018-02-22  2:12 UTC (permalink / raw)
  To: netdev, dsahern

The iprule.c code was using `struct rtmsg` as the data
type to pass into the kernel for the netlink message.
While 'struct rtmsg' and `struct fib_rule_hdr` are
the same size and mostly the same, we should use
the correct data structure.  This commit translates
the data structures to have iprule.c use the correct
one.

Additionally copy over the modified fib_rules.h file

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 include/uapi/linux/fib_rules.h |   2 +-
 ip/iprule.c                    | 129 ++++++++++++++++++++++-------------------
 2 files changed, 69 insertions(+), 62 deletions(-)

diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 2b642bf9..92553917 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -23,8 +23,8 @@ struct fib_rule_hdr {
 	__u8		tos;
 
 	__u8		table;
+	__u8		proto;
 	__u8		res1;	/* reserved */
-	__u8		res2;	/* reserved */
 	__u8		action;
 
 	__u32		flags;
diff --git a/ip/iprule.c b/ip/iprule.c
index a3abf2f6..00a6c26a 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -73,25 +73,33 @@ static struct
 	inet_prefix dst;
 } filter;
 
+static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
+{
+	__u32 table = frh->table;
+	if (tb[RTA_TABLE])
+		table = rta_getattr_u32(tb[RTA_TABLE]);
+	return table;
+}
+
 static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 {
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	__u32 table;
 
-	if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
+	if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
 		return false;
 
 	if (filter.prefmask &&
 	    filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
 		return false;
-	if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT))
+	if (filter.not && !(frh->flags & FIB_RULE_INVERT))
 		return false;
 
 	if (filter.src.family) {
 		inet_prefix *f_src = &filter.src;
 
-		if (f_src->family != r->rtm_family ||
-		    f_src->bitlen > r->rtm_src_len)
+		if (f_src->family != frh->family ||
+		    f_src->bitlen > frh->src_len)
 			return false;
 
 		if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
@@ -101,15 +109,15 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 	if (filter.dst.family) {
 		inet_prefix *f_dst = &filter.dst;
 
-		if (f_dst->family != r->rtm_family ||
-		    f_dst->bitlen > r->rtm_dst_len)
+		if (f_dst->family != frh->family ||
+		    f_dst->bitlen > frh->dst_len)
 			return false;
 
 		if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
 			return false;
 	}
 
-	if (filter.tosmask && filter.tos ^ r->rtm_tos)
+	if (filter.tosmask && filter.tos ^ frh->tos)
 		return false;
 
 	if (filter.fwmark) {
@@ -159,7 +167,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 			return false;
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (filter.tb > 0 && filter.tb ^ table)
 		return false;
 
@@ -169,7 +177,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	int host_len = -1;
 	__u32 table;
@@ -180,13 +188,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
 		return 0;
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
-	host_len = af_bit_len(r->rtm_family);
+	host_len = af_bit_len(frh->family);
 
 	if (!filter_nlmsg(n, tb, host_len))
 		return 0;
@@ -200,41 +208,41 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	else
 		fprintf(fp, "0:\t");
 
-	if (r->rtm_flags & FIB_RULE_INVERT)
+	if (frh->flags & FIB_RULE_INVERT)
 		fprintf(fp, "not ");
 
 	if (tb[FRA_SRC]) {
-		if (r->rtm_src_len != host_len) {
+		if (frh->src_len != host_len) {
 			fprintf(fp, "from %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
-				r->rtm_src_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
+				frh->src_len);
 		} else {
 			fprintf(fp, "from %s ",
-				format_host_rta(r->rtm_family, tb[FRA_SRC]));
+				format_host_rta(frh->family, tb[FRA_SRC]));
 		}
-	} else if (r->rtm_src_len) {
-		fprintf(fp, "from 0/%d ", r->rtm_src_len);
+	} else if (frh->src_len) {
+		fprintf(fp, "from 0/%d ", frh->src_len);
 	} else {
 		fprintf(fp, "from all ");
 	}
 
 	if (tb[FRA_DST]) {
-		if (r->rtm_dst_len != host_len) {
+		if (frh->dst_len != host_len) {
 			fprintf(fp, "to %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
-				r->rtm_dst_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
+				frh->dst_len);
 		} else {
 			fprintf(fp, "to %s ",
-				format_host_rta(r->rtm_family, tb[FRA_DST]));
+				format_host_rta(frh->family, tb[FRA_DST]));
 		}
-	} else if (r->rtm_dst_len) {
-		fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+	} else if (frh->dst_len) {
+		fprintf(fp, "to 0/%d ", frh->dst_len);
 	}
 
-	if (r->rtm_tos) {
+	if (frh->tos) {
 		SPRINT_BUF(b1);
 		fprintf(fp, "tos %s ",
-			rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+			rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
 	}
 
 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -252,13 +260,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
 	if (tb[FRA_IFNAME]) {
 		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
-		if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
+		if (frh->flags & FIB_RULE_IIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
 	if (tb[FRA_OIFNAME]) {
 		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
-		if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
+		if (frh->flags & FIB_RULE_OIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
@@ -273,7 +281,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		fprintf(fp, "uidrange %u-%u ", r->start, r->end);
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (table) {
 		fprintf(fp, "lookup %s ",
 			rtnl_rttable_n2a(table, b1, sizeof(b1)));
@@ -308,26 +316,26 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 	}
 
-	if (r->rtm_type == RTN_NAT) {
+	if (frh->action == RTN_NAT) {
 		if (tb[RTA_GATEWAY]) {
 			fprintf(fp, "map-to %s ",
-				format_host_rta(r->rtm_family,
+				format_host_rta(frh->family,
 						tb[RTA_GATEWAY]));
 		} else
 			fprintf(fp, "masquerade");
-	} else if (r->rtm_type == FR_ACT_GOTO) {
+	} else if (frh->action == FR_ACT_GOTO) {
 		fprintf(fp, "goto ");
 		if (tb[FRA_GOTO])
 			fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
 		else
 			fprintf(fp, "none");
-		if (r->rtm_flags & FIB_RULE_UNRESOLVED)
+		if (frh->flags & FIB_RULE_UNRESOLVED)
 			fprintf(fp, " [unresolved]");
-	} else if (r->rtm_type == FR_ACT_NOP)
+	} else if (frh->action == FR_ACT_NOP)
 		fprintf(fp, "nop");
-	else if (r->rtm_type != RTN_UNICAST)
+	else if (frh->action != RTN_UNICAST)
 		fprintf(fp, "%s",
-			rtnl_rtntype_n2a(r->rtm_type,
+			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
 	fprintf(fp, "\n");
@@ -373,15 +381,15 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		      void *arg)
 {
 	struct rtnl_handle rth2;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[FRA_MAX+1];
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
@@ -577,21 +585,20 @@ static int iprule_modify(int cmd, int argc, char **argv)
 	__u32 tid = 0;
 	struct {
 		struct nlmsghdr	n;
-		struct rtmsg		r;
+		struct fib_rule_hdr	frh;
 		char			buf[1024];
 	} req = {
 		.n.nlmsg_type = cmd,
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
 		.n.nlmsg_flags = NLM_F_REQUEST,
-		.r.rtm_family = preferred_family,
-		.r.rtm_protocol = RTPROT_BOOT,
-		.r.rtm_scope = RT_SCOPE_UNIVERSE,
-		.r.rtm_type = RTN_UNSPEC,
+		.frh.family = preferred_family,
+		.frh.proto = RTPROT_BOOT,
+		.frh.action = RTN_UNSPEC,
 	};
 
 	if (cmd == RTM_NEWRULE) {
 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
-		req.r.rtm_type = RTN_UNICAST;
+		req.frh.action = RTN_UNICAST;
 	}
 
 	if (cmd == RTM_DELRULE && argc == 0) {
@@ -601,21 +608,21 @@ static int iprule_modify(int cmd, int argc, char **argv)
 
 	while (argc > 0) {
 		if (strcmp(*argv, "not") == 0) {
-			req.r.rtm_flags |= FIB_RULE_INVERT;
+			req.frh.flags |= FIB_RULE_INVERT;
 		} else if (strcmp(*argv, "from") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_src_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.src_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_SRC,
 				  &dst.data, dst.bytelen);
 		} else if (strcmp(*argv, "to") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_dst_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.dst_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_DST,
 				  &dst.data, dst.bytelen);
 		} else if (matches(*argv, "preference") == 0 ||
@@ -634,7 +641,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			NEXT_ARG();
 			if (rtnl_dsfield_a2n(&tos, *argv))
 				invarg("TOS value is invalid\n", *argv);
-			req.r.rtm_tos = tos;
+			req.frh.tos = tos;
 		} else if (strcmp(*argv, "fwmark") == 0) {
 			char *slash;
 			__u32 fwmark, fwmask;
@@ -667,9 +674,9 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (rtnl_rttable_a2n(&tid, *argv))
 				invarg("invalid table ID\n", *argv);
 			if (tid < 256)
-				req.r.rtm_table = tid;
+				req.frh.table = tid;
 			else {
-				req.r.rtm_table = RT_TABLE_UNSPEC;
+				req.frh.table = RT_TABLE_UNSPEC;
 				addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
 			}
 			table_ok = 1;
@@ -724,7 +731,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			fprintf(stderr, "Warning: route NAT is deprecated\n");
 			addattr32(&req.n, sizeof(req), RTA_GATEWAY,
 				  get_addr32(*argv));
-			req.r.rtm_type = RTN_NAT;
+			req.frh.action = RTN_NAT;
 		} else {
 			int type;
 
@@ -746,7 +753,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 				type = FR_ACT_NOP;
 			else if (rtnl_rtntype_a2n(&type, *argv))
 				invarg("Failed to parse rule type", *argv);
-			req.r.rtm_type = type;
+			req.frh.action = type;
 			table_ok = 1;
 		}
 		argc--;
@@ -759,11 +766,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
 		return -EINVAL;
 	}
 
-	if (req.r.rtm_family == AF_UNSPEC)
-		req.r.rtm_family = AF_INET;
+	if (req.frh.family == AF_UNSPEC)
+		req.frh.family = AF_INET;
 
 	if (!table_ok && cmd == RTM_NEWRULE)
-		req.r.rtm_table = RT_TABLE_MAIN;
+		req.frh.table = RT_TABLE_MAIN;
 
 	if (rtnl_talk(&rth, &req.n, NULL) < 0)
 		return -2;
-- 
2.14.3

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

* [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 0/3] " Donald Sharp
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
@ 2018-02-22  2:12 ` Donald Sharp
  2018-02-22 21:28   ` David Ahern
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Donald Sharp @ 2018-02-22  2:12 UTC (permalink / raw)
  To: netdev, dsahern

Modify 'ip rule' command to notice when the kernel passes
to us the originating protocol.

Add code to allow the `ip rule flush protocol XXX`
command to be accepted and properly handled.

Modify the documentation to reflect these code changes.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c        | 29 ++++++++++++++++++++++-------
 man/man8/ip-rule.8 | 18 +++++++++++++++++-
 2 files changed, 39 insertions(+), 8 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index 00a6c26a..39008768 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -47,6 +47,7 @@ static void usage(void)
 		"            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
 		"            [ uidrange NUMBER-NUMBER ]\n"
 		"ACTION := [ table TABLE_ID ]\n"
+		"          [ protocol RPROTO ]\n"
 		"          [ nat ADDRESS ]\n"
 		"          [ realms [SRCREALM/]DSTREALM ]\n"
 		"          [ goto NUMBER ]\n"
@@ -71,6 +72,8 @@ static struct
 	struct fib_rule_uid_range range;
 	inet_prefix src;
 	inet_prefix dst;
+	int protocol;
+	int protocolmask;
 } filter;
 
 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
@@ -338,6 +341,10 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
+	if (frh->proto != RTPROT_UNSPEC)
+		fprintf(fp, " proto %s ",
+			rtnl_rtprot_n2a(frh->proto, b1, sizeof(b1)));
+
 	fprintf(fp, "\n");
 	fflush(fp);
 	return 0;
@@ -391,6 +398,9 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
 	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
+	if ((filter.protocol^frh->proto)&filter.protocolmask)
+		return 0;
+
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
 		n->nlmsg_flags = NLM_F_REQUEST;
@@ -415,12 +425,6 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 	if (af == AF_UNSPEC)
 		af = AF_INET;
 
-	if (action != IPRULE_LIST && argc > 0) {
-		fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
-				action == IPRULE_SAVE ? "save" : "flush");
-		return -1;
-	}
-
 	switch (action) {
 	case IPRULE_SAVE:
 		if (save_rule_prep())
@@ -508,7 +512,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 			NEXT_ARG();
 			if (get_prefix(&filter.src, *argv, af))
 				invarg("from value is invalid\n", *argv);
-		} else {
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 prot;
+			NEXT_ARG();
+			filter.protocolmask = -1;
+			if (rtnl_rtprot_a2n(&prot, *argv)) {
+				if (strcmp(*argv, "all") != 0)
+					invarg("invalid \"protocol\"\n", *argv);
+				prot = 0;
+				filter.protocolmask = 0;
+			}
+			filter.protocol = prot;
+		} else{
 			if (matches(*argv, "dst") == 0 ||
 			    matches(*argv, "to") == 0) {
 				NEXT_ARG();
diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
index a5c47981..98b2573d 100644
--- a/man/man8/ip-rule.8
+++ b/man/man8/ip-rule.8
@@ -50,6 +50,8 @@ ip-rule \- routing policy database management
 .IR ACTION " := [ "
 .B  table
 .IR TABLE_ID " ] [ "
+.B  protocol
+.IR RPROTO " ] [ "
 .B  nat
 .IR ADDRESS " ] [ "
 .B realms
@@ -240,6 +242,10 @@ The options preference and order are synonyms with priority.
 the routing table identifier to lookup if the rule selector matches.
 It is also possible to use lookup instead of table.
 
+.TP
+.BI protocol " RPROTO"
+the protocol who installed the rule in question.
+
 .TP
 .BI suppress_prefixlength " NUMBER"
 reject routing decisions that have a prefix length of NUMBER or less.
@@ -275,7 +281,11 @@ updates, it flushes the routing cache with
 .RE
 .TP
 .B ip rule flush - also dumps all the deleted rules.
-This command has no arguments.
+.RS
+.TP
+.BI protocol " RPROTO"
+Select the originating protocol.
+.RE
 .TP
 .B ip rule show - list rules
 This command has no arguments.
@@ -283,6 +293,12 @@ The options list or lst are synonyms with show.
 
 .TP
 .B ip rule save
+.RS
+.TP
+.BI protocl " RPROTO"
+Select the originating protocol.
+.RE
+.TP
 save rules table information to stdout
 .RS
 This command behaves like
-- 
2.14.3

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

* [PATCH v2 iproute2-next 3/3] ip: Allow rules to accept a specified protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (2 preceding siblings ...)
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
@ 2018-02-22  2:12 ` Donald Sharp
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-22  2:12 UTC (permalink / raw)
  To: netdev, dsahern

Allow the specification of a protocol when the user
adds/modifies/deletes a rule.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ip/iprule.c b/ip/iprule.c
index 39008768..192fe215 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -683,6 +683,12 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (get_rt_realms_or_raw(&realm, *argv))
 				invarg("invalid realms\n", *argv);
 			addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 proto;
+			NEXT_ARG();
+			if (rtnl_rtprot_a2n(&proto, *argv))
+				invarg("\"protocol\" value is invalid\n", *argv);
+			req.frh.proto = proto;
 		} else if (matches(*argv, "table") == 0 ||
 			   strcmp(*argv, "lookup") == 0) {
 			NEXT_ARG();
-- 
2.14.3

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

* Re: [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
@ 2018-02-22 17:23   ` David Ahern
  0 siblings, 0 replies; 17+ messages in thread
From: David Ahern @ 2018-02-22 17:23 UTC (permalink / raw)
  To: Donald Sharp, netdev

On 2/21/18 7:12 PM, Donald Sharp wrote:
> @@ -577,21 +585,20 @@ static int iprule_modify(int cmd, int argc, char **argv)
>  	__u32 tid = 0;
>  	struct {
>  		struct nlmsghdr	n;
> -		struct rtmsg		r;
> +		struct fib_rule_hdr	frh;
>  		char			buf[1024];
>  	} req = {
>  		.n.nlmsg_type = cmd,
> -		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
> +		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
>  		.n.nlmsg_flags = NLM_F_REQUEST,
> -		.r.rtm_family = preferred_family,
> -		.r.rtm_protocol = RTPROT_BOOT,
> -		.r.rtm_scope = RT_SCOPE_UNIVERSE,
> -		.r.rtm_type = RTN_UNSPEC,
> +		.frh.family = preferred_family,
> +		.frh.proto = RTPROT_BOOT,
> +		.frh.action = RTN_UNSPEC,
>  	};
>  
>  	if (cmd == RTM_NEWRULE) {
>  		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
> -		req.r.rtm_type = RTN_UNICAST;
> +		req.frh.action = RTN_UNICAST;
>  	}

The action should be FR_ACT_TO_TBL; RTN_UNICAST == 1 == FR_ACT_TO_TBL;
the latter is the proper enum for fib rules.

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

* Re: [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
@ 2018-02-22 21:28   ` David Ahern
  0 siblings, 0 replies; 17+ messages in thread
From: David Ahern @ 2018-02-22 21:28 UTC (permalink / raw)
  To: Donald Sharp, netdev

On 2/21/18 7:12 PM, Donald Sharp wrote:
> diff --git a/ip/iprule.c b/ip/iprule.c
> index 00a6c26a..39008768 100644
> --- a/ip/iprule.c
> +++ b/ip/iprule.c
> @@ -47,6 +47,7 @@ static void usage(void)
>  		"            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
>  		"            [ uidrange NUMBER-NUMBER ]\n"
>  		"ACTION := [ table TABLE_ID ]\n"
> +		"          [ protocol RPROTO ]\n"

Drop the 'R' makes it harder to read; just 'PROTO' is fine.


>  		"          [ nat ADDRESS ]\n"
>  		"          [ realms [SRCREALM/]DSTREALM ]\n"
>  		"          [ goto NUMBER ]\n"
> @@ -71,6 +72,8 @@ static struct
>  	struct fib_rule_uid_range range;
>  	inet_prefix src;
>  	inet_prefix dst;
> +	int protocol;
> +	int protocolmask;
>  } filter;
>  
>  static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
> @@ -338,6 +341,10 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
>  			rtnl_rtntype_n2a(frh->action,
>  					 b1, sizeof(b1)));
>  
> +	if (frh->proto != RTPROT_UNSPEC)
> +		fprintf(fp, " proto %s ",
> +			rtnl_rtprot_n2a(frh->proto, b1, sizeof(b1)));
> +
>  	fprintf(fp, "\n");
>  	fflush(fp);
>  	return 0;
> @@ -391,6 +398,9 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
>  
>  	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
>  
> +	if ((filter.protocol^frh->proto)&filter.protocolmask)
> +		return 0;
> +
>  	if (tb[FRA_PRIORITY]) {
>  		n->nlmsg_type = RTM_DELRULE;
>  		n->nlmsg_flags = NLM_F_REQUEST;
> @@ -415,12 +425,6 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
>  	if (af == AF_UNSPEC)
>  		af = AF_INET;
>  
> -	if (action != IPRULE_LIST && argc > 0) {
> -		fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
> -				action == IPRULE_SAVE ? "save" : "flush");
> -		return -1;
> -	}
> -
>  	switch (action) {
>  	case IPRULE_SAVE:
>  		if (save_rule_prep())
> @@ -508,7 +512,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
>  			NEXT_ARG();
>  			if (get_prefix(&filter.src, *argv, af))
>  				invarg("from value is invalid\n", *argv);
> -		} else {
> +		} else if (matches(*argv, "protocol") == 0) {
> +			__u32 prot;
> +			NEXT_ARG();
> +			filter.protocolmask = -1;
> +			if (rtnl_rtprot_a2n(&prot, *argv)) {
> +				if (strcmp(*argv, "all") != 0)
> +					invarg("invalid \"protocol\"\n", *argv);
> +				prot = 0;
> +				filter.protocolmask = 0;
> +			}
> +			filter.protocol = prot;
> +		} else{
>  			if (matches(*argv, "dst") == 0 ||
>  			    matches(*argv, "to") == 0) {
>  				NEXT_ARG();
> diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
> index a5c47981..98b2573d 100644
> --- a/man/man8/ip-rule.8
> +++ b/man/man8/ip-rule.8
> @@ -50,6 +50,8 @@ ip-rule \- routing policy database management
>  .IR ACTION " := [ "
>  .B  table
>  .IR TABLE_ID " ] [ "
> +.B  protocol
> +.IR RPROTO " ] [ "

same here and others in this file

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

* [PATCH v3 iproute2-next 0/3] Allow 'ip rule' command to use protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (3 preceding siblings ...)
  2018-02-22  2:12 ` [PATCH v2 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
@ 2018-02-23 19:32 ` Donald Sharp
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-23 19:32 UTC (permalink / raw)
  To: netdev, dsahern

Fix iprule.c to use the actual `struct fib_rule_hdr` and to
allow the end user to see and use the protocol keyword
for rule manipulation.

v2: Rearrange and code changes as per David Ahern
v3: Fix some missed RTN_XXX to appropriate FR_XX and doc changes

Donald Sharp (3):
  ip: Use the `struct fib_rule_hdr` for rules
  ip: Display ip rule protocol used
  ip: Allow rules to accept a specified protocol

 include/uapi/linux/fib_rules.h |   1 +
 ip/iprule.c                    | 170 ++++++++++++++++++++++++-----------------
 man/man8/ip-rule.8             |  18 ++++-
 3 files changed, 120 insertions(+), 69 deletions(-)

-- 
2.14.3

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

* [PATCH v3 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (4 preceding siblings ...)
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
@ 2018-02-23 19:32 ` Donald Sharp
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-23 19:32 UTC (permalink / raw)
  To: netdev, dsahern

The iprule.c code was using `struct rtmsg` as the data
type to pass into the kernel for the netlink message.
While 'struct rtmsg' and `struct fib_rule_hdr` are
the same size and mostly the same, we should use
the correct data structure.  This commit translates
the data structures to have iprule.c use the correct
one.

Additionally copy over the modified fib_rules.h file

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 include/uapi/linux/fib_rules.h |   1 +
 ip/iprule.c                    | 128 +++++++++++++++++++++--------------------
 2 files changed, 68 insertions(+), 61 deletions(-)

diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 2b642bf9..9477c3af 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -58,6 +58,7 @@ enum {
 	FRA_PAD,
 	FRA_L3MDEV,	/* iif or oif is l3mdev goto its table */
 	FRA_UID_RANGE,	/* UID range */
+	FRA_PROTOCOL,
 	__FRA_MAX
 };
 
diff --git a/ip/iprule.c b/ip/iprule.c
index a3abf2f6..94356bf8 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -73,25 +73,33 @@ static struct
 	inet_prefix dst;
 } filter;
 
+static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
+{
+	__u32 table = frh->table;
+	if (tb[RTA_TABLE])
+		table = rta_getattr_u32(tb[RTA_TABLE]);
+	return table;
+}
+
 static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 {
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	__u32 table;
 
-	if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
+	if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
 		return false;
 
 	if (filter.prefmask &&
 	    filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
 		return false;
-	if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT))
+	if (filter.not && !(frh->flags & FIB_RULE_INVERT))
 		return false;
 
 	if (filter.src.family) {
 		inet_prefix *f_src = &filter.src;
 
-		if (f_src->family != r->rtm_family ||
-		    f_src->bitlen > r->rtm_src_len)
+		if (f_src->family != frh->family ||
+		    f_src->bitlen > frh->src_len)
 			return false;
 
 		if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
@@ -101,15 +109,15 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 	if (filter.dst.family) {
 		inet_prefix *f_dst = &filter.dst;
 
-		if (f_dst->family != r->rtm_family ||
-		    f_dst->bitlen > r->rtm_dst_len)
+		if (f_dst->family != frh->family ||
+		    f_dst->bitlen > frh->dst_len)
 			return false;
 
 		if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
 			return false;
 	}
 
-	if (filter.tosmask && filter.tos ^ r->rtm_tos)
+	if (filter.tosmask && filter.tos ^ frh->tos)
 		return false;
 
 	if (filter.fwmark) {
@@ -159,7 +167,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 			return false;
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (filter.tb > 0 && filter.tb ^ table)
 		return false;
 
@@ -169,7 +177,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	int host_len = -1;
 	__u32 table;
@@ -180,13 +188,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
 		return 0;
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
-	host_len = af_bit_len(r->rtm_family);
+	host_len = af_bit_len(frh->family);
 
 	if (!filter_nlmsg(n, tb, host_len))
 		return 0;
@@ -200,41 +208,41 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	else
 		fprintf(fp, "0:\t");
 
-	if (r->rtm_flags & FIB_RULE_INVERT)
+	if (frh->flags & FIB_RULE_INVERT)
 		fprintf(fp, "not ");
 
 	if (tb[FRA_SRC]) {
-		if (r->rtm_src_len != host_len) {
+		if (frh->src_len != host_len) {
 			fprintf(fp, "from %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
-				r->rtm_src_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
+				frh->src_len);
 		} else {
 			fprintf(fp, "from %s ",
-				format_host_rta(r->rtm_family, tb[FRA_SRC]));
+				format_host_rta(frh->family, tb[FRA_SRC]));
 		}
-	} else if (r->rtm_src_len) {
-		fprintf(fp, "from 0/%d ", r->rtm_src_len);
+	} else if (frh->src_len) {
+		fprintf(fp, "from 0/%d ", frh->src_len);
 	} else {
 		fprintf(fp, "from all ");
 	}
 
 	if (tb[FRA_DST]) {
-		if (r->rtm_dst_len != host_len) {
+		if (frh->dst_len != host_len) {
 			fprintf(fp, "to %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
-				r->rtm_dst_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
+				frh->dst_len);
 		} else {
 			fprintf(fp, "to %s ",
-				format_host_rta(r->rtm_family, tb[FRA_DST]));
+				format_host_rta(frh->family, tb[FRA_DST]));
 		}
-	} else if (r->rtm_dst_len) {
-		fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+	} else if (frh->dst_len) {
+		fprintf(fp, "to 0/%d ", frh->dst_len);
 	}
 
-	if (r->rtm_tos) {
+	if (frh->tos) {
 		SPRINT_BUF(b1);
 		fprintf(fp, "tos %s ",
-			rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+			rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
 	}
 
 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -252,13 +260,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
 	if (tb[FRA_IFNAME]) {
 		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
-		if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
+		if (frh->flags & FIB_RULE_IIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
 	if (tb[FRA_OIFNAME]) {
 		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
-		if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
+		if (frh->flags & FIB_RULE_OIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
@@ -273,7 +281,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		fprintf(fp, "uidrange %u-%u ", r->start, r->end);
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (table) {
 		fprintf(fp, "lookup %s ",
 			rtnl_rttable_n2a(table, b1, sizeof(b1)));
@@ -308,26 +316,26 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 	}
 
-	if (r->rtm_type == RTN_NAT) {
+	if (frh->action == RTN_NAT) {
 		if (tb[RTA_GATEWAY]) {
 			fprintf(fp, "map-to %s ",
-				format_host_rta(r->rtm_family,
+				format_host_rta(frh->family,
 						tb[RTA_GATEWAY]));
 		} else
 			fprintf(fp, "masquerade");
-	} else if (r->rtm_type == FR_ACT_GOTO) {
+	} else if (frh->action == FR_ACT_GOTO) {
 		fprintf(fp, "goto ");
 		if (tb[FRA_GOTO])
 			fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
 		else
 			fprintf(fp, "none");
-		if (r->rtm_flags & FIB_RULE_UNRESOLVED)
+		if (frh->flags & FIB_RULE_UNRESOLVED)
 			fprintf(fp, " [unresolved]");
-	} else if (r->rtm_type == FR_ACT_NOP)
+	} else if (frh->action == FR_ACT_NOP)
 		fprintf(fp, "nop");
-	else if (r->rtm_type != RTN_UNICAST)
+	else if (frh->action != FR_ACT_TO_TBL)
 		fprintf(fp, "%s",
-			rtnl_rtntype_n2a(r->rtm_type,
+			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
 	fprintf(fp, "\n");
@@ -373,15 +381,15 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		      void *arg)
 {
 	struct rtnl_handle rth2;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[FRA_MAX+1];
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
@@ -577,21 +585,19 @@ static int iprule_modify(int cmd, int argc, char **argv)
 	__u32 tid = 0;
 	struct {
 		struct nlmsghdr	n;
-		struct rtmsg		r;
+		struct fib_rule_hdr	frh;
 		char			buf[1024];
 	} req = {
 		.n.nlmsg_type = cmd,
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
 		.n.nlmsg_flags = NLM_F_REQUEST,
-		.r.rtm_family = preferred_family,
-		.r.rtm_protocol = RTPROT_BOOT,
-		.r.rtm_scope = RT_SCOPE_UNIVERSE,
-		.r.rtm_type = RTN_UNSPEC,
+		.frh.family = preferred_family,
+		.frh.action = FR_ACT_UNSPEC,
 	};
 
 	if (cmd == RTM_NEWRULE) {
 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
-		req.r.rtm_type = RTN_UNICAST;
+		req.frh.action = FR_ACT_TO_TBL;
 	}
 
 	if (cmd == RTM_DELRULE && argc == 0) {
@@ -601,21 +607,21 @@ static int iprule_modify(int cmd, int argc, char **argv)
 
 	while (argc > 0) {
 		if (strcmp(*argv, "not") == 0) {
-			req.r.rtm_flags |= FIB_RULE_INVERT;
+			req.frh.flags |= FIB_RULE_INVERT;
 		} else if (strcmp(*argv, "from") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_src_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.src_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_SRC,
 				  &dst.data, dst.bytelen);
 		} else if (strcmp(*argv, "to") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_dst_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.dst_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_DST,
 				  &dst.data, dst.bytelen);
 		} else if (matches(*argv, "preference") == 0 ||
@@ -634,7 +640,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			NEXT_ARG();
 			if (rtnl_dsfield_a2n(&tos, *argv))
 				invarg("TOS value is invalid\n", *argv);
-			req.r.rtm_tos = tos;
+			req.frh.tos = tos;
 		} else if (strcmp(*argv, "fwmark") == 0) {
 			char *slash;
 			__u32 fwmark, fwmask;
@@ -667,9 +673,9 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (rtnl_rttable_a2n(&tid, *argv))
 				invarg("invalid table ID\n", *argv);
 			if (tid < 256)
-				req.r.rtm_table = tid;
+				req.frh.table = tid;
 			else {
-				req.r.rtm_table = RT_TABLE_UNSPEC;
+				req.frh.table = RT_TABLE_UNSPEC;
 				addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
 			}
 			table_ok = 1;
@@ -724,7 +730,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			fprintf(stderr, "Warning: route NAT is deprecated\n");
 			addattr32(&req.n, sizeof(req), RTA_GATEWAY,
 				  get_addr32(*argv));
-			req.r.rtm_type = RTN_NAT;
+			req.frh.action = RTN_NAT;
 		} else {
 			int type;
 
@@ -746,7 +752,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 				type = FR_ACT_NOP;
 			else if (rtnl_rtntype_a2n(&type, *argv))
 				invarg("Failed to parse rule type", *argv);
-			req.r.rtm_type = type;
+			req.frh.action = type;
 			table_ok = 1;
 		}
 		argc--;
@@ -759,11 +765,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
 		return -EINVAL;
 	}
 
-	if (req.r.rtm_family == AF_UNSPEC)
-		req.r.rtm_family = AF_INET;
+	if (req.frh.family == AF_UNSPEC)
+		req.frh.family = AF_INET;
 
 	if (!table_ok && cmd == RTM_NEWRULE)
-		req.r.rtm_table = RT_TABLE_MAIN;
+		req.frh.table = RT_TABLE_MAIN;
 
 	if (rtnl_talk(&rth, &req.n, NULL) < 0)
 		return -2;
-- 
2.14.3

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

* [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (5 preceding siblings ...)
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
@ 2018-02-23 19:32 ` Donald Sharp
  2018-02-26 21:35   ` David Ahern
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Donald Sharp @ 2018-02-23 19:32 UTC (permalink / raw)
  To: netdev, dsahern

Modify 'ip rule' command to notice when the kernel passes
to us the originating protocol.

Add code to allow the `ip rule flush protocol XXX`
command to be accepted and properly handled.

Modify the documentation to reflect these code changes.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c        | 36 +++++++++++++++++++++++++++++-------
 man/man8/ip-rule.8 | 18 +++++++++++++++++-
 2 files changed, 46 insertions(+), 8 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index 94356bf8..17df9e9b 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -47,6 +47,7 @@ static void usage(void)
 		"            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
 		"            [ uidrange NUMBER-NUMBER ]\n"
 		"ACTION := [ table TABLE_ID ]\n"
+		"          [ protocol PROTO ]\n"
 		"          [ nat ADDRESS ]\n"
 		"          [ realms [SRCREALM/]DSTREALM ]\n"
 		"          [ goto NUMBER ]\n"
@@ -71,6 +72,8 @@ static struct
 	struct fib_rule_uid_range range;
 	inet_prefix src;
 	inet_prefix dst;
+	int protocol;
+	int protocolmask;
 } filter;
 
 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
@@ -338,6 +341,16 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
+	if (tb[FRA_PROTOCOL]) {
+		__u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+		if ((protocol && protocol != RTPROT_KERNEL) ||
+		    show_details > 0) {
+			fprintf(fp, " proto %s ",
+				rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+		}
+	}
+
 	fprintf(fp, "\n");
 	fflush(fp);
 	return 0;
@@ -391,6 +404,10 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
 	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
+	if (tb[FRA_PROTOCOL] &&
+	    (filter.protocol^rta_getattr_u8(tb[FRA_PROTOCOL]))&filter.protocolmask)
+		return 0;
+
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
 		n->nlmsg_flags = NLM_F_REQUEST;
@@ -415,12 +432,6 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 	if (af == AF_UNSPEC)
 		af = AF_INET;
 
-	if (action != IPRULE_LIST && argc > 0) {
-		fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
-				action == IPRULE_SAVE ? "save" : "flush");
-		return -1;
-	}
-
 	switch (action) {
 	case IPRULE_SAVE:
 		if (save_rule_prep())
@@ -508,7 +519,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 			NEXT_ARG();
 			if (get_prefix(&filter.src, *argv, af))
 				invarg("from value is invalid\n", *argv);
-		} else {
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 prot;
+			NEXT_ARG();
+			filter.protocolmask = -1;
+			if (rtnl_rtprot_a2n(&prot, *argv)) {
+				if (strcmp(*argv, "all") != 0)
+					invarg("invalid \"protocol\"\n", *argv);
+				prot = 0;
+				filter.protocolmask = 0;
+			}
+			filter.protocol = prot;
+		} else{
 			if (matches(*argv, "dst") == 0 ||
 			    matches(*argv, "to") == 0) {
 				NEXT_ARG();
diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
index a5c47981..f4070542 100644
--- a/man/man8/ip-rule.8
+++ b/man/man8/ip-rule.8
@@ -50,6 +50,8 @@ ip-rule \- routing policy database management
 .IR ACTION " := [ "
 .B  table
 .IR TABLE_ID " ] [ "
+.B  protocol
+.IR PROTO " ] [ "
 .B  nat
 .IR ADDRESS " ] [ "
 .B realms
@@ -240,6 +242,10 @@ The options preference and order are synonyms with priority.
 the routing table identifier to lookup if the rule selector matches.
 It is also possible to use lookup instead of table.
 
+.TP
+.BI protocol " PROTO"
+the protocol who installed the rule in question.
+
 .TP
 .BI suppress_prefixlength " NUMBER"
 reject routing decisions that have a prefix length of NUMBER or less.
@@ -275,7 +281,11 @@ updates, it flushes the routing cache with
 .RE
 .TP
 .B ip rule flush - also dumps all the deleted rules.
-This command has no arguments.
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
 .TP
 .B ip rule show - list rules
 This command has no arguments.
@@ -283,6 +293,12 @@ The options list or lst are synonyms with show.
 
 .TP
 .B ip rule save
+.RS
+.TP
+.BI protocl " PROTO"
+Select the originating protocol.
+.RE
+.TP
 save rules table information to stdout
 .RS
 This command behaves like
-- 
2.14.3

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

* [PATCH v3 iproute2-next 3/3] ip: Allow rules to accept a specified protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (6 preceding siblings ...)
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
@ 2018-02-23 19:32 ` Donald Sharp
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-23 19:32 UTC (permalink / raw)
  To: netdev, dsahern

Allow the specification of a protocol when the user
adds/modifies/deletes a rule.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/ip/iprule.c b/ip/iprule.c
index 17df9e9b..796da3b3 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -689,6 +689,12 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (get_rt_realms_or_raw(&realm, *argv))
 				invarg("invalid realms\n", *argv);
 			addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 proto;
+			NEXT_ARG();
+			if (rtnl_rtprot_a2n(&proto, *argv))
+				invarg("\"protocol\" value is invalid\n", *argv);
+			addattr8(&req.n, sizeof(req), FRA_PROTOCOL, proto);
 		} else if (matches(*argv, "table") == 0 ||
 			   strcmp(*argv, "lookup") == 0) {
 			NEXT_ARG();
-- 
2.14.3

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

* Re: [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
@ 2018-02-26 21:35   ` David Ahern
  0 siblings, 0 replies; 17+ messages in thread
From: David Ahern @ 2018-02-26 21:35 UTC (permalink / raw)
  To: Donald Sharp, netdev

On 2/23/18 12:32 PM, Donald Sharp wrote:
> @@ -391,6 +404,10 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
>  
>  	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
>  
> +	if (tb[FRA_PROTOCOL] &&
> +	    (filter.protocol^rta_getattr_u8(tb[FRA_PROTOCOL]))&filter.protocolmask)
> +		return 0;
> +

Please use an intermediate variable for rta conversion and put
whitespace around '^' and '&'; existing code that does the above is a
poor example to follow. ;-)


>  	if (tb[FRA_PRIORITY]) {
>  		n->nlmsg_type = RTM_DELRULE;
>  		n->nlmsg_flags = NLM_F_REQUEST;
> @@ -415,12 +432,6 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
>  	if (af == AF_UNSPEC)
>  		af = AF_INET;
>  
> -	if (action != IPRULE_LIST && argc > 0) {
> -		fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
> -				action == IPRULE_SAVE ? "save" : "flush");

You need to keep this for IPRULE_SAVE; only IPRULE_FLUSH is allowing
arguments with this patch.

> -		return -1;
> -	}
> -
>  	switch (action) {
>  	case IPRULE_SAVE:
>  		if (save_rule_prep())
> @@ -508,7 +519,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
>  			NEXT_ARG();
>  			if (get_prefix(&filter.src, *argv, af))
>  				invarg("from value is invalid\n", *argv);
> -		} else {
> +		} else if (matches(*argv, "protocol") == 0) {
> +			__u32 prot;
> +			NEXT_ARG();
> +			filter.protocolmask = -1;
> +			if (rtnl_rtprot_a2n(&prot, *argv)) {
> +				if (strcmp(*argv, "all") != 0)
> +					invarg("invalid \"protocol\"\n", *argv);
> +				prot = 0;
> +				filter.protocolmask = 0;
> +			}
> +			filter.protocol = prot;
> +		} else{
>  			if (matches(*argv, "dst") == 0 ||
>  			    matches(*argv, "to") == 0) {
>  				NEXT_ARG();
> diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
> index a5c47981..f4070542 100644
> --- a/man/man8/ip-rule.8
> +++ b/man/man8/ip-rule.8
> @@ -50,6 +50,8 @@ ip-rule \- routing policy database management
>  .IR ACTION " := [ "
>  .B  table
>  .IR TABLE_ID " ] [ "
> +.B  protocol
> +.IR PROTO " ] [ "
>  .B  nat
>  .IR ADDRESS " ] [ "
>  .B realms
> @@ -240,6 +242,10 @@ The options preference and order are synonyms with priority.
>  the routing table identifier to lookup if the rule selector matches.
>  It is also possible to use lookup instead of table.
>  
> +.TP
> +.BI protocol " PROTO"
> +the protocol who installed the rule in question.

"protocol" is getting a bit vague. Make it clearer by using something
like 'routing protocol' as the description and given an example (e.g.,
zebra for RTPROT_ZEBRA)

> +
>  .TP
>  .BI suppress_prefixlength " NUMBER"
>  reject routing decisions that have a prefix length of NUMBER or less.
> @@ -275,7 +281,11 @@ updates, it flushes the routing cache with
>  .RE
>  .TP
>  .B ip rule flush - also dumps all the deleted rules.
> -This command has no arguments.
> +.RS
> +.TP
> +.BI protocol " PROTO"
> +Select the originating protocol.
> +.RE
>  .TP
>  .B ip rule show - list rules
>  This command has no arguments.
> @@ -283,6 +293,12 @@ The options list or lst are synonyms with show.
>  
>  .TP
>  .B ip rule save
> +.RS
> +.TP
> +.BI protocl " PROTO"

missing an 'o' between 'c' and 'l'

> +Select the originating protocol.
> +.RE
> +.TP
>  save rules table information to stdout
>  .RS
>  This command behaves like
> 

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

* [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (7 preceding siblings ...)
  2018-02-23 19:32 ` [PATCH v3 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
@ 2018-02-28 23:43 ` Donald Sharp
  2018-03-01  3:46   ` David Ahern
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Donald Sharp @ 2018-02-28 23:43 UTC (permalink / raw)
  To: netdev, dsahern

Fix iprule.c to use the actual `struct fib_rule_hdr` and to
allow the end user to see and use the protocol keyword
for rule manipulation.

v2: Rearrange and code changes as per David Ahern
v3: Fix some missed RTN_XXX to appropriate FR_XX and doc changes
v4: Cleanup some code, fix 'ip rule save' no parameters and doc changes

Donald Sharp (3):
  ip: Use the `struct fib_rule_hdr` for rules
  ip: Display ip rule protocol used
  ip: Allow rules to accept a specified protocol

 include/uapi/linux/fib_rules.h |   1 +
 ip/iprule.c                    | 173 +++++++++++++++++++++++++----------------
 man/man8/ip-rule.8             |  18 ++++-
 3 files changed, 126 insertions(+), 66 deletions(-)

-- 
2.14.3

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

* [PATCH v4 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (8 preceding siblings ...)
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
@ 2018-02-28 23:43 ` Donald Sharp
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
  2018-02-28 23:44 ` [PATCH v4 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-28 23:43 UTC (permalink / raw)
  To: netdev, dsahern

The iprule.c code was using `struct rtmsg` as the data
type to pass into the kernel for the netlink message.
While 'struct rtmsg' and `struct fib_rule_hdr` are
the same size and mostly the same, we should use
the correct data structure.  This commit translates
the data structures to have iprule.c use the correct
one.

Additionally copy over the modified fib_rules.h file

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 include/uapi/linux/fib_rules.h |   1 +
 ip/iprule.c                    | 128 +++++++++++++++++++++--------------------
 2 files changed, 68 insertions(+), 61 deletions(-)

diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
index 2b642bf9..9477c3af 100644
--- a/include/uapi/linux/fib_rules.h
+++ b/include/uapi/linux/fib_rules.h
@@ -58,6 +58,7 @@ enum {
 	FRA_PAD,
 	FRA_L3MDEV,	/* iif or oif is l3mdev goto its table */
 	FRA_UID_RANGE,	/* UID range */
+	FRA_PROTOCOL,
 	__FRA_MAX
 };
 
diff --git a/ip/iprule.c b/ip/iprule.c
index a3abf2f6..94356bf8 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -73,25 +73,33 @@ static struct
 	inet_prefix dst;
 } filter;
 
+static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
+{
+	__u32 table = frh->table;
+	if (tb[RTA_TABLE])
+		table = rta_getattr_u32(tb[RTA_TABLE]);
+	return table;
+}
+
 static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 {
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	__u32 table;
 
-	if (preferred_family != AF_UNSPEC && r->rtm_family != preferred_family)
+	if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
 		return false;
 
 	if (filter.prefmask &&
 	    filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
 		return false;
-	if (filter.not && !(r->rtm_flags & FIB_RULE_INVERT))
+	if (filter.not && !(frh->flags & FIB_RULE_INVERT))
 		return false;
 
 	if (filter.src.family) {
 		inet_prefix *f_src = &filter.src;
 
-		if (f_src->family != r->rtm_family ||
-		    f_src->bitlen > r->rtm_src_len)
+		if (f_src->family != frh->family ||
+		    f_src->bitlen > frh->src_len)
 			return false;
 
 		if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
@@ -101,15 +109,15 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 	if (filter.dst.family) {
 		inet_prefix *f_dst = &filter.dst;
 
-		if (f_dst->family != r->rtm_family ||
-		    f_dst->bitlen > r->rtm_dst_len)
+		if (f_dst->family != frh->family ||
+		    f_dst->bitlen > frh->dst_len)
 			return false;
 
 		if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
 			return false;
 	}
 
-	if (filter.tosmask && filter.tos ^ r->rtm_tos)
+	if (filter.tosmask && filter.tos ^ frh->tos)
 		return false;
 
 	if (filter.fwmark) {
@@ -159,7 +167,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 			return false;
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (filter.tb > 0 && filter.tb ^ table)
 		return false;
 
@@ -169,7 +177,7 @@ static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 {
 	FILE *fp = (FILE *)arg;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	int host_len = -1;
 	__u32 table;
@@ -180,13 +188,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
 		return 0;
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
-	host_len = af_bit_len(r->rtm_family);
+	host_len = af_bit_len(frh->family);
 
 	if (!filter_nlmsg(n, tb, host_len))
 		return 0;
@@ -200,41 +208,41 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 	else
 		fprintf(fp, "0:\t");
 
-	if (r->rtm_flags & FIB_RULE_INVERT)
+	if (frh->flags & FIB_RULE_INVERT)
 		fprintf(fp, "not ");
 
 	if (tb[FRA_SRC]) {
-		if (r->rtm_src_len != host_len) {
+		if (frh->src_len != host_len) {
 			fprintf(fp, "from %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_SRC]),
-				r->rtm_src_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_SRC]),
+				frh->src_len);
 		} else {
 			fprintf(fp, "from %s ",
-				format_host_rta(r->rtm_family, tb[FRA_SRC]));
+				format_host_rta(frh->family, tb[FRA_SRC]));
 		}
-	} else if (r->rtm_src_len) {
-		fprintf(fp, "from 0/%d ", r->rtm_src_len);
+	} else if (frh->src_len) {
+		fprintf(fp, "from 0/%d ", frh->src_len);
 	} else {
 		fprintf(fp, "from all ");
 	}
 
 	if (tb[FRA_DST]) {
-		if (r->rtm_dst_len != host_len) {
+		if (frh->dst_len != host_len) {
 			fprintf(fp, "to %s/%u ",
-				rt_addr_n2a_rta(r->rtm_family, tb[FRA_DST]),
-				r->rtm_dst_len);
+				rt_addr_n2a_rta(frh->family, tb[FRA_DST]),
+				frh->dst_len);
 		} else {
 			fprintf(fp, "to %s ",
-				format_host_rta(r->rtm_family, tb[FRA_DST]));
+				format_host_rta(frh->family, tb[FRA_DST]));
 		}
-	} else if (r->rtm_dst_len) {
-		fprintf(fp, "to 0/%d ", r->rtm_dst_len);
+	} else if (frh->dst_len) {
+		fprintf(fp, "to 0/%d ", frh->dst_len);
 	}
 
-	if (r->rtm_tos) {
+	if (frh->tos) {
 		SPRINT_BUF(b1);
 		fprintf(fp, "tos %s ",
-			rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
+			rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
 	}
 
 	if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
@@ -252,13 +260,13 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 
 	if (tb[FRA_IFNAME]) {
 		fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME]));
-		if (r->rtm_flags & FIB_RULE_IIF_DETACHED)
+		if (frh->flags & FIB_RULE_IIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
 	if (tb[FRA_OIFNAME]) {
 		fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME]));
-		if (r->rtm_flags & FIB_RULE_OIF_DETACHED)
+		if (frh->flags & FIB_RULE_OIF_DETACHED)
 			fprintf(fp, "[detached] ");
 	}
 
@@ -273,7 +281,7 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 		fprintf(fp, "uidrange %u-%u ", r->start, r->end);
 	}
 
-	table = rtm_get_table(r, tb);
+	table = frh_get_table(frh, tb);
 	if (table) {
 		fprintf(fp, "lookup %s ",
 			rtnl_rttable_n2a(table, b1, sizeof(b1)));
@@ -308,26 +316,26 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
 	}
 
-	if (r->rtm_type == RTN_NAT) {
+	if (frh->action == RTN_NAT) {
 		if (tb[RTA_GATEWAY]) {
 			fprintf(fp, "map-to %s ",
-				format_host_rta(r->rtm_family,
+				format_host_rta(frh->family,
 						tb[RTA_GATEWAY]));
 		} else
 			fprintf(fp, "masquerade");
-	} else if (r->rtm_type == FR_ACT_GOTO) {
+	} else if (frh->action == FR_ACT_GOTO) {
 		fprintf(fp, "goto ");
 		if (tb[FRA_GOTO])
 			fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO]));
 		else
 			fprintf(fp, "none");
-		if (r->rtm_flags & FIB_RULE_UNRESOLVED)
+		if (frh->flags & FIB_RULE_UNRESOLVED)
 			fprintf(fp, " [unresolved]");
-	} else if (r->rtm_type == FR_ACT_NOP)
+	} else if (frh->action == FR_ACT_NOP)
 		fprintf(fp, "nop");
-	else if (r->rtm_type != RTN_UNICAST)
+	else if (frh->action != FR_ACT_TO_TBL)
 		fprintf(fp, "%s",
-			rtnl_rtntype_n2a(r->rtm_type,
+			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
 	fprintf(fp, "\n");
@@ -373,15 +381,15 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 		      void *arg)
 {
 	struct rtnl_handle rth2;
-	struct rtmsg *r = NLMSG_DATA(n);
+	struct fib_rule_hdr *frh = NLMSG_DATA(n);
 	int len = n->nlmsg_len;
 	struct rtattr *tb[FRA_MAX+1];
 
-	len -= NLMSG_LENGTH(sizeof(*r));
+	len -= NLMSG_LENGTH(sizeof(*frh));
 	if (len < 0)
 		return -1;
 
-	parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len);
+	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
@@ -577,21 +585,19 @@ static int iprule_modify(int cmd, int argc, char **argv)
 	__u32 tid = 0;
 	struct {
 		struct nlmsghdr	n;
-		struct rtmsg		r;
+		struct fib_rule_hdr	frh;
 		char			buf[1024];
 	} req = {
 		.n.nlmsg_type = cmd,
-		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
+		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
 		.n.nlmsg_flags = NLM_F_REQUEST,
-		.r.rtm_family = preferred_family,
-		.r.rtm_protocol = RTPROT_BOOT,
-		.r.rtm_scope = RT_SCOPE_UNIVERSE,
-		.r.rtm_type = RTN_UNSPEC,
+		.frh.family = preferred_family,
+		.frh.action = FR_ACT_UNSPEC,
 	};
 
 	if (cmd == RTM_NEWRULE) {
 		req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
-		req.r.rtm_type = RTN_UNICAST;
+		req.frh.action = FR_ACT_TO_TBL;
 	}
 
 	if (cmd == RTM_DELRULE && argc == 0) {
@@ -601,21 +607,21 @@ static int iprule_modify(int cmd, int argc, char **argv)
 
 	while (argc > 0) {
 		if (strcmp(*argv, "not") == 0) {
-			req.r.rtm_flags |= FIB_RULE_INVERT;
+			req.frh.flags |= FIB_RULE_INVERT;
 		} else if (strcmp(*argv, "from") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_src_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.src_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_SRC,
 				  &dst.data, dst.bytelen);
 		} else if (strcmp(*argv, "to") == 0) {
 			inet_prefix dst;
 
 			NEXT_ARG();
-			get_prefix(&dst, *argv, req.r.rtm_family);
-			req.r.rtm_dst_len = dst.bitlen;
+			get_prefix(&dst, *argv, req.frh.family);
+			req.frh.dst_len = dst.bitlen;
 			addattr_l(&req.n, sizeof(req), FRA_DST,
 				  &dst.data, dst.bytelen);
 		} else if (matches(*argv, "preference") == 0 ||
@@ -634,7 +640,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			NEXT_ARG();
 			if (rtnl_dsfield_a2n(&tos, *argv))
 				invarg("TOS value is invalid\n", *argv);
-			req.r.rtm_tos = tos;
+			req.frh.tos = tos;
 		} else if (strcmp(*argv, "fwmark") == 0) {
 			char *slash;
 			__u32 fwmark, fwmask;
@@ -667,9 +673,9 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (rtnl_rttable_a2n(&tid, *argv))
 				invarg("invalid table ID\n", *argv);
 			if (tid < 256)
-				req.r.rtm_table = tid;
+				req.frh.table = tid;
 			else {
-				req.r.rtm_table = RT_TABLE_UNSPEC;
+				req.frh.table = RT_TABLE_UNSPEC;
 				addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
 			}
 			table_ok = 1;
@@ -724,7 +730,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			fprintf(stderr, "Warning: route NAT is deprecated\n");
 			addattr32(&req.n, sizeof(req), RTA_GATEWAY,
 				  get_addr32(*argv));
-			req.r.rtm_type = RTN_NAT;
+			req.frh.action = RTN_NAT;
 		} else {
 			int type;
 
@@ -746,7 +752,7 @@ static int iprule_modify(int cmd, int argc, char **argv)
 				type = FR_ACT_NOP;
 			else if (rtnl_rtntype_a2n(&type, *argv))
 				invarg("Failed to parse rule type", *argv);
-			req.r.rtm_type = type;
+			req.frh.action = type;
 			table_ok = 1;
 		}
 		argc--;
@@ -759,11 +765,11 @@ static int iprule_modify(int cmd, int argc, char **argv)
 		return -EINVAL;
 	}
 
-	if (req.r.rtm_family == AF_UNSPEC)
-		req.r.rtm_family = AF_INET;
+	if (req.frh.family == AF_UNSPEC)
+		req.frh.family = AF_INET;
 
 	if (!table_ok && cmd == RTM_NEWRULE)
-		req.r.rtm_table = RT_TABLE_MAIN;
+		req.frh.table = RT_TABLE_MAIN;
 
 	if (rtnl_talk(&rth, &req.n, NULL) < 0)
 		return -2;
-- 
2.14.3

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

* [PATCH v4 iproute2-next 2/3] ip: Display ip rule protocol used
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (9 preceding siblings ...)
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
@ 2018-02-28 23:43 ` Donald Sharp
  2018-02-28 23:44 ` [PATCH v4 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-28 23:43 UTC (permalink / raw)
  To: netdev, dsahern

Modify 'ip rule' command to notice when the kernel passes
to us the originating protocol.

Add code to allow the `ip rule flush protocol XXX`
command to be accepted and properly handled.

Modify the documentation to reflect these code changes.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c        | 38 ++++++++++++++++++++++++++++++++++----
 man/man8/ip-rule.8 | 18 +++++++++++++++++-
 2 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/ip/iprule.c b/ip/iprule.c
index 94356bf8..8120520e 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -47,6 +47,7 @@ static void usage(void)
 		"            [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
 		"            [ uidrange NUMBER-NUMBER ]\n"
 		"ACTION := [ table TABLE_ID ]\n"
+		"          [ protocol PROTO ]\n"
 		"          [ nat ADDRESS ]\n"
 		"          [ realms [SRCREALM/]DSTREALM ]\n"
 		"          [ goto NUMBER ]\n"
@@ -71,6 +72,8 @@ static struct
 	struct fib_rule_uid_range range;
 	inet_prefix src;
 	inet_prefix dst;
+	int protocol;
+	int protocolmask;
 } filter;
 
 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
@@ -338,6 +341,16 @@ int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
 			rtnl_rtntype_n2a(frh->action,
 					 b1, sizeof(b1)));
 
+	if (tb[FRA_PROTOCOL]) {
+		__u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+		if ((protocol && protocol != RTPROT_KERNEL) ||
+		    show_details > 0) {
+			fprintf(fp, " proto %s ",
+				rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
+		}
+	}
+
 	fprintf(fp, "\n");
 	fflush(fp);
 	return 0;
@@ -391,6 +404,13 @@ static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
 
 	parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
 
+	if (tb[FRA_PROTOCOL]) {
+		__u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
+
+		if ((filter.protocol ^ protocol) & filter.protocolmask)
+			return 0;
+	}
+
 	if (tb[FRA_PRIORITY]) {
 		n->nlmsg_type = RTM_DELRULE;
 		n->nlmsg_flags = NLM_F_REQUEST;
@@ -415,9 +435,8 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 	if (af == AF_UNSPEC)
 		af = AF_INET;
 
-	if (action != IPRULE_LIST && argc > 0) {
-		fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n",
-				action == IPRULE_SAVE ? "save" : "flush");
+	if (action == IPRULE_SAVE && argc > 0) {
+		fprintf(stderr, "\"ip rule save\" does not take any arguments.\n");
 		return -1;
 	}
 
@@ -508,7 +527,18 @@ static int iprule_list_flush_or_save(int argc, char **argv, int action)
 			NEXT_ARG();
 			if (get_prefix(&filter.src, *argv, af))
 				invarg("from value is invalid\n", *argv);
-		} else {
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 prot;
+			NEXT_ARG();
+			filter.protocolmask = -1;
+			if (rtnl_rtprot_a2n(&prot, *argv)) {
+				if (strcmp(*argv, "all") != 0)
+					invarg("invalid \"protocol\"\n", *argv);
+				prot = 0;
+				filter.protocolmask = 0;
+			}
+			filter.protocol = prot;
+		} else{
 			if (matches(*argv, "dst") == 0 ||
 			    matches(*argv, "to") == 0) {
 				NEXT_ARG();
diff --git a/man/man8/ip-rule.8 b/man/man8/ip-rule.8
index a5c47981..7cf8fd9a 100644
--- a/man/man8/ip-rule.8
+++ b/man/man8/ip-rule.8
@@ -50,6 +50,8 @@ ip-rule \- routing policy database management
 .IR ACTION " := [ "
 .B  table
 .IR TABLE_ID " ] [ "
+.B  protocol
+.IR PROTO " ] [ "
 .B  nat
 .IR ADDRESS " ] [ "
 .B realms
@@ -240,6 +242,10 @@ The options preference and order are synonyms with priority.
 the routing table identifier to lookup if the rule selector matches.
 It is also possible to use lookup instead of table.
 
+.TP
+.BI protocol " PROTO"
+the routing protocol who installed the rule in question.  As an example when zebra installs a rule it would get RTPROT_ZEBRA as the installing protocol.
+
 .TP
 .BI suppress_prefixlength " NUMBER"
 reject routing decisions that have a prefix length of NUMBER or less.
@@ -275,7 +281,11 @@ updates, it flushes the routing cache with
 .RE
 .TP
 .B ip rule flush - also dumps all the deleted rules.
-This command has no arguments.
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
 .TP
 .B ip rule show - list rules
 This command has no arguments.
@@ -283,6 +293,12 @@ The options list or lst are synonyms with show.
 
 .TP
 .B ip rule save
+.RS
+.TP
+.BI protocol " PROTO"
+Select the originating protocol.
+.RE
+.TP
 save rules table information to stdout
 .RS
 This command behaves like
-- 
2.14.3

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

* [PATCH v4 iproute2-next 3/3] ip: Allow rules to accept a specified protocol
  2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
                   ` (10 preceding siblings ...)
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
@ 2018-02-28 23:44 ` Donald Sharp
  11 siblings, 0 replies; 17+ messages in thread
From: Donald Sharp @ 2018-02-28 23:44 UTC (permalink / raw)
  To: netdev, dsahern

Allow the specification of a protocol when the user
adds/modifies/deletes a rule.

Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
---
 ip/iprule.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ip/iprule.c b/ip/iprule.c
index 8120520e..6fdc9b5e 100644
--- a/ip/iprule.c
+++ b/ip/iprule.c
@@ -697,6 +697,13 @@ static int iprule_modify(int cmd, int argc, char **argv)
 			if (get_rt_realms_or_raw(&realm, *argv))
 				invarg("invalid realms\n", *argv);
 			addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
+		} else if (matches(*argv, "protocol") == 0) {
+			__u32 proto;
+
+			NEXT_ARG();
+			if (rtnl_rtprot_a2n(&proto, *argv))
+				invarg("\"protocol\" value is invalid\n", *argv);
+			addattr8(&req.n, sizeof(req), FRA_PROTOCOL, proto);
 		} else if (matches(*argv, "table") == 0 ||
 			   strcmp(*argv, "lookup") == 0) {
 			NEXT_ARG();
-- 
2.14.3

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

* Re: [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol
  2018-02-28 23:43 ` [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
@ 2018-03-01  3:46   ` David Ahern
  0 siblings, 0 replies; 17+ messages in thread
From: David Ahern @ 2018-03-01  3:46 UTC (permalink / raw)
  To: Donald Sharp, netdev

On 2/28/18 4:43 PM, Donald Sharp wrote:
> Fix iprule.c to use the actual `struct fib_rule_hdr` and to
> allow the end user to see and use the protocol keyword
> for rule manipulation.
> 
> v2: Rearrange and code changes as per David Ahern
> v3: Fix some missed RTN_XXX to appropriate FR_XX and doc changes
> v4: Cleanup some code, fix 'ip rule save' no parameters and doc changes
> 
> Donald Sharp (3):
>   ip: Use the `struct fib_rule_hdr` for rules
>   ip: Display ip rule protocol used
>   ip: Allow rules to accept a specified protocol
> 
>  include/uapi/linux/fib_rules.h |   1 +
>  ip/iprule.c                    | 173 +++++++++++++++++++++++++----------------
>  man/man8/ip-rule.8             |  18 ++++-
>  3 files changed, 126 insertions(+), 66 deletions(-)
> 

Applied to iproute2-next.

Please submit a followup for listing with the protocol as a filter.

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

end of thread, other threads:[~2018-03-01  3:46 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-21  1:53 [PATCH iproute2-next 0/4] Allow 'ip rule' command to use protocol Donald Sharp
2018-02-22  2:12 ` [PATCH v2 iproute2-next 0/3] " Donald Sharp
2018-02-22  2:12 ` [PATCH v2 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
2018-02-22 17:23   ` David Ahern
2018-02-22  2:12 ` [PATCH v2 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
2018-02-22 21:28   ` David Ahern
2018-02-22  2:12 ` [PATCH v2 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
2018-02-23 19:32 ` [PATCH v3 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
2018-02-23 19:32 ` [PATCH v3 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
2018-02-23 19:32 ` [PATCH v3 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
2018-02-26 21:35   ` David Ahern
2018-02-23 19:32 ` [PATCH v3 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp
2018-02-28 23:43 ` [PATCH v4 iproute2-next 0/3] Allow 'ip rule' command to use protocol Donald Sharp
2018-03-01  3:46   ` David Ahern
2018-02-28 23:43 ` [PATCH v4 iproute2-next 1/3] ip: Use the `struct fib_rule_hdr` for rules Donald Sharp
2018-02-28 23:43 ` [PATCH v4 iproute2-next 2/3] ip: Display ip rule protocol used Donald Sharp
2018-02-28 23:44 ` [PATCH v4 iproute2-next 3/3] ip: Allow rules to accept a specified protocol Donald Sharp

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.