Merge tag 'nds32-for-linus-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / net / ipv4 / fib_frontend.c
index e66172a..e46cdd3 100644 (file)
@@ -300,6 +300,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
        if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
                struct flowi4 fl4 = {
                        .flowi4_iif = LOOPBACK_IFINDEX,
+                       .flowi4_oif = l3mdev_master_ifindex_rcu(dev),
                        .daddr = ip_hdr(skb)->saddr,
                        .flowi4_tos = RT_TOS(ip_hdr(skb)->tos),
                        .flowi4_scope = scope,
@@ -354,8 +355,6 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
                fl4.fl4_dport = 0;
        }
 
-       trace_fib_validate_source(dev, &fl4);
-
        if (fib_lookup(net, &fl4, &res, 0))
                goto last_resort;
        if (res.type != RTN_UNICAST &&
@@ -569,7 +568,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
                struct nlattr *mx;
                int len = 0;
 
-               mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL);
+               mx = kcalloc(3, nla_total_size(4), GFP_KERNEL);
                if (!mx)
                        return -ENOMEM;
 
@@ -650,6 +649,9 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = {
        [RTA_UID]               = { .type = NLA_U32 },
        [RTA_MARK]              = { .type = NLA_U32 },
        [RTA_TABLE]             = { .type = NLA_U32 },
+       [RTA_IP_PROTO]          = { .type = NLA_U8 },
+       [RTA_SPORT]             = { .type = NLA_U16 },
+       [RTA_DPORT]             = { .type = NLA_U16 },
 };
 
 static int rtm_to_fib_config(struct net *net, struct sk_buff *skb,
@@ -846,7 +848,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);
@@ -856,6 +859,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,
@@ -901,31 +905,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.
@@ -967,7 +997,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;
        }
 
@@ -1051,17 +1081,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,