diff options
| author | Jafar Al-Gharaibeh <Jafaral@users.noreply.github.com> | 2021-07-27 15:09:29 -0500 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-27 15:09:29 -0500 | 
| commit | 213d980ff904a30565e1b5fcabafabe49143d35c (patch) | |
| tree | 4cb4bca4547575138df357487c701c3e6e3a37b3 | |
| parent | 42ac787226bc3b83aa75f6e2040b2808c72b23ec (diff) | |
| parent | 99ed46d964bc8634d5f73e48f2eae5feddac6fd6 (diff) | |
Merge pull request #9007 from donaldsharp/pbr_stuff
add ability to match on proto to pbr
| -rw-r--r-- | bgpd/bgp_zebra.c | 1 | ||||
| -rw-r--r-- | doc/user/pbr.rst | 15 | ||||
| -rw-r--r-- | lib/pbr.h | 6 | ||||
| -rw-r--r-- | pbrd/pbr_map.h | 11 | ||||
| -rw-r--r-- | pbrd/pbr_vty.c | 92 | ||||
| -rw-r--r-- | pbrd/pbr_zebra.c | 5 | ||||
| -rw-r--r-- | zebra/kernel_netlink.c | 6 | ||||
| -rw-r--r-- | zebra/kernel_netlink.h | 2 | ||||
| -rw-r--r-- | zebra/rule_netlink.c | 34 | ||||
| -rw-r--r-- | zebra/zapi_msg.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_dplane.c | 16 | ||||
| -rw-r--r-- | zebra/zebra_dplane.h | 2 | ||||
| -rw-r--r-- | zebra/zebra_pbr.c | 9 | 
13 files changed, 184 insertions, 19 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 2c7c087855..24652ee93a 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2576,6 +2576,7 @@ static void bgp_encode_pbr_rule_action(struct stream *s,  		stream_putl(s, pbr->unique);  	else  		stream_putl(s, pbra->unique); +	stream_putc(s, 0); /* ip protocol being used */  	if (pbr && pbr->flags & MATCH_IP_SRC_SET)  		memcpy(&pfx, &(pbr->src), sizeof(struct prefix));  	else { diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index 77134a7704..e59ed10896 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -117,6 +117,21 @@ end destination.     both v4 and v6 prefixes.  This command is used in conjunction of the     :clicmd:`match src-ip PREFIX` command for matching. +.. clicmd:: match src-port (1-65535) + +   When a incoming packet matches the source port specified, take the +   packet and forward according to the nexthops specified. + +.. clicmd:: match dst-port (1-65535) + +   When a incoming packet matches the destination port specified, take the +   packet and forward according to the nexthops specified. + +.. clicmd:: match ip-protocol [tcp|udp] + +   When a incoming packet matches the specified ip protocol, take the +   packet and forward according to the nexthops specified. +  .. clicmd:: match mark (1-4294967295)     Select the mark to match.  This is a linux only command and if attempted @@ -49,7 +49,8 @@ struct pbr_filter {  #define PBR_FILTER_PROTO		(1 << 5)  #define PBR_FILTER_SRC_PORT_RANGE	(1 << 6)  #define PBR_FILTER_DST_PORT_RANGE	(1 << 7) -#define PBR_FILTER_DSFIELD			(1 << 8) +#define PBR_FILTER_DSFIELD		(1 << 8) +#define PBR_FILTER_IP_PROTOCOL		(1 << 9)  #define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */  #define PBR_DSFIELD_ECN (0x03)	/* Lower 2 bits of DS field: BCN */ @@ -67,6 +68,9 @@ struct pbr_filter {  	/* Filter with fwmark */  	uint32_t fwmark; + +	/* Filter with the ip protocol */ +	uint8_t ip_proto;  };  /* diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index caeadb0644..694b915f48 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -85,6 +85,17 @@ struct pbr_map_sequence {  	uint32_t ruleno;  	/* +	 * src and dst ports +	 */ +	uint16_t src_prt; +	uint16_t dst_prt; + +	/* +	 * The ip protocol we want to match on +	 */ +	uint8_t ip_proto; + +	/*  	 * Our policy Catchers  	 */  	struct prefix *src; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 3d56fc3daa..730f965cd0 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -193,6 +193,76 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,  	return CMD_SUCCESS;  } +DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd, +      "[no] match ip-protocol [tcp|udp]$ip_proto", +      NO_STR +      "Match the rest of the command\n" +      "Choose an ip-protocol\n" +      "Match on tcp flows\n" +      "Match on udp flows\n") +{ +	struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); +	struct protoent *p; + +	if (!no) { +		p = getprotobyname(ip_proto); +		if (!p) { +			vty_out(vty, "Unable to convert %s to proto id\n", +				ip_proto); +			return CMD_WARNING; +		} + +		pbrms->ip_proto = p->p_proto; +	} else +		pbrms->ip_proto = 0; + +	return CMD_SUCCESS; +} + +DEFPY(pbr_map_match_src_port, pbr_map_match_src_port_cmd, +      "[no] match src-port (1-65535)$port", +      NO_STR +      "Match the rest of the command\n" +      "Choose the source port to use\n" +      "The Source Port\n") +{ +	struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + +	if (!no) { +		if (pbrms->src_prt == port) +			return CMD_SUCCESS; +		else +			pbrms->src_prt = port; +	} else +		pbrms->src_prt = 0; + +	pbr_map_check(pbrms, true); + +	return CMD_SUCCESS; +} + +DEFPY(pbr_map_match_dst_port, pbr_map_match_dst_port_cmd, +      "[no] match dst-port (1-65535)$port", +      NO_STR +      "Match the rest of the command\n" +      "Choose the destination port to use\n" +      "The Destination Port\n") +{ +	struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + +	if (!no) { +		if (pbrms->dst_prt == port) +			return CMD_SUCCESS; +		else +			pbrms->dst_prt = port; +	} else +		pbrms->dst_prt = 0; + +	pbr_map_check(pbrms, true); + +	return CMD_SUCCESS; +} +  DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,        "[no] match dscp DSCP$dscp",        NO_STR @@ -674,6 +744,13 @@ static void vty_show_pbrms(struct vty *vty,  			pbrms->installed ? "yes" : "no",  			pbrms->reason ? rbuf : "Valid"); +	if (pbrms->ip_proto) { +		struct protoent *p; + +		p = getprotobynumber(pbrms->ip_proto); +		vty_out(vty, "        IP Protocol Match: %s\n", p->p_name); +	} +  	if (pbrms->src)  		vty_out(vty, "        SRC Match: %pFX\n", pbrms->src);  	if (pbrms->dst) @@ -1079,6 +1156,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,  	if (pbrms->dst)  		vty_out(vty, " match dst-ip %pFX\n", pbrms->dst); +	if (pbrms->src_prt) +		vty_out(vty, " match src-port %u\n", pbrms->src_prt); +	if (pbrms->dst_prt) +		vty_out(vty, " match dst-port %u\n", pbrms->dst_prt); + +	if (pbrms->ip_proto) { +		struct protoent *p; + +		p = getprotobynumber(pbrms->ip_proto); +		vty_out(vty, " match ip-protocol %s\n", p->p_name); +	} +  	if (pbrms->dsfield & PBR_DSFIELD_DSCP)  		vty_out(vty, " match dscp %u\n",  			(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2); @@ -1169,6 +1258,9 @@ void pbr_vty_init(void)  	install_element(CONFIG_NODE, &pbr_set_table_range_cmd);  	install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd);  	install_element(INTERFACE_NODE, &pbr_policy_cmd); +	install_element(PBRMAP_NODE, &pbr_map_match_ip_proto_cmd); +	install_element(PBRMAP_NODE, &pbr_map_match_src_port_cmd); +	install_element(PBRMAP_NODE, &pbr_map_match_dst_port_cmd);  	install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);  	install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);  	install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index fc5303c9d8..28def509d5 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -534,10 +534,11 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,  	stream_putl(s, pbrms->seqno);  	stream_putl(s, pbrms->ruleno);  	stream_putl(s, pbrms->unique); +	stream_putc(s, pbrms->ip_proto); /* The ip_proto */  	pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family); -	stream_putw(s, 0);  /* src port */ +	stream_putw(s, pbrms->src_prt);  	pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family); -	stream_putw(s, 0);  /* dst port */ +	stream_putw(s, pbrms->dst_prt);  	stream_putc(s, pbrms->dsfield);  	stream_putl(s, pbrms->mark); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 8b631a3726..011883649d 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -550,6 +550,12 @@ bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type,  	return true;  } +bool nl_attr_put8(struct nlmsghdr *n, unsigned int maxlen, int type, +		  uint8_t data) +{ +	return nl_attr_put(n, maxlen, type, &data, sizeof(uint8_t)); +} +  bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type,  		   uint16_t data)  { diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index a7b152b31b..d8e5671b72 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -38,6 +38,8 @@ extern "C" {   */  extern bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type,  			const void *data, unsigned int alen); +extern bool nl_attr_put8(struct nlmsghdr *n, unsigned int maxlen, int type, +			 uint8_t data);  extern bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type,  			  uint16_t data);  extern bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type, diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 08a675ef3a..b651edd8f9 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -58,12 +58,11 @@   * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer   * or the number of bytes written to buf.   */ -static ssize_t -netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx, -			uint32_t filter_bm, uint32_t priority, uint32_t table, -			const struct prefix *src_ip, -			const struct prefix *dst_ip, uint32_t fwmark, -			uint8_t dsfield, void *buf, size_t buflen) +static ssize_t netlink_rule_msg_encode( +	int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm, +	uint32_t priority, uint32_t table, const struct prefix *src_ip, +	const struct prefix *dst_ip, uint32_t fwmark, uint8_t dsfield, +	uint8_t ip_protocol, void *buf, size_t buflen)  {  	uint8_t protocol = RTPROT_ZEBRA;  	int family; @@ -136,6 +135,10 @@ netlink_rule_msg_encode(int cmd, const struct zebra_dplane_ctx *ctx,  	if (filter_bm & PBR_FILTER_DSFIELD)  		req->frh.tos = dsfield; +	/* protocol to match on */ +	if (filter_bm & PBR_FILTER_IP_PROTOCOL) +		nl_attr_put8(&req->n, buflen, FRA_IP_PROTO, ip_protocol); +  	/* Route table to use to forward, if filter criteria matches. */  	if (table < 256)  		req->frh.table = table; @@ -168,7 +171,8 @@ static ssize_t netlink_rule_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf,  		dplane_ctx_rule_get_table(ctx), dplane_ctx_rule_get_src_ip(ctx),  		dplane_ctx_rule_get_dst_ip(ctx),  		dplane_ctx_rule_get_fwmark(ctx), -		dplane_ctx_rule_get_dsfield(ctx), buf, buflen); +		dplane_ctx_rule_get_dsfield(ctx), +		dplane_ctx_rule_get_ipproto(ctx), buf, buflen);  }  static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx, @@ -181,7 +185,8 @@ static ssize_t netlink_oldrule_msg_encoder(struct zebra_dplane_ctx *ctx,  		dplane_ctx_rule_get_old_src_ip(ctx),  		dplane_ctx_rule_get_old_dst_ip(ctx),  		dplane_ctx_rule_get_old_fwmark(ctx), -		dplane_ctx_rule_get_old_dsfield(ctx), buf, buflen); +		dplane_ctx_rule_get_old_dsfield(ctx), +		dplane_ctx_rule_get_old_ipproto(ctx), buf, buflen);  }  /* Public functions */ @@ -236,6 +241,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)  	char *ifname;  	struct zebra_pbr_rule rule = {};  	uint8_t proto = 0; +	uint8_t ip_proto = 0;  	/* Basic validation followed by extracting attributes. */  	if (h->nlmsg_type != RTM_NEWRULE && h->nlmsg_type != RTM_DELRULE) @@ -312,6 +318,9 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)  	if (tb[FRA_PROTOCOL])  		proto = *(uint8_t *)RTA_DATA(tb[FRA_PROTOCOL]); +	if (tb[FRA_IP_PROTO]) +		ip_proto = *(uint8_t *)RTA_DATA(tb[FRA_IP_PROTO]); +  	ifname = (char *)RTA_DATA(tb[FRA_IFNAME]);  	strlcpy(rule.ifname, ifname, sizeof(rule.ifname)); @@ -326,7 +335,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)  			ret = dplane_pbr_rule_delete(&rule);  			zlog_debug( -				"%s: %s leftover rule: family %s IF %s Pref %u Src %pFX Dst %pFX Table %u", +				"%s: %s leftover rule: family %s IF %s Pref %u Src %pFX Dst %pFX Table %u ip-proto: %u",  				__func__,  				((ret == ZEBRA_DPLANE_REQUEST_FAILURE)  					 ? "Failed to remove" @@ -334,7 +343,7 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)  				nl_family_to_str(frh->family), rule.ifname,  				rule.rule.priority, &rule.rule.filter.src_ip,  				&rule.rule.filter.dst_ip, -				rule.rule.action.table); +				rule.rule.action.table, ip_proto);  		}  		/* TBD */ @@ -349,11 +358,12 @@ int netlink_rule_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)  	if (IS_ZEBRA_DEBUG_KERNEL)  		zlog_debug( -			"Rx %s family %s IF %s Pref %u Src %pFX Dst %pFX Table %u", +			"Rx %s family %s IF %s Pref %u Src %pFX Dst %pFX Table %u ip-proto: %u",  			nl_msg_type_to_str(h->nlmsg_type),  			nl_family_to_str(frh->family), rule.ifname,  			rule.rule.priority, &rule.rule.filter.src_ip, -			&rule.rule.filter.dst_ip, rule.rule.action.table); +			&rule.rule.filter.dst_ip, rule.rule.action.table, +			ip_proto);  	return kernel_pbr_rule_del(&rule);  } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 5b2b1cc26f..27fb5d7c22 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3131,6 +3131,7 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)  		STREAM_GETL(s, zpr.rule.seq);  		STREAM_GETL(s, zpr.rule.priority);  		STREAM_GETL(s, zpr.rule.unique); +		STREAM_GETC(s, zpr.rule.filter.ip_proto);  		STREAM_GETC(s, zpr.rule.filter.src_ip.family);  		STREAM_GETC(s, zpr.rule.filter.src_ip.prefixlen);  		STREAM_GET(&zpr.rule.filter.src_ip.u.prefix, s, @@ -3164,6 +3165,9 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)  		if (zpr.rule.filter.dsfield)  			zpr.rule.filter.filter_bm |= PBR_FILTER_DSFIELD; +		if (zpr.rule.filter.ip_proto) +			zpr.rule.filter.filter_bm |= PBR_FILTER_IP_PROTOCOL; +  		if (zpr.rule.filter.fwmark)  			zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 1217ed915a..2a30fc6eef 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -259,6 +259,7 @@ struct dplane_ctx_rule {  	uint8_t dsfield;  	struct prefix src_ip;  	struct prefix dst_ip; +	uint8_t ip_proto;  	char ifname[INTERFACE_NAMSIZ + 1];  }; @@ -1929,6 +1930,20 @@ uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx)  	return ctx->u.rule.old.fwmark;  } +uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx) +{ +	DPLANE_CTX_VALID(ctx); + +	return ctx->u.rule.new.ip_proto; +} + +uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx) +{ +	DPLANE_CTX_VALID(ctx); + +	return ctx->u.rule.old.ip_proto; +} +  uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx)  {  	DPLANE_CTX_VALID(ctx); @@ -2636,6 +2651,7 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule,  	dplane_rule->filter_bm = rule->rule.filter.filter_bm;  	dplane_rule->fwmark = rule->rule.filter.fwmark;  	dplane_rule->dsfield = rule->rule.filter.dsfield; +	dplane_rule->ip_proto = rule->rule.filter.ip_proto;  	prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip);  	prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip);  	strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index e091655a48..5ec1bd5807 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -493,6 +493,8 @@ uint32_t dplane_ctx_rule_get_fwmark(const struct zebra_dplane_ctx *ctx);  uint32_t dplane_ctx_rule_get_old_fwmark(const struct zebra_dplane_ctx *ctx);  uint8_t dplane_ctx_rule_get_dsfield(const struct zebra_dplane_ctx *ctx);  uint8_t dplane_ctx_rule_get_old_dsfield(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_rule_get_ipproto(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_rule_get_old_ipproto(const struct zebra_dplane_ctx *ctx);  const struct prefix *  dplane_ctx_rule_get_src_ip(const struct zebra_dplane_ctx *ctx);  const struct prefix * diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 7bcd097371..3607110aa2 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -166,10 +166,8 @@ uint32_t zebra_pbr_rules_hash_key(const void *arg)  			   rule->rule.action.table,  			   prefix_hash_key(&rule->rule.filter.src_ip)); -	if (rule->rule.filter.fwmark) -		key = jhash_2words(rule->rule.filter.fwmark, rule->vrf_id, key); -	else -		key = jhash_1word(rule->vrf_id, key); +	key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id, +			   rule->rule.filter.ip_proto, key);  	key = jhash(rule->ifname, strlen(rule->ifname), key); @@ -207,6 +205,9 @@ bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2)  	if (r1->rule.filter.fwmark != r2->rule.filter.fwmark)  		return false; +	if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto) +		return false; +  	if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip))  		return false;  | 
