[IFA_LABEL]             = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
        [IFA_CACHEINFO]         = { .len = sizeof(struct ifa_cacheinfo) },
        [IFA_FLAGS]             = { .type = NLA_U32 },
+       [IFA_RT_PRIORITY]       = { .type = NLA_U32 },
 };
 
 #define IN4_ADDR_HSIZE_SHIFT   8
        else
                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
+       if (tb[IFA_RT_PRIORITY])
+               ifa->ifa_rt_priority = nla_get_u32(tb[IFA_RT_PRIORITY]);
+
        if (tb[IFA_CACHEINFO]) {
                struct ifa_cacheinfo *ci;
 
                return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid,
                                         extack);
        } else {
+               u32 new_metric = ifa->ifa_rt_priority;
+
                inet_free_ifa(ifa);
 
                if (nlh->nlmsg_flags & NLM_F_EXCL ||
                    !(nlh->nlmsg_flags & NLM_F_REPLACE))
                        return -EEXIST;
                ifa = ifa_existing;
+
+               if (ifa->ifa_rt_priority != new_metric) {
+                       fib_modify_prefix_metric(ifa, new_metric);
+                       ifa->ifa_rt_priority = new_metric;
+               }
+
                set_ifa_lifetime(ifa, valid_lft, prefered_lft);
                cancel_delayed_work(&check_lifetime_work);
                queue_delayed_work(system_power_efficient_wq,
               + nla_total_size(4) /* IFA_BROADCAST */
               + nla_total_size(IFNAMSIZ) /* IFA_LABEL */
               + nla_total_size(4)  /* IFA_FLAGS */
+              + nla_total_size(4)  /* IFA_RT_PRIORITY */
               + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */
 }
 
            (ifa->ifa_label[0] &&
             nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) ||
            nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) ||
+           (ifa->ifa_rt_priority &&
+            nla_put_u32(skb, IFA_RT_PRIORITY, ifa->ifa_rt_priority)) ||
            put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp,
                          preferred, valid))
                goto nla_put_failure;
 
  * 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);
                .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,
                }
        }
 
-       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.
                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;
        }
 
 
 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,