Skip to content

Commit 47f0bd5

Browse files
jackuesskuba-moo
authored andcommitted
net: Add new protocol attribute to IP addresses
This patch adds a new protocol attribute to IPv4 and IPv6 addresses. Inspiration was taken from the protocol attribute of routes. User space applications like iproute2 can set/get the protocol with the Netlink API. The attribute is stored as an 8-bit unsigned integer. The protocol attribute is set by kernel for these categories: - IPv4 and IPv6 loopback addresses - IPv6 addresses generated from router announcements - IPv6 link local addresses User space may pass custom protocols, not defined by the kernel. Grouping addresses on their origin is useful in scenarios where you want to distinguish between addresses based on who added them, e.g. kernel vs. user space. Tagging addresses with a string label is an existing feature that could be used as a solution. Unfortunately the max length of a label is 15 characters, and for compatibility reasons the label must be prefixed with the name of the device followed by a colon. Since device names also have a max length of 15 characters, only -1 characters is guaranteed to be available for any origin tag, which is not that much. A reference implementation of user space setting and getting protocols is available for iproute2: westermo/iproute2@9a6ea18 Signed-off-by: Jacques de Laval <[email protected]> Reviewed-by: David Ahern <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 6e2e59e commit 47f0bd5

File tree

6 files changed

+41
-7
lines changed

6 files changed

+41
-7
lines changed

include/linux/inetdevice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ struct in_ifaddr {
150150
__be32 ifa_broadcast;
151151
unsigned char ifa_scope;
152152
unsigned char ifa_prefixlen;
153+
unsigned char ifa_proto;
153154
__u32 ifa_flags;
154155
char ifa_label[IFNAMSIZ];
155156

include/net/addrconf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ struct ifa6_config {
6464
const struct in6_addr *pfx;
6565
unsigned int plen;
6666

67+
u8 ifa_proto;
68+
6769
const struct in6_addr *peer_pfx;
6870

6971
u32 rt_priority;

include/net/if_inet6.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ struct inet6_ifaddr {
7171

7272
bool tokenized;
7373

74+
u8 ifa_proto;
75+
7476
struct rcu_head rcu;
7577
struct in6_addr peer_addr;
7678
};

include/uapi/linux/if_addr.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ enum {
3333
IFA_CACHEINFO,
3434
IFA_MULTICAST,
3535
IFA_FLAGS,
36-
IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
36+
IFA_RT_PRIORITY, /* u32, priority/metric for prefix route */
3737
IFA_TARGET_NETNSID,
38+
IFA_PROTO, /* u8, address protocol */
3839
__IFA_MAX,
3940
};
4041

@@ -69,4 +70,10 @@ struct ifa_cacheinfo {
6970
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
7071
#endif
7172

73+
/* ifa_proto */
74+
#define IFAPROT_UNSPEC 0
75+
#define IFAPROT_KERNEL_LO 1 /* loopback */
76+
#define IFAPROT_KERNEL_RA 2 /* set by kernel from router announcement */
77+
#define IFAPROT_KERNEL_LL 3 /* link-local set by kernel */
78+
7279
#endif

net/ipv4/devinet.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
104104
[IFA_FLAGS] = { .type = NLA_U32 },
105105
[IFA_RT_PRIORITY] = { .type = NLA_U32 },
106106
[IFA_TARGET_NETNSID] = { .type = NLA_S32 },
107+
[IFA_PROTO] = { .type = NLA_U8 },
107108
};
108109

109110
struct inet_fill_args {
@@ -889,6 +890,9 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh,
889890
if (tb[IFA_RT_PRIORITY])
890891
ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
891892

893+
if (tb[IFA_PROTO])
894+
ifa->ifa_proto = nla_get_u8(tb[IFA_PROTO]);
895+
892896
if (tb[IFA_CACHEINFO]) {
893897
struct ifa_cacheinfo *ci;
894898

@@ -1625,6 +1629,7 @@ static size_t inet_nlmsg_size(void)
16251629
+ nla_total_size(4) /* IFA_BROADCAST */
16261630
+ nla_total_size(IFNAMSIZ) /* IFA_LABEL */
16271631
+ nla_total_size(4) /* IFA_FLAGS */
1632+
+ nla_total_size(1) /* IFA_PROTO */
16281633
+ nla_total_size(4) /* IFA_RT_PRIORITY */
16291634
+ nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
16301635
}
@@ -1699,6 +1704,8 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
16991704
nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) ||
17001705
(ifa->ifa_label[0] &&
17011706
nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
1707+
(ifa->ifa_proto &&
1708+
nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto)) ||
17021709
nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
17031710
(ifa->ifa_rt_priority &&
17041711
nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||

net/ipv6/addrconf.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,6 +1115,7 @@ ipv6_add_addr(struct inet6_dev *idev, struct ifa6_config *cfg,
11151115
ifa->prefix_len = cfg->plen;
11161116
ifa->rt_priority = cfg->rt_priority;
11171117
ifa->flags = cfg->ifa_flags;
1118+
ifa->ifa_proto = cfg->ifa_proto;
11181119
/* No need to add the TENTATIVE flag for addresses with NODAD */
11191120
if (!(cfg->ifa_flags & IFA_F_NODAD))
11201121
ifa->flags |= IFA_F_TENTATIVE;
@@ -2593,6 +2594,7 @@ int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,
25932594
.valid_lft = valid_lft,
25942595
.preferred_lft = prefered_lft,
25952596
.scope = addr_type & IPV6_ADDR_SCOPE_MASK,
2597+
.ifa_proto = IFAPROT_KERNEL_RA
25962598
};
25972599

25982600
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
@@ -3077,7 +3079,7 @@ int addrconf_del_ifaddr(struct net *net, void __user *arg)
30773079
}
30783080

30793081
static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
3080-
int plen, int scope)
3082+
int plen, int scope, u8 proto)
30813083
{
30823084
struct inet6_ifaddr *ifp;
30833085
struct ifa6_config cfg = {
@@ -3086,7 +3088,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
30863088
.ifa_flags = IFA_F_PERMANENT,
30873089
.valid_lft = INFINITY_LIFE_TIME,
30883090
.preferred_lft = INFINITY_LIFE_TIME,
3089-
.scope = scope
3091+
.scope = scope,
3092+
.ifa_proto = proto
30903093
};
30913094

30923095
ifp = ipv6_add_addr(idev, &cfg, true, NULL);
@@ -3131,7 +3134,7 @@ static void add_v4_addrs(struct inet6_dev *idev)
31313134
}
31323135

31333136
if (addr.s6_addr32[3]) {
3134-
add_addr(idev, &addr, plen, scope);
3137+
add_addr(idev, &addr, plen, scope, IFAPROT_UNSPEC);
31353138
addrconf_prefix_route(&addr, plen, 0, idev->dev, 0, pflags,
31363139
GFP_KERNEL);
31373140
return;
@@ -3154,7 +3157,8 @@ static void add_v4_addrs(struct inet6_dev *idev)
31543157
flag |= IFA_HOST;
31553158
}
31563159

3157-
add_addr(idev, &addr, plen, flag);
3160+
add_addr(idev, &addr, plen, flag,
3161+
IFAPROT_UNSPEC);
31583162
addrconf_prefix_route(&addr, plen, 0, idev->dev,
31593163
0, pflags, GFP_KERNEL);
31603164
}
@@ -3177,7 +3181,7 @@ static void init_loopback(struct net_device *dev)
31773181
return;
31783182
}
31793183

3180-
add_addr(idev, &in6addr_loopback, 128, IFA_HOST);
3184+
add_addr(idev, &in6addr_loopback, 128, IFA_HOST, IFAPROT_KERNEL_LO);
31813185
}
31823186

31833187
void addrconf_add_linklocal(struct inet6_dev *idev,
@@ -3189,7 +3193,8 @@ void addrconf_add_linklocal(struct inet6_dev *idev,
31893193
.ifa_flags = flags | IFA_F_PERMANENT,
31903194
.valid_lft = INFINITY_LIFE_TIME,
31913195
.preferred_lft = INFINITY_LIFE_TIME,
3192-
.scope = IFA_LINK
3196+
.scope = IFA_LINK,
3197+
.ifa_proto = IFAPROT_KERNEL_LL
31933198
};
31943199
struct inet6_ifaddr *ifp;
31953200

@@ -4627,6 +4632,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = {
46274632
[IFA_FLAGS] = { .len = sizeof(u32) },
46284633
[IFA_RT_PRIORITY] = { .len = sizeof(u32) },
46294634
[IFA_TARGET_NETNSID] = { .type = NLA_S32 },
4635+
[IFA_PROTO] = { .type = NLA_U8 },
46304636
};
46314637

46324638
static int
@@ -4752,6 +4758,7 @@ static int inet6_addr_modify(struct net *net, struct inet6_ifaddr *ifp,
47524758
ifp->tstamp = jiffies;
47534759
ifp->valid_lft = cfg->valid_lft;
47544760
ifp->prefered_lft = cfg->preferred_lft;
4761+
ifp->ifa_proto = cfg->ifa_proto;
47554762

47564763
if (cfg->rt_priority && cfg->rt_priority != ifp->rt_priority)
47574764
ifp->rt_priority = cfg->rt_priority;
@@ -4845,6 +4852,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh,
48454852
if (tb[IFA_RT_PRIORITY])
48464853
cfg.rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
48474854

4855+
if (tb[IFA_PROTO])
4856+
cfg.ifa_proto = nla_get_u8(tb[IFA_PROTO]);
4857+
48484858
cfg.valid_lft = INFINITY_LIFE_TIME;
48494859
cfg.preferred_lft = INFINITY_LIFE_TIME;
48504860

@@ -4948,6 +4958,7 @@ static inline int inet6_ifaddr_msgsize(void)
49484958
+ nla_total_size(16) /* IFA_ADDRESS */
49494959
+ nla_total_size(sizeof(struct ifa_cacheinfo))
49504960
+ nla_total_size(4) /* IFA_FLAGS */
4961+
+ nla_total_size(1) /* IFA_PROTO */
49514962
+ nla_total_size(4) /* IFA_RT_PRIORITY */;
49524963
}
49534964

@@ -5025,6 +5036,10 @@ static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa,
50255036
if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0)
50265037
goto error;
50275038

5039+
if (ifa->ifa_proto &&
5040+
nla_put_u8(skb, IFA_PROTO, ifa->ifa_proto))
5041+
goto error;
5042+
50285043
nlmsg_end(skb, nlh);
50295044
return 0;
50305045

0 commit comments

Comments
 (0)