^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * DECnet An implementation of the DECnet protocol suite for the LINUX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * operating system. DECnet is implemented using the BSD Socket
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * interface as the means of communication with the user level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * DECnet Routing Forwarding Information Base (Glue/Info List)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Author: Steve Whitehouse <SteveW@ACM.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * Changes:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Alexey Kuznetsov : SMP locking changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * Steve Whitehouse : Rewrote it... Well to be more correct, I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * copied most of it from the ipv4 fib code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Steve Whitehouse : Updated it in style and fixed a few bugs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * which were fixed in the ipv4 code since
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * this code was copied from it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/net.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/socket.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/sockios.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/skbuff.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/netlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <linux/netdevice.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <linux/atomic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <net/neighbour.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <net/dst.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #include <net/flow.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #include <net/fib_rules.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #include <net/dn.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #include <net/dn_route.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #include <net/dn_fib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #include <net/dn_neigh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #include <net/dn_dev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #include <net/rtnh.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define RT_MIN_TABLE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define for_fib_info() { struct dn_fib_info *fi;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) for(fi = dn_fib_info_list; fi; fi = fi->fib_next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define endfor_fib_info() }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define endfor_nexthops(fi) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static DEFINE_SPINLOCK(dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static struct dn_fib_info *dn_fib_info_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static DEFINE_SPINLOCK(dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u8 scope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) } dn_fib_props[RTN_MAX+1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) [RTN_BROADCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) [RTN_ANYCAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) [RTN_MULTICAST] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) [RTN_BLACKHOLE] = { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) [RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) [RTN_PROHIBIT] = { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) [RTN_THROW] = { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) [RTN_NAT] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) [RTN_XRESOLVE] = { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static int dn_fib_sync_up(struct net_device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) void dn_fib_free_info(struct dn_fib_info *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (fi->fib_dead == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (nh->nh_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) dev_put(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) nh->nh_dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) kfree(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) void dn_fib_release_info(struct dn_fib_info *fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) spin_lock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (fi && --fi->fib_treeref == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (fi->fib_next)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) fi->fib_next->fib_prev = fi->fib_prev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (fi->fib_prev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) fi->fib_prev->fib_next = fi->fib_next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (fi == dn_fib_info_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) dn_fib_info_list = fi->fib_next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) dn_fib_info_put(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) spin_unlock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) const struct dn_fib_nh *onh = ofi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) for_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (nh->nh_oif != onh->nh_oif ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) nh->nh_gw != onh->nh_gw ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) nh->nh_scope != onh->nh_scope ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) nh->nh_weight != onh->nh_weight ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) onh++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static inline struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (fi->fib_nhs != nfi->fib_nhs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (nfi->fib_protocol == fi->fib_protocol &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) nfi->fib_prefsrc == fi->fib_prefsrc &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) nfi->fib_priority == fi->fib_priority &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) memcmp(nfi->fib_metrics, fi->fib_metrics, sizeof(fi->fib_metrics)) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) ((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) (nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) } endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) static int dn_fib_count_nhs(const struct nlattr *attr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct rtnexthop *nhp = nla_data(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int nhs = 0, nhlen = nla_len(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) while (rtnh_ok(nhp, nhlen)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) nhs++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) nhp = rtnh_next(nhp, &nhlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) /* leftover implies invalid nexthop configuration, discard it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return nhlen > 0 ? 0 : nhs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct nlattr *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) const struct rtmsg *r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct rtnexthop *nhp = nla_data(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) int nhlen = nla_len(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) int attrlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (!rtnh_ok(nhp, nhlen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) nh->nh_flags = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) nh->nh_oif = nhp->rtnh_ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) nh->nh_weight = nhp->rtnh_hops + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) attrlen = rtnh_attrlen(nhp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (attrlen > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct nlattr *gw_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) gw_attr = nla_find((struct nlattr *) (nhp + 1), attrlen, RTA_GATEWAY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) nh->nh_gw = gw_attr ? nla_get_le16(gw_attr) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) nhp = rtnh_next(nhp, &nhlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) if (nh->nh_gw) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) struct flowidn fld;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) struct dn_fib_res res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (nh->nh_flags&RTNH_F_ONLINK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (r->rtm_scope >= RT_SCOPE_LINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) if (dnet_addr_type(nh->nh_gw) != RTN_UNICAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if ((dev = __dev_get_by_index(&init_net, nh->nh_oif)) == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) nh->nh_dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) dev_hold(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) nh->nh_scope = RT_SCOPE_LINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) memset(&fld, 0, sizeof(fld));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) fld.daddr = nh->nh_gw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) fld.flowidn_oif = nh->nh_oif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) fld.flowidn_scope = r->rtm_scope + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (fld.flowidn_scope < RT_SCOPE_LINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) fld.flowidn_scope = RT_SCOPE_LINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if ((err = dn_fib_lookup(&fld, &res)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) if (res.type != RTN_UNICAST && res.type != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) nh->nh_scope = res.scope;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) nh->nh_oif = DN_FIB_RES_OIF(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) nh->nh_dev = DN_FIB_RES_DEV(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) if (nh->nh_dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) dev_hold(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) err = -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (!(nh->nh_dev->flags & IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) dn_fib_res_put(&res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) dev = __dev_get_by_index(&init_net, nh->nh_oif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (dev == NULL || dev->dn_ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) return -ENETDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) nh->nh_dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dev_hold(nh->nh_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) nh->nh_scope = RT_SCOPE_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct nlattr *attrs[],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) const struct nlmsghdr *nlh, int *errp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) struct dn_fib_info *fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) struct dn_fib_info *ofi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) int nhs = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (r->rtm_type > RTN_MAX)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (attrs[RTA_MULTIPATH] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) (nhs = dn_fib_count_nhs(attrs[RTA_MULTIPATH])) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) fi = kzalloc(struct_size(fi, fib_nh, nhs), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) err = -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (fi == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) fi->fib_protocol = r->rtm_protocol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) fi->fib_nhs = nhs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) fi->fib_flags = r->rtm_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) if (attrs[RTA_PRIORITY])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) fi->fib_priority = nla_get_u32(attrs[RTA_PRIORITY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) if (attrs[RTA_METRICS]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct nlattr *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int rem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) nla_for_each_nested(attr, attrs[RTA_METRICS], rem) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int type = nla_type(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if (type > RTAX_MAX || type == RTAX_CC_ALGO ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) nla_len(attr) < 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) fi->fib_metrics[type-1] = nla_get_u32(attr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (attrs[RTA_PREFSRC])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) fi->fib_prefsrc = nla_get_le16(attrs[RTA_PREFSRC]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (attrs[RTA_MULTIPATH]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if ((err = dn_fib_get_nhs(fi, attrs[RTA_MULTIPATH], r)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (attrs[RTA_OIF] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) fi->fib_nh->nh_oif != nla_get_u32(attrs[RTA_OIF]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (attrs[RTA_GATEWAY] &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) fi->fib_nh->nh_gw != nla_get_le16(attrs[RTA_GATEWAY]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) struct dn_fib_nh *nh = fi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (attrs[RTA_OIF])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) nh->nh_oif = nla_get_u32(attrs[RTA_OIF]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (attrs[RTA_GATEWAY])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) nh->nh_flags = r->rtm_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) nh->nh_weight = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (r->rtm_type == RTN_NAT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (!attrs[RTA_GATEWAY] || nhs != 1 || attrs[RTA_OIF])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) fi->fib_nh->nh_gw = nla_get_le16(attrs[RTA_GATEWAY]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) goto link_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (dn_fib_props[r->rtm_type].error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if (attrs[RTA_GATEWAY] || attrs[RTA_OIF] || attrs[RTA_MULTIPATH])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) goto link_it;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) if (r->rtm_scope > RT_SCOPE_HOST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (r->rtm_scope == RT_SCOPE_HOST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) struct dn_fib_nh *nh = fi->fib_nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) /* Local address is added */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (nhs != 1 || nh->nh_gw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) nh->nh_scope = RT_SCOPE_NOWHERE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) nh->nh_dev = dev_get_by_index(&init_net, fi->fib_nh->nh_oif);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (nh->nh_dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if ((err = dn_fib_check_nh(r, fi, nh)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) goto failure;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) } endfor_nexthops(fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (fi->fib_prefsrc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (r->rtm_type != RTN_LOCAL || !attrs[RTA_DST] ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) fi->fib_prefsrc != nla_get_le16(attrs[RTA_DST]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (dnet_addr_type(fi->fib_prefsrc) != RTN_LOCAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) goto err_inval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) link_it:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if ((ofi = dn_fib_find_info(fi)) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) dn_fib_free_info(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) ofi->fib_treeref++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) return ofi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) fi->fib_treeref++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) refcount_set(&fi->fib_clntref, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) spin_lock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) fi->fib_next = dn_fib_info_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) fi->fib_prev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (dn_fib_info_list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) dn_fib_info_list->fib_prev = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) dn_fib_info_list = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) spin_unlock(&dn_fib_info_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) return fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) err_inval:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) failure:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) *errp = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) fi->fib_dead = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) dn_fib_free_info(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) int dn_fib_semantic_match(int type, struct dn_fib_info *fi, const struct flowidn *fld, struct dn_fib_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) int err = dn_fib_props[type].error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (err == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) if (fi->fib_flags & RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) res->fi = fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) switch (type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) case RTN_NAT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) DN_FIB_RES_RESET(*res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) refcount_inc(&fi->fib_clntref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) case RTN_UNICAST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) case RTN_LOCAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) for_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (nh->nh_flags & RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (!fld->flowidn_oif ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) fld->flowidn_oif == nh->nh_oif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) if (nhsel < fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) res->nh_sel = nhsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) refcount_inc(&fi->fib_clntref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) res->fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) net_err_ratelimited("DECnet: impossible routing event : dn_fib_semantic_match type=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) res->fi = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) void dn_fib_select_multipath(const struct flowidn *fld, struct dn_fib_res *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) struct dn_fib_info *fi = res->fi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) int w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) if (fi->fib_power <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) int power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (!(nh->nh_flags&RTNH_F_DEAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) power += nh->nh_weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) nh->nh_power = nh->nh_weight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) fi->fib_power = power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) if (power < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) res->nh_sel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) w = jiffies % fi->fib_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if ((w -= nh->nh_power) <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) nh->nh_power--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) fi->fib_power--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) res->nh_sel = nhsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) res->nh_sel = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static inline u32 rtm_get_table(struct nlattr *attrs[], u8 table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (attrs[RTA_TABLE])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) table = nla_get_u32(attrs[RTA_TABLE]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) return table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) struct net *net = sock_net(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct rtmsg *r = nlmsg_data(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) struct nlattr *attrs[RTA_MAX+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) if (!netlink_capable(skb, CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (!net_eq(net, &init_net))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) rtm_dn_policy, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) if (!tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) return -ESRCH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) return tb->delete(tb, r, attrs, nlh, &NETLINK_CB(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) struct netlink_ext_ack *extack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) struct net *net = sock_net(skb->sk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) struct rtmsg *r = nlmsg_data(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) struct nlattr *attrs[RTA_MAX+1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (!netlink_capable(skb, CAP_NET_ADMIN))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) return -EPERM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (!net_eq(net, &init_net))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) err = nlmsg_parse_deprecated(nlh, sizeof(*r), attrs, RTA_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) rtm_dn_policy, extack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) tb = dn_fib_get_table(rtm_get_table(attrs, r->rtm_table), 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) if (!tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) return -ENOBUFS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return tb->insert(tb, r, attrs, nlh, &NETLINK_CB(skb));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) struct dn_fib_table *tb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) struct nlmsghdr nlh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) struct rtmsg rtm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) } req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) __le16 dst;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) } dst_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) .dst = dst,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) __le16 prefsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) } prefsrc_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) .prefsrc = ifa->ifa_local,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) struct nlattr hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) u32 oif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) } oif_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) .oif = ifa->ifa_dev->dev->ifindex,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) struct nlattr *attrs[RTA_MAX+1] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) [RTA_DST] = (struct nlattr *) &dst_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) [RTA_PREFSRC] = (struct nlattr * ) &prefsrc_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) [RTA_OIF] = (struct nlattr *) &oif_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) memset(&req.rtm, 0, sizeof(req.rtm));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) if (type == RTN_UNICAST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) tb = dn_fib_get_table(RT_MIN_TABLE, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) tb = dn_fib_get_table(RT_TABLE_LOCAL, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (tb == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) req.nlh.nlmsg_len = sizeof(req);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) req.nlh.nlmsg_type = cmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_APPEND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) req.nlh.nlmsg_pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) req.nlh.nlmsg_seq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) req.rtm.rtm_dst_len = dst_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) req.rtm.rtm_table = tb->n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) req.rtm.rtm_protocol = RTPROT_KERNEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) req.rtm.rtm_scope = (type != RTN_LOCAL ? RT_SCOPE_LINK : RT_SCOPE_HOST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) req.rtm.rtm_type = type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (cmd == RTM_NEWROUTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) tb->insert(tb, &req.rtm, attrs, &req.nlh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) tb->delete(tb, &req.rtm, attrs, &req.nlh, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) static void dn_fib_add_ifaddr(struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) fib_magic(RTM_NEWROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) /* In the future, we will want to add default routes here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int found_it = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) struct dn_dev *dn_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) struct dn_ifaddr *ifa2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) ASSERT_RTNL();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) /* Scan device list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) rcu_read_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) for_each_netdev_rcu(&init_net, dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) dn_db = rcu_dereference(dev->dn_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (dn_db == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) for (ifa2 = rcu_dereference(dn_db->ifa_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) ifa2 != NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) ifa2 = rcu_dereference(ifa2->ifa_next)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (ifa2->ifa_local == ifa->ifa_local) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) found_it = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) rcu_read_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) if (found_it == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 16, ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (dnet_addr_type(ifa->ifa_local) != RTN_LOCAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (dn_fib_sync_down(ifa->ifa_local, NULL, 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) dn_fib_flush();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) static void dn_fib_disable_addr(struct net_device *dev, int force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (dn_fib_sync_down(0, dev, force))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) dn_fib_flush();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) dn_rt_cache_flush(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) neigh_ifdown(&dn_neigh_table, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) struct dn_ifaddr *ifa = (struct dn_ifaddr *)ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) case NETDEV_UP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) dn_fib_add_ifaddr(ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) dn_fib_sync_up(ifa->ifa_dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) dn_rt_cache_flush(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) case NETDEV_DOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) dn_fib_del_ifaddr(ifa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) dn_fib_disable_addr(ifa->ifa_dev->dev, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) dn_rt_cache_flush(-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return NOTIFY_DONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) int scope = RT_SCOPE_NOWHERE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) if (force)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) scope = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) * This makes no sense for DECnet.... we will almost
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) * certainly have more than one local address the same
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) * over all our interfaces. It needs thinking about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) * some more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (local && fi->fib_prefsrc == local) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) fi->fib_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) } else if (dev && fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) int dead = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) if (nh->nh_flags&RTNH_F_DEAD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) dead++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) else if (nh->nh_dev == dev &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) nh->nh_scope != scope) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) nh->nh_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) fi->fib_power -= nh->nh_power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) nh->nh_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) dead++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) } endfor_nexthops(fi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) if (dead == fi->fib_nhs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) fi->fib_flags |= RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) } endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static int dn_fib_sync_up(struct net_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (!(dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) for_fib_info() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) int alive = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) change_nexthops(fi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (!(nh->nh_flags&RTNH_F_DEAD)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) alive++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) if (nh->nh_dev != dev || dev->dn_ptr == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) alive++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) spin_lock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) nh->nh_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) nh->nh_flags &= ~RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) spin_unlock_bh(&dn_fib_multipath_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) } endfor_nexthops(fi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (alive > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) fi->fib_flags &= ~RTNH_F_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) ret++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) } endfor_fib_info();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) static struct notifier_block dn_fib_dnaddr_notifier = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) .notifier_call = dn_fib_dnaddr_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) void __exit dn_fib_cleanup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) dn_fib_table_cleanup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) dn_fib_rules_cleanup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) unregister_dnaddr_notifier(&dn_fib_dnaddr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) void __init dn_fib_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) dn_fib_table_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) dn_fib_rules_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_NEWROUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) dn_fib_rtm_newroute, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) rtnl_register_module(THIS_MODULE, PF_DECnet, RTM_DELROUTE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) dn_fib_rtm_delroute, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }