📄 route.c
字号:
else { err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst, &itag); if (err < 0) goto martian_source; if (err) flags |= RTCF_DIRECTSRC; } flags |= RTCF_BROADCAST; res.type = RTN_BROADCAST; rt_cache_stat[smp_processor_id()].in_brd++;local_input: rth = dst_alloc(&ipv4_dst_ops); if (!rth) goto e_nobufs; rth->u.dst.output= ip_rt_bug; atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; rth->key.dst = daddr; rth->rt_dst = daddr; rth->key.tos = tos;#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark = skb->nfmark;#endif rth->key.src = saddr; rth->rt_src = saddr;#ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = key.dst; rth->rt_src_map = key.src;#endif#ifdef CONFIG_NET_CLS_ROUTE rth->u.dst.tclassid = itag;#endif rth->rt_iif = rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; dev_hold(rth->u.dst.dev); rth->key.oif = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->u.dst.input= ip_local_deliver; rth->rt_flags = flags|RTCF_LOCAL; if (res.type == RTN_UNREACHABLE) { rth->u.dst.input= ip_error; rth->u.dst.error= -err; rth->rt_flags &= ~RTCF_LOCAL; } rth->rt_type = res.type; goto intern;no_route: rt_cache_stat[smp_processor_id()].in_no_route++; spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); res.type = RTN_UNREACHABLE; goto local_input; /* * Do not cache martian addresses: they should be logged (RFC1812) */martian_destination: rt_cache_stat[smp_processor_id()].in_martian_dst++;#ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_WARNING "martian destination %u.%u.%u.%u from " "%u.%u.%u.%u, dev %s\n", NIPQUAD(daddr), NIPQUAD(saddr), dev->name);#endife_inval: err = -EINVAL; goto done;e_nobufs: err = -ENOBUFS; goto done;martian_source: rt_cache_stat[smp_processor_id()].in_martian_src++;#ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) { /* * RFC1812 recommendation, if source is martian, * the only hint is MAC header. */ printk(KERN_WARNING "martian source %u.%u.%u.%u from " "%u.%u.%u.%u, on dev %s\n", NIPQUAD(daddr), NIPQUAD(saddr), dev->name); if (dev->hard_header_len) { int i; unsigned char *p = skb->mac.raw; printk(KERN_WARNING "ll header: "); for (i = 0; i < dev->hard_header_len; i++, p++) { printk("%02x", *p); if (i < (dev->hard_header_len - 1)) printk(":"); } printk("\n"); } }#endif goto e_inval;}int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct net_device *dev){ struct rtable * rth; unsigned hash; int iif = dev->ifindex; tos &= IPTOS_RT_MASK; hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos); read_lock(&rt_hash_table[hash].lock); for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { if (rth->key.dst == daddr && rth->key.src == saddr && rth->key.iif == iif && rth->key.oif == 0 &&#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark == skb->nfmark &&#endif rth->key.tos == tos) { rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; rt_cache_stat[smp_processor_id()].in_hit++; read_unlock(&rt_hash_table[hash].lock); skb->dst = (struct dst_entry*)rth; return 0; } } read_unlock(&rt_hash_table[hash].lock); /* Multicast recognition logic is moved from route cache to here. The problem was that too many Ethernet cards have broken/missing hardware multicast filters :-( As result the host on multicasting network acquires a lot of useless route cache entries, sort of SDR messages from all the world. Now we try to get rid of them. Really, provided software IP multicast filter is organized reasonably (at least, hashed), it does not result in a slowdown comparing with route cache reject entries. Note, that multicast routers are not affected, because route cache entry is created eventually. */ if (MULTICAST(daddr)) { struct in_device *in_dev; read_lock(&inetdev_lock); if ((in_dev = __in_dev_get(dev)) != NULL) { int our = ip_check_mc(in_dev, daddr); if (our#ifdef CONFIG_IP_MROUTE || (!LOCAL_MCAST(daddr) && IN_DEV_MFORWARD(in_dev))#endif ) { read_unlock(&inetdev_lock); return ip_route_input_mc(skb, daddr, saddr, tos, dev, our); } } read_unlock(&inetdev_lock); return -EINVAL; } return ip_route_input_slow(skb, daddr, saddr, tos, dev);}/* * Major route resolver routine. */int ip_route_output_slow(struct rtable **rp, const struct rt_key *oldkey){ struct rt_key key; struct fib_result res; unsigned flags = 0; struct rtable *rth; struct net_device *dev_out = NULL; unsigned hash; int free_res = 0; int err; u32 tos; tos = oldkey->tos & (IPTOS_RT_MASK | RTO_ONLINK); key.dst = oldkey->dst; key.src = oldkey->src; key.tos = tos & IPTOS_RT_MASK; key.iif = loopback_dev.ifindex; key.oif = oldkey->oif;#ifdef CONFIG_IP_ROUTE_FWMARK key.fwmark = oldkey->fwmark;#endif key.scope = (tos & RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; res.fi = NULL;#ifdef CONFIG_IP_MULTIPLE_TABLES res.r = NULL;#endif if (oldkey->src) { err = -EINVAL; if (MULTICAST(oldkey->src) || BADCLASS(oldkey->src) || ZERONET(oldkey->src)) goto out; /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ dev_out = ip_dev_find(oldkey->src); if (dev_out == NULL) goto out; /* I removed check for oif == dev_out->oif here. It was wrong by three reasons: 1. ip_dev_find(saddr) can return wrong iface, if saddr is assigned to multiple interfaces. 2. Moreover, we are allowed to send packets with saddr of another iface. --ANK */ if (oldkey->oif == 0 && (MULTICAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF)) { /* Special hack: user can direct multicasts and limited broadcast via necessary interface without fiddling with IP_MULTICAST_IF or IP_PKTINFO. This hack is not just for fun, it allows vic,vat and friends to work. They bind socket to loopback, set ttl to zero and expect that it will work. From the viewpoint of routing cache they are broken, because we are not allowed to build multicast path with loopback source addr (look, routing cache cannot know, that ttl is zero, so that packet will not leave this host and route is valid). Luckily, this hack is good workaround. */ key.oif = dev_out->ifindex; goto make_route; } if (dev_out) dev_put(dev_out); dev_out = NULL; } if (oldkey->oif) { dev_out = dev_get_by_index(oldkey->oif); err = -ENODEV; if (dev_out == NULL) goto out; if (__in_dev_get(dev_out) == NULL) { dev_put(dev_out); goto out; /* Wrong error code */ } if (LOCAL_MCAST(oldkey->dst) || oldkey->dst == 0xFFFFFFFF) { if (!key.src) key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); goto make_route; } if (!key.src) { if (MULTICAST(oldkey->dst)) key.src = inet_select_addr(dev_out, 0, key.scope); else if (!oldkey->dst) key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); } } if (!key.dst) { key.dst = key.src; if (!key.dst) key.dst = key.src = htonl(INADDR_LOOPBACK); if (dev_out) dev_put(dev_out); dev_out = &loopback_dev; dev_hold(dev_out); key.oif = loopback_dev.ifindex; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; } if (fib_lookup(&key, &res)) { res.fi = NULL; if (oldkey->oif) { /* Apparently, routing tables are wrong. Assume, that the destination is on link. WHY? DW. Because we are allowed to send to iface even if it has NO routes and NO assigned addresses. When oif is specified, routing tables are looked up with only one purpose: to catch if destination is gatewayed, rather than direct. Moreover, if MSG_DONTROUTE is set, we send packet, ignoring both routing tables and ifaddr state. --ANK We could make it even if oif is unknown, likely IPv6, but we do not. */ if (key.src == 0) key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); res.type = RTN_UNICAST; goto make_route; } if (dev_out) dev_put(dev_out); err = -ENETUNREACH; goto out; } free_res = 1; if (res.type == RTN_NAT) goto e_inval; if (res.type == RTN_LOCAL) { if (!key.src) key.src = key.dst; if (dev_out) dev_put(dev_out); dev_out = &loopback_dev; dev_hold(dev_out); key.oif = dev_out->ifindex; if (res.fi) fib_info_put(res.fi); res.fi = NULL; flags |= RTCF_LOCAL; goto make_route; }#ifdef CONFIG_IP_ROUTE_MULTIPATH if (res.fi->fib_nhs > 1 && key.oif == 0) fib_select_multipath(&key, &res); else#endif if (!res.prefixlen && res.type == RTN_UNICAST && !key.oif) fib_select_default(&key, &res); if (!key.src) key.src = FIB_RES_PREFSRC(res); if (dev_out) dev_put(dev_out); dev_out = FIB_RES_DEV(res); dev_hold(dev_out); key.oif = dev_out->ifindex;make_route: if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) goto e_inval; if (key.dst == 0xFFFFFFFF) res.type = RTN_BROADCAST; else if (MULTICAST(key.dst)) res.type = RTN_MULTICAST; else if (BADCLASS(key.dst) || ZERONET(key.dst)) goto e_inval; if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; if (res.type == RTN_BROADCAST) { flags |= RTCF_BROADCAST | RTCF_LOCAL; if (res.fi) { fib_info_put(res.fi); res.fi = NULL; } } else if (res.type == RTN_MULTICAST) { flags |= RTCF_MULTICAST|RTCF_LOCAL; read_lock(&inetdev_lock); if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), oldkey->dst)) flags &= ~RTCF_LOCAL; read_unlock(&inetdev_lock); /* If multicast route do not exist use default one, but do not gateway in this case. Yes, it is hack. */ if (res.fi && res.prefixlen < 4) { fib_info_put(res.fi); res.fi = NULL; } } rth = dst_alloc(&ipv4_dst_ops); if (!rth) goto e_nobufs; atomic_set(&rth->u.dst.__refcnt, 1); rth->u.dst.flags= DST_HOST; rth->key.dst = oldkey->dst; rth->key.tos = tos; rth->key.src = oldkey->src; rth->key.iif = 0; rth->key.oif = oldkey->oif;#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark = oldkey->fwmark;#endif rth->rt_dst = key.dst; rth->rt_src = key.src;#ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = key.dst; rth->rt_src_map = key.src;#endif rth->rt_iif = oldkey->oif ? : dev_out->ifindex; rth->u.dst.dev = dev_out; dev_hold(dev_out); rth->rt_gateway = key.dst; rth->rt_spec_dst= key.src; rth->u.dst.output=ip_output; rt_cache_stat[smp_processor_id()].out_slow_tot++; if (flags & RTCF_LOCAL) { rth->u.dst.input = ip_local_deliver; rth->rt_spec_dst = key.dst; } if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { rth->rt_spec_dst = key.src; if (flags & RTCF_LOCAL && !(dev_out->flags & IFF_LOOPBACK)) { rth->u.dst.output = ip_mc_output; rt_cache_stat[smp_processor_id()].out_slow_mc++; }#ifdef CONFIG_IP_MROUTE if (res.type == RTN_MULTICAST) { struct in_device *in_dev = in_dev_get(dev_out); if (in_dev) { if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(oldkey->dst)) { rth->u.dst.input = ip_mr_input; rth->u.dst.output = ip_mc_output; } in_dev_put(in_dev); } }#endif } rt_set_nexthop(rth, &res, 0); rth->rt_flags = flags; hash = rt_hash_code(oldkey->dst, oldkey->src ^ (oldkey->oif << 5), tos); err = rt_intern_hash(hash, rth, rp);done: if (free_res) fib_res_put(&res); if (dev_out) dev_put(dev_out);out: return err;e_inval: err = -EINVAL; goto done;e_nobufs: err = -ENOBUFS; goto done;}int ip_route_output_key(struct rtable **rp, const struct rt_key *key){ unsigned hash; struct rtable *rth; hash = rt_hash_code(key->dst, key->src ^ (key->oif << 5), key->tos); read_lock_bh(&rt_hash_table[hash].lock); for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { if (rth->key.dst == key->dst && rth->key.src == key->src && rth->key.iif == 0 && rth->key.oif == key->oif &&#ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark == key->fwmark &&#endif !((rth->key.tos ^ key->tos) & (IPTOS_RT_MASK | RTO_ONLINK))) { rth->u.dst.lastuse = jiffies; dst_hold(&rth->u.dst); rth->u.dst.__use++; rt_cache_stat[smp_processor_id()].out_hit++; read_unlock_bh(&rt_hash_table[hash].lock); *rp = rth; return 0; } } read_unlock_bh(&rt_hash_table[hash].lock); return ip_route_output_slow(rp, key);} static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait){ struct rtable *rt = (struct rtable*)skb->dst; struct rtmsg *r;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -