Re: [PATCH net-next 1/5] net: fib_rules: support for match on ip_proto, sport and dport

2018-02-25 Thread Roopa Prabhu
On Sun, Feb 25, 2018 at 7:08 PM, David Ahern  wrote:
> On 2/24/18 10:44 PM, Roopa Prabhu wrote:
>> From: Roopa Prabhu 
>>
>> uapi for ip_proto, sport and dport range match
>> in fib rules.
>>
>> Signed-off-by: Roopa Prabhu 
>> ---
>>  include/net/fib_rules.h| 31 +-
>>  include/uapi/linux/fib_rules.h |  8 
>>  net/core/fib_rules.c   | 94 
>> +-
>>  3 files changed, 130 insertions(+), 3 deletions(-)
>>
>> diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
>> index b3d2162..6d99202 100644
>> --- a/include/net/fib_rules.h
>> +++ b/include/net/fib_rules.h
>> @@ -11,6 +11,11 @@
>>  #include 
>>  #include 
>>
>> +struct fib_port_range {
>> + __u16 start;
>> + __u16 end;
>
> u16 for kernel headers; __u16 is for uapi.
>

ack,

>> +};
>> +
>>  struct fib_kuid_range {
>>   kuid_t start;
>>   kuid_t end;
>> @@ -27,7 +32,7 @@ struct fib_rule {
>>   u8  action;
>>   u8  l3mdev;
>>   u8  proto;
>> - /* 1 byte hole, try to use */
>> + u8  ip_proto;
>>   u32 target;
>>   __be64  tun_id;
>>   struct fib_rule __rcu   *ctarget;
>> @@ -40,6 +45,8 @@ struct fib_rule {
>>   chariifname[IFNAMSIZ];
>>   charoifname[IFNAMSIZ];
>>   struct fib_kuid_range   uid_range;
>> + struct fib_port_range   sport_range;
>> + struct fib_port_range   dport_range;
>>   struct rcu_head rcu;
>>  };
>>
>> @@ -144,6 +151,28 @@ static inline u32 frh_get_table(struct fib_rule_hdr 
>> *frh, struct nlattr **nla)
>>   return frh->table;
>>  }
>>
>> +static inline bool fib_rule_port_inrange(struct fib_port_range *a,
>> +  __be16 port)
>> +{
>> + if (!a->start)
>> + return true;
>> + return ntohs(port) >= a->start &&
>> + ntohs(port) <= a->end;
>> +}
>> +
>> +static inline bool fib_rule_port_range_valid(const struct fib_port_range *a)
>> +{
>> + return a->start > 0 && a->end < 0x &&
>> + a->start <= a->end;
>> +}
>> +
>> +static inline bool fib_rule_port_range_compare(struct fib_port_range *a,
>> +struct fib_port_range *b)
>> +{
>> + return a->start == b->start &&
>> + a->end == b->end;
>> +}
>> +
>>  struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
>>struct net *);
>>  void fib_rules_unregister(struct fib_rules_ops *);
>> diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
>> index 77d90ae..232df14 100644
>> --- a/include/uapi/linux/fib_rules.h
>> +++ b/include/uapi/linux/fib_rules.h
>> @@ -35,6 +35,11 @@ struct fib_rule_uid_range {
>>   __u32   end;
>>  };
>>
>> +struct fib_rule_port_range {
>> + __u16   start;
>> + __u16   end;
>> +};
>> +
>>  enum {
>>   FRA_UNSPEC,
>>   FRA_DST,/* destination address */
>> @@ -59,6 +64,9 @@ enum {
>>   FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
>>   FRA_UID_RANGE,  /* UID range */
>>   FRA_PROTOCOL,   /* Originator of the rule */
>> + FRA_IP_PROTO,   /* ip proto */
>> + FRA_SPORT_RANGE, /* sport */
>> + FRA_DPORT_RANGE, /* dport */
>>   __FRA_MAX
>>  };
>>
>> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
>> index a6aea80..5008235 100644
>> --- a/net/core/fib_rules.c
>> +++ b/net/core/fib_rules.c
>> @@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
>>   if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
>>   !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
>>   return false;
>> + if (fib_rule_port_range_valid(>sport_range))
>> + return false;
>> + if (fib_rule_port_range_valid(>dport_range))
>> + return false;
>
> Seems like that should be a check that start and end are both not 0.
> Given the uses of fib_rule_port_range_valid, perhaps another helper is
> needed to make this more readable -- e.g., fib_rule_port_range_set --
> which would be used here and fill_rule.

yeah, was trying to not add two helpers. But, i sure can.


>
>
>>   return true;
>>  }
>>  EXPORT_SYMBOL_GPL(fib_rule_matchall);
>> @@ -221,6 +225,12 @@ static int nla_put_uid_range(struct sk_buff *skb, 
>> struct fib_kuid_range *range)
>>   return nla_put(skb, FRA_UID_RANGE, sizeof(out), );
>>  }
>>
>> +static int nla_put_port_range(struct sk_buff *skb, int attrtype,
>> +   struct fib_port_range *range)
>> +{
>> + return nla_put(skb, attrtype, sizeof(*range), range);
>> +}
>> +
>>  static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
>> 

Re: [PATCH net-next 1/5] net: fib_rules: support for match on ip_proto, sport and dport

2018-02-25 Thread David Ahern
On 2/24/18 10:44 PM, Roopa Prabhu wrote:
> From: Roopa Prabhu 
> 
> uapi for ip_proto, sport and dport range match
> in fib rules.
> 
> Signed-off-by: Roopa Prabhu 
> ---
>  include/net/fib_rules.h| 31 +-
>  include/uapi/linux/fib_rules.h |  8 
>  net/core/fib_rules.c   | 94 
> +-
>  3 files changed, 130 insertions(+), 3 deletions(-)
> 
> diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
> index b3d2162..6d99202 100644
> --- a/include/net/fib_rules.h
> +++ b/include/net/fib_rules.h
> @@ -11,6 +11,11 @@
>  #include 
>  #include 
>  
> +struct fib_port_range {
> + __u16 start;
> + __u16 end;

u16 for kernel headers; __u16 is for uapi.

> +};
> +
>  struct fib_kuid_range {
>   kuid_t start;
>   kuid_t end;
> @@ -27,7 +32,7 @@ struct fib_rule {
>   u8  action;
>   u8  l3mdev;
>   u8  proto;
> - /* 1 byte hole, try to use */
> + u8  ip_proto;
>   u32 target;
>   __be64  tun_id;
>   struct fib_rule __rcu   *ctarget;
> @@ -40,6 +45,8 @@ struct fib_rule {
>   chariifname[IFNAMSIZ];
>   charoifname[IFNAMSIZ];
>   struct fib_kuid_range   uid_range;
> + struct fib_port_range   sport_range;
> + struct fib_port_range   dport_range;
>   struct rcu_head rcu;
>  };
>  
> @@ -144,6 +151,28 @@ static inline u32 frh_get_table(struct fib_rule_hdr 
> *frh, struct nlattr **nla)
>   return frh->table;
>  }
>  
> +static inline bool fib_rule_port_inrange(struct fib_port_range *a,
> +  __be16 port)
> +{
> + if (!a->start)
> + return true;
> + return ntohs(port) >= a->start &&
> + ntohs(port) <= a->end;
> +}
> +
> +static inline bool fib_rule_port_range_valid(const struct fib_port_range *a)
> +{
> + return a->start > 0 && a->end < 0x &&
> + a->start <= a->end;
> +}
> +
> +static inline bool fib_rule_port_range_compare(struct fib_port_range *a,
> +struct fib_port_range *b)
> +{
> + return a->start == b->start &&
> + a->end == b->end;
> +}
> +
>  struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
>struct net *);
>  void fib_rules_unregister(struct fib_rules_ops *);
> diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
> index 77d90ae..232df14 100644
> --- a/include/uapi/linux/fib_rules.h
> +++ b/include/uapi/linux/fib_rules.h
> @@ -35,6 +35,11 @@ struct fib_rule_uid_range {
>   __u32   end;
>  };
>  
> +struct fib_rule_port_range {
> + __u16   start;
> + __u16   end;
> +};
> +
>  enum {
>   FRA_UNSPEC,
>   FRA_DST,/* destination address */
> @@ -59,6 +64,9 @@ enum {
>   FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
>   FRA_UID_RANGE,  /* UID range */
>   FRA_PROTOCOL,   /* Originator of the rule */
> + FRA_IP_PROTO,   /* ip proto */
> + FRA_SPORT_RANGE, /* sport */
> + FRA_DPORT_RANGE, /* dport */
>   __FRA_MAX
>  };
>  
> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
> index a6aea80..5008235 100644
> --- a/net/core/fib_rules.c
> +++ b/net/core/fib_rules.c
> @@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
>   if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
>   !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
>   return false;
> + if (fib_rule_port_range_valid(>sport_range))
> + return false;
> + if (fib_rule_port_range_valid(>dport_range))
> + return false;

Seems like that should be a check that start and end are both not 0.
Given the uses of fib_rule_port_range_valid, perhaps another helper is
needed to make this more readable -- e.g., fib_rule_port_range_set --
which would be used here and fill_rule.


>   return true;
>  }
>  EXPORT_SYMBOL_GPL(fib_rule_matchall);
> @@ -221,6 +225,12 @@ static int nla_put_uid_range(struct sk_buff *skb, struct 
> fib_kuid_range *range)
>   return nla_put(skb, FRA_UID_RANGE, sizeof(out), );
>  }
>  
> +static int nla_put_port_range(struct sk_buff *skb, int attrtype,
> +   struct fib_port_range *range)
> +{
> + return nla_put(skb, attrtype, sizeof(*range), range);
> +}
> +
>  static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
> struct flowi *fl, int flags,
> struct fib_lookup_arg *arg)
> @@ -425,6 +435,17 @@ static int rule_exists(struct fib_rules_ops *ops, struct 
> fib_rule_hdr *frh,
>   !uid_eq(r->uid_range.end, rule->uid_range.end))
>   

Re: [PATCH net-next 1/5] net: fib_rules: support for match on ip_proto, sport and dport

2018-02-25 Thread Roopa Prabhu
On Sun, Feb 25, 2018 at 7:04 AM, Nikolay Aleksandrov
 wrote:
> On 25/02/18 07:44, Roopa Prabhu wrote:
>> From: Roopa Prabhu 
>>
>> uapi for ip_proto, sport and dport range match
>> in fib rules.
>>
>> Signed-off-by: Roopa Prabhu 
>> ---
>>  include/net/fib_rules.h| 31 +-
>>  include/uapi/linux/fib_rules.h |  8 
>>  net/core/fib_rules.c   | 94 
>> +-
>>  3 files changed, 130 insertions(+), 3 deletions(-)
>>
>
> You should probably update validate_rulemsg() as well, these aren't added in 
> the per-proto
> policies and nothing validates if the attribute data is actually there. Maybe 
> I'm missing
> something obvious, but it looks like many other FRA_ attributes don't have 
> such checks.


yeah, I added the sport checks there initially and later removed it
since I did not see any of the
other FRA_* attributes there. and then ended up adding it in the
respective rule add and del functions where other attributes
 were validated for consistency. I can submit a follow on patch to
move all FRA_* attribute validations to validate_rulemsg().

I can sure start with the new attribute validation in this series in
validate_rulemsg in v2




>
>> diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
>> index b3d2162..6d99202 100644
>> --- a/include/net/fib_rules.h
>> +++ b/include/net/fib_rules.h
>> @@ -11,6 +11,11 @@
>>  #include 
>>  #include 
>>
>> +struct fib_port_range {
>> + __u16 start;
>> + __u16 end;
>> +};
>> +
>>  struct fib_kuid_range {
>>   kuid_t start;
>>   kuid_t end;
>> @@ -27,7 +32,7 @@ struct fib_rule {
>>   u8  action;
>>   u8  l3mdev;
>>   u8  proto;
>> - /* 1 byte hole, try to use */
>> + u8  ip_proto;
>>   u32 target;
>>   __be64  tun_id;
>>   struct fib_rule __rcu   *ctarget;
>> @@ -40,6 +45,8 @@ struct fib_rule {
>>   chariifname[IFNAMSIZ];
>>   charoifname[IFNAMSIZ];
>>   struct fib_kuid_range   uid_range;
>> + struct fib_port_range   sport_range;
>> + struct fib_port_range   dport_range;
>>   struct rcu_head rcu;
>>  };
>>
>> @@ -144,6 +151,28 @@ static inline u32 frh_get_table(struct fib_rule_hdr 
>> *frh, struct nlattr **nla)
>>   return frh->table;
>>  }
>>
>> +static inline bool fib_rule_port_inrange(struct fib_port_range *a,
>> +  __be16 port)
>> +{
>> + if (!a->start)
>> + return true;
>
> Can start be == 0 ?
> IIUC this check is unnecessary because when you're adding the new rule,
> you do a check for start > 0 so it shouldn't be possible to be 0.
>
>> + return ntohs(port) >= a->start &&
>> + ntohs(port) <= a->end;
>> +}
>> +
>> +static inline bool fib_rule_port_range_valid(const struct fib_port_range *a)
>> +{
>> + return a->start > 0 && a->end < 0x &&
>> + a->start <= a->end;
>
> nit: alignment (also can be on a single line)
>
>> +}
>> +
>> +static inline bool fib_rule_port_range_compare(struct fib_port_range *a,
>> +struct fib_port_range *b)
>> +{
>> + return a->start == b->start &&
>> + a->end == b->end;
>
> nit: alignment (also can be on a single line)
>
>> +}
>> +
>>  struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
>>struct net *);
>>  void fib_rules_unregister(struct fib_rules_ops *);
>> diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
>> index 77d90ae..232df14 100644
>> --- a/include/uapi/linux/fib_rules.h
>> +++ b/include/uapi/linux/fib_rules.h
>> @@ -35,6 +35,11 @@ struct fib_rule_uid_range {
>>   __u32   end;
>>  };
>>
>> +struct fib_rule_port_range {
>> + __u16   start;
>> + __u16   end;
>> +};
>> +
>>  enum {
>>   FRA_UNSPEC,
>>   FRA_DST,/* destination address */
>> @@ -59,6 +64,9 @@ enum {
>>   FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
>>   FRA_UID_RANGE,  /* UID range */
>>   FRA_PROTOCOL,   /* Originator of the rule */
>> + FRA_IP_PROTO,   /* ip proto */
>> + FRA_SPORT_RANGE, /* sport */
>> + FRA_DPORT_RANGE, /* dport */
>>   __FRA_MAX
>>  };
>>
>> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
>> index a6aea80..5008235 100644
>> --- a/net/core/fib_rules.c
>> +++ b/net/core/fib_rules.c
>> @@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
>>   if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
>>   !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
>>   return false;
>> + if (fib_rule_port_range_valid(>sport_range))
>> + return false;
>> + if 

Re: [PATCH net-next 1/5] net: fib_rules: support for match on ip_proto, sport and dport

2018-02-25 Thread Nikolay Aleksandrov
On 25/02/18 17:04, Nikolay Aleksandrov wrote:
> On 25/02/18 07:44, Roopa Prabhu wrote:
>> From: Roopa Prabhu 
>>
>> uapi for ip_proto, sport and dport range match
>> in fib rules.
>>
>> Signed-off-by: Roopa Prabhu 
>> ---
[snip]
>>  struct rcu_head rcu;
>>  };
>>  
>> @@ -144,6 +151,28 @@ static inline u32 frh_get_table(struct fib_rule_hdr 
>> *frh, struct nlattr **nla)
>>  return frh->table;
>>  }
>>  
>> +static inline bool fib_rule_port_inrange(struct fib_port_range *a,
>> + __be16 port)
>> +{
>> +if (!a->start)
>> +return true;
> 
> Can start be == 0 ?
> IIUC this check is unnecessary because when you're adding the new rule,
> you do a check for start > 0 so it shouldn't be possible to be 0.

Nevermind this comment, I spoke too soon and saw the match later. :-)

> 
>> +return ntohs(port) >= a->start &&
>> +ntohs(port) <= a->end;
>> +}
>> +
>> +static inline bool fib_rule_port_range_valid(const struct fib_port_range *a)
>> +{
>> +return a->start > 0 && a->end < 0x &&
>> +a->start <= a->end;
> 
> nit: alignment (also can be on a single line)
> 
>> +}
>> +
>> +static inline bool fib_rule_port_range_compare(struct fib_port_range *a,
>> +   struct fib_port_range *b)
>> +{
>> +return a->start == b->start &&
>> +a->end == b->end;
> 
> nit: alignment (also can be on a single line)
> 
>> +}
>> +
>>  struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
>>   struct net *);
>>  void fib_rules_unregister(struct fib_rules_ops *);
>> diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
>> index 77d90ae..232df14 100644
>> --- a/include/uapi/linux/fib_rules.h
>> +++ b/include/uapi/linux/fib_rules.h
>> @@ -35,6 +35,11 @@ struct fib_rule_uid_range {
>>  __u32   end;
>>  };
>>  
>> +struct fib_rule_port_range {
>> +__u16   start;
>> +__u16   end;
>> +};
>> +
>>  enum {
>>  FRA_UNSPEC,
>>  FRA_DST,/* destination address */
>> @@ -59,6 +64,9 @@ enum {
>>  FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
>>  FRA_UID_RANGE,  /* UID range */
>>  FRA_PROTOCOL,   /* Originator of the rule */
>> +FRA_IP_PROTO,   /* ip proto */
>> +FRA_SPORT_RANGE, /* sport */
>> +FRA_DPORT_RANGE, /* dport */
>>  __FRA_MAX
>>  };
>>  
>> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
>> index a6aea80..5008235 100644
>> --- a/net/core/fib_rules.c
>> +++ b/net/core/fib_rules.c
>> @@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
>>  if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
>>  !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
>>  return false;
>> +if (fib_rule_port_range_valid(>sport_range))
>> +return false;
>> +if (fib_rule_port_range_valid(>dport_range))
>> +return false;
>>  return true;
>>  }
>>  EXPORT_SYMBOL_GPL(fib_rule_matchall);
>> @@ -221,6 +225,12 @@ static int nla_put_uid_range(struct sk_buff *skb, 
>> struct fib_kuid_range *range)
>>  return nla_put(skb, FRA_UID_RANGE, sizeof(out), );
>>  }
>>  
>> +static int nla_put_port_range(struct sk_buff *skb, int attrtype,
>> +  struct fib_port_range *range)
>> +{
>> +return nla_put(skb, attrtype, sizeof(*range), range);
>> +}
>> +
>>  static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
>>struct flowi *fl, int flags,
>>struct fib_lookup_arg *arg)
>> @@ -425,6 +435,17 @@ static int rule_exists(struct fib_rules_ops *ops, 
>> struct fib_rule_hdr *frh,
>>  !uid_eq(r->uid_range.end, rule->uid_range.end))
>>  continue;
>>  
>> +if (r->ip_proto != rule->ip_proto)
>> +continue;
>> +
>> +if (!fib_rule_port_range_compare(>sport_range,
>> + >sport_range))
>> +continue;
>> +
>> +if (!fib_rule_port_range_compare(>dport_range,
>> + >dport_range))
>> +continue;
>> +
>>  if (!ops->compare(r, frh, tb))
>>  continue;
>>  return 1;
>> @@ -432,6 +453,20 @@ static int rule_exists(struct fib_rules_ops *ops, 
>> struct fib_rule_hdr *frh,
>>  return 0;
>>  }
>>  
>> +static int nla_get_port_range(struct nlattr *pattr,
>> +  struct fib_port_range *port_range)
>> +{
>> +const struct fib_port_range *pr = nla_data(pattr);
>> +
>> +if (!fib_rule_port_range_valid(pr))
>> +return -EINVAL;
>> +
>> +port_range->start = pr->start;
>> +port_range->end = pr->end;
>> +
>> +return 0;
>> +}
>> +
>>  int 

Re: [PATCH net-next 1/5] net: fib_rules: support for match on ip_proto, sport and dport

2018-02-25 Thread Nikolay Aleksandrov
On 25/02/18 07:44, Roopa Prabhu wrote:
> From: Roopa Prabhu 
> 
> uapi for ip_proto, sport and dport range match
> in fib rules.
> 
> Signed-off-by: Roopa Prabhu 
> ---
>  include/net/fib_rules.h| 31 +-
>  include/uapi/linux/fib_rules.h |  8 
>  net/core/fib_rules.c   | 94 
> +-
>  3 files changed, 130 insertions(+), 3 deletions(-)
> 

You should probably update validate_rulemsg() as well, these aren't added in 
the per-proto
policies and nothing validates if the attribute data is actually there. Maybe 
I'm missing
something obvious, but it looks like many other FRA_ attributes don't have such 
checks.

> diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
> index b3d2162..6d99202 100644
> --- a/include/net/fib_rules.h
> +++ b/include/net/fib_rules.h
> @@ -11,6 +11,11 @@
>  #include 
>  #include 
>  
> +struct fib_port_range {
> + __u16 start;
> + __u16 end;
> +};
> +
>  struct fib_kuid_range {
>   kuid_t start;
>   kuid_t end;
> @@ -27,7 +32,7 @@ struct fib_rule {
>   u8  action;
>   u8  l3mdev;
>   u8  proto;
> - /* 1 byte hole, try to use */
> + u8  ip_proto;
>   u32 target;
>   __be64  tun_id;
>   struct fib_rule __rcu   *ctarget;
> @@ -40,6 +45,8 @@ struct fib_rule {
>   chariifname[IFNAMSIZ];
>   charoifname[IFNAMSIZ];
>   struct fib_kuid_range   uid_range;
> + struct fib_port_range   sport_range;
> + struct fib_port_range   dport_range;
>   struct rcu_head rcu;
>  };
>  
> @@ -144,6 +151,28 @@ static inline u32 frh_get_table(struct fib_rule_hdr 
> *frh, struct nlattr **nla)
>   return frh->table;
>  }
>  
> +static inline bool fib_rule_port_inrange(struct fib_port_range *a,
> +  __be16 port)
> +{
> + if (!a->start)
> + return true;

Can start be == 0 ?
IIUC this check is unnecessary because when you're adding the new rule,
you do a check for start > 0 so it shouldn't be possible to be 0.

> + return ntohs(port) >= a->start &&
> + ntohs(port) <= a->end;
> +}
> +
> +static inline bool fib_rule_port_range_valid(const struct fib_port_range *a)
> +{
> + return a->start > 0 && a->end < 0x &&
> + a->start <= a->end;

nit: alignment (also can be on a single line)

> +}
> +
> +static inline bool fib_rule_port_range_compare(struct fib_port_range *a,
> +struct fib_port_range *b)
> +{
> + return a->start == b->start &&
> + a->end == b->end;

nit: alignment (also can be on a single line)

> +}
> +
>  struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
>struct net *);
>  void fib_rules_unregister(struct fib_rules_ops *);
> diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h
> index 77d90ae..232df14 100644
> --- a/include/uapi/linux/fib_rules.h
> +++ b/include/uapi/linux/fib_rules.h
> @@ -35,6 +35,11 @@ struct fib_rule_uid_range {
>   __u32   end;
>  };
>  
> +struct fib_rule_port_range {
> + __u16   start;
> + __u16   end;
> +};
> +
>  enum {
>   FRA_UNSPEC,
>   FRA_DST,/* destination address */
> @@ -59,6 +64,9 @@ enum {
>   FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
>   FRA_UID_RANGE,  /* UID range */
>   FRA_PROTOCOL,   /* Originator of the rule */
> + FRA_IP_PROTO,   /* ip proto */
> + FRA_SPORT_RANGE, /* sport */
> + FRA_DPORT_RANGE, /* dport */
>   __FRA_MAX
>  };
>  
> diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
> index a6aea80..5008235 100644
> --- a/net/core/fib_rules.c
> +++ b/net/core/fib_rules.c
> @@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
>   if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
>   !uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
>   return false;
> + if (fib_rule_port_range_valid(>sport_range))
> + return false;
> + if (fib_rule_port_range_valid(>dport_range))
> + return false;
>   return true;
>  }
>  EXPORT_SYMBOL_GPL(fib_rule_matchall);
> @@ -221,6 +225,12 @@ static int nla_put_uid_range(struct sk_buff *skb, struct 
> fib_kuid_range *range)
>   return nla_put(skb, FRA_UID_RANGE, sizeof(out), );
>  }
>  
> +static int nla_put_port_range(struct sk_buff *skb, int attrtype,
> +   struct fib_port_range *range)
> +{
> + return nla_put(skb, attrtype, sizeof(*range), range);
> +}
> +
>  static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
> struct flowi *fl, int flags,
>