|
@@ -847,7 +847,8 @@ out_err:
|
|
|
* to fib engine. It is legal, because all events occur
|
|
|
* only when netlink is already locked.
|
|
|
*/
|
|
|
-static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
|
|
|
+static void fib_magic(int cmd, int type, __be32 dst, int dst_len,
|
|
|
+ struct in_ifaddr *ifa, u32 rt_priority)
|
|
|
{
|
|
|
struct net *net = dev_net(ifa->ifa_dev->dev);
|
|
|
u32 tb_id = l3mdev_fib_table(ifa->ifa_dev->dev);
|
|
@@ -857,6 +858,7 @@ static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifad
|
|
|
.fc_type = type,
|
|
|
.fc_dst = dst,
|
|
|
.fc_dst_len = dst_len,
|
|
|
+ .fc_priority = rt_priority,
|
|
|
.fc_prefsrc = ifa->ifa_local,
|
|
|
.fc_oif = ifa->ifa_dev->dev->ifindex,
|
|
|
.fc_nlflags = NLM_F_CREATE | NLM_F_APPEND,
|
|
@@ -902,31 +904,57 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim);
|
|
|
+ fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim, 0);
|
|
|
|
|
|
if (!(dev->flags & IFF_UP))
|
|
|
return;
|
|
|
|
|
|
/* Add broadcast address, if it is explicitly assigned. */
|
|
|
if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
|
|
|
- fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
|
|
|
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
|
|
|
+ prim, 0);
|
|
|
|
|
|
if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) &&
|
|
|
(prefix != addr || ifa->ifa_prefixlen < 32)) {
|
|
|
if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE))
|
|
|
fib_magic(RTM_NEWROUTE,
|
|
|
dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
|
|
- prefix, ifa->ifa_prefixlen, prim);
|
|
|
+ prefix, ifa->ifa_prefixlen, prim,
|
|
|
+ ifa->ifa_rt_priority);
|
|
|
|
|
|
/* Add network specific broadcasts, when it takes a sense */
|
|
|
if (ifa->ifa_prefixlen < 31) {
|
|
|
- fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim);
|
|
|
+ fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32,
|
|
|
+ prim, 0);
|
|
|
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask,
|
|
|
- 32, prim);
|
|
|
+ 32, prim, 0);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+void fib_modify_prefix_metric(struct in_ifaddr *ifa, u32 new_metric)
|
|
|
+{
|
|
|
+ __be32 prefix = ifa->ifa_address & ifa->ifa_mask;
|
|
|
+ struct in_device *in_dev = ifa->ifa_dev;
|
|
|
+ struct net_device *dev = in_dev->dev;
|
|
|
+
|
|
|
+ if (!(dev->flags & IFF_UP) ||
|
|
|
+ ifa->ifa_flags & (IFA_F_SECONDARY | IFA_F_NOPREFIXROUTE) ||
|
|
|
+ ipv4_is_zeronet(prefix) ||
|
|
|
+ prefix == ifa->ifa_local || ifa->ifa_prefixlen == 32)
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* add the new */
|
|
|
+ fib_magic(RTM_NEWROUTE,
|
|
|
+ dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
|
|
+ prefix, ifa->ifa_prefixlen, ifa, new_metric);
|
|
|
+
|
|
|
+ /* delete the old */
|
|
|
+ fib_magic(RTM_DELROUTE,
|
|
|
+ dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
|
|
+ prefix, ifa->ifa_prefixlen, ifa, ifa->ifa_rt_priority);
|
|
|
+}
|
|
|
+
|
|
|
/* Delete primary or secondary address.
|
|
|
* Optionally, on secondary address promotion consider the addresses
|
|
|
* from subnet iprim as deleted, even if they are in device list.
|
|
@@ -968,7 +996,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
|
|
if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE))
|
|
|
fib_magic(RTM_DELROUTE,
|
|
|
dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST,
|
|
|
- any, ifa->ifa_prefixlen, prim);
|
|
|
+ any, ifa->ifa_prefixlen, prim, 0);
|
|
|
subnet = 1;
|
|
|
}
|
|
|
|
|
@@ -1052,17 +1080,20 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim)
|
|
|
|
|
|
no_promotions:
|
|
|
if (!(ok & BRD_OK))
|
|
|
- fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
|
|
|
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32,
|
|
|
+ prim, 0);
|
|
|
if (subnet && ifa->ifa_prefixlen < 31) {
|
|
|
if (!(ok & BRD1_OK))
|
|
|
- fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim);
|
|
|
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32,
|
|
|
+ prim, 0);
|
|
|
if (!(ok & BRD0_OK))
|
|
|
- fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim);
|
|
|
+ fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32,
|
|
|
+ prim, 0);
|
|
|
}
|
|
|
if (!(ok & LOCAL_OK)) {
|
|
|
unsigned int addr_type;
|
|
|
|
|
|
- fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim);
|
|
|
+ fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim, 0);
|
|
|
|
|
|
/* Check, that this local address finally disappeared. */
|
|
|
addr_type = inet_addr_type_dev_table(dev_net(dev), dev,
|