📄 fib_semantics.c
字号:
} if (fi->fib_prefsrc) { if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) goto err_inval; }link_it: if ((ofi = fib_find_info(fi)) != NULL) { kfree(fi); ofi->fib_refcnt++; return ofi; } fi->fib_refcnt++; fi->fib_next = fib_info_list; fi->fib_prev = NULL; if (fib_info_list) fib_info_list->fib_prev = fi; fib_info_list = fi; return fi;err_inval: err = -EINVAL;failure: *errp = err; if (fi) kfree(fi); return NULL;}int fib_semantic_match(int type, struct fib_info *fi, const struct rt_key *key, struct fib_result *res){ int err = fib_props[type].error; if (err == 0) { if (fi->fib_flags&RTNH_F_DEAD) return 1; res->fi = fi; switch (type) {#ifdef CONFIG_IP_ROUTE_NAT case RTN_NAT: FIB_RES_RESET(*res); return 0;#endif case RTN_UNICAST: case RTN_LOCAL: case RTN_BROADCAST: case RTN_ANYCAST: case RTN_MULTICAST: for_nexthops(fi) { if (nh->nh_flags&RTNH_F_DEAD) continue; if (!key->oif || key->oif == nh->nh_oif) break; }#ifdef CONFIG_IP_ROUTE_MULTIPATH if (nhsel < fi->fib_nhs) { res->nh_sel = nhsel; return 0; }#else if (nhsel < 1) return 0;#endif endfor_nexthops(fi); return 1; default: printk(KERN_DEBUG "impossible 102\n"); return -EINVAL; } } return err;}/* Find appropriate source address to this destination */u32 __fib_res_prefsrc(struct fib_result *res){ return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);}#ifdef CONFIG_RTNETLINKintfib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, struct fib_info *fi){ struct rtmsg *rtm; struct nlmsghdr *nlh; unsigned char *b = skb->tail; nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*rtm)); rtm = NLMSG_DATA(nlh); rtm->rtm_family = AF_INET; rtm->rtm_dst_len = dst_len; rtm->rtm_src_len = 0; rtm->rtm_tos = tos; rtm->rtm_table = tb_id; rtm->rtm_type = type; rtm->rtm_flags = fi->fib_flags; rtm->rtm_scope = scope; if (rtm->rtm_dst_len) RTA_PUT(skb, RTA_DST, 4, dst); rtm->rtm_protocol = fi->fib_protocol; if (fi->fib_priority) RTA_PUT(skb, RTA_PRIORITY, 4, &fi->fib_priority);#ifdef CONFIG_NET_CLS_ROUTE if (fi->fib_nh[0].nh_tclassid) RTA_PUT(skb, RTA_FLOW, 4, &fi->fib_nh[0].nh_tclassid);#endif if (fi->fib_mtu || fi->fib_window || fi->fib_rtt) { int i; struct rtattr *mx = (struct rtattr *)skb->tail; RTA_PUT(skb, RTA_METRICS, 0, NULL); for (i=0; i<FIB_MAX_METRICS; i++) { if (fi->fib_metrics[i]) RTA_PUT(skb, i+1, sizeof(unsigned), fi->fib_metrics + i); } mx->rta_len = skb->tail - (u8*)mx; } if (fi->fib_prefsrc) RTA_PUT(skb, RTA_PREFSRC, 4, &fi->fib_prefsrc); if (fi->fib_nhs == 1) { if (fi->fib_nh->nh_gw) RTA_PUT(skb, RTA_GATEWAY, 4, &fi->fib_nh->nh_gw); if (fi->fib_nh->nh_oif) RTA_PUT(skb, RTA_OIF, sizeof(int), &fi->fib_nh->nh_oif); }#ifdef CONFIG_IP_ROUTE_MULTIPATH if (fi->fib_nhs > 1) { struct rtnexthop *nhp; struct rtattr *mp_head; if (skb_tailroom(skb) <= RTA_SPACE(0)) goto rtattr_failure; mp_head = (struct rtattr*)skb_put(skb, RTA_SPACE(0)); for_nexthops(fi) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); nhp->rtnh_flags = nh->nh_flags & 0xFF; nhp->rtnh_hops = nh->nh_weight-1; nhp->rtnh_ifindex = nh->nh_oif; if (nh->nh_gw) RTA_PUT(skb, RTA_GATEWAY, 4, &nh->nh_gw); nhp->rtnh_len = skb->tail - (unsigned char*)nhp; } endfor_nexthops(fi); mp_head->rta_type = RTA_MULTIPATH; mp_head->rta_len = skb->tail - (u8*)mp_head; }#endif nlh->nlmsg_len = skb->tail - b; return skb->len;nlmsg_failure:rtattr_failure: skb_trim(skb, b - skb->data); return -1;}#endif /* CONFIG_RTNETLINK */#ifndef CONFIG_IP_NOSIOCRTintfib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, struct kern_rta *rta, struct rtentry *r){ int plen; u32 *ptr; memset(rtm, 0, sizeof(*rtm)); memset(rta, 0, sizeof(*rta)); if (r->rt_dst.sa_family != AF_INET) return -EAFNOSUPPORT; /* Check mask for validity: a) it must be contiguous. b) destination must have all host bits clear. c) if application forgot to set correct family (AF_INET), reject request unless it is absolutely clear i.e. both family and mask are zero. */ plen = 32; ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr; if (!(r->rt_flags&RTF_HOST)) { u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr; if (r->rt_genmask.sa_family != AF_INET) { if (mask || r->rt_genmask.sa_family) return -EAFNOSUPPORT; } if (bad_mask(mask, *ptr)) return -EINVAL; plen = inet_mask_len(mask); } nl->nlmsg_flags = NLM_F_REQUEST; nl->nlmsg_pid = 0; nl->nlmsg_seq = 0; nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm)); if (cmd == SIOCDELRT) { nl->nlmsg_type = RTM_DELROUTE; nl->nlmsg_flags = 0; } else { nl->nlmsg_type = RTM_NEWROUTE; nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE; rtm->rtm_protocol = RTPROT_BOOT; } rtm->rtm_dst_len = plen; rta->rta_dst = ptr; if (r->rt_metric) { *(u32*)&r->rt_pad3 = r->rt_metric - 1; rta->rta_priority = (u32*)&r->rt_pad3; } if (r->rt_flags&RTF_REJECT) { rtm->rtm_scope = RT_SCOPE_HOST; rtm->rtm_type = RTN_UNREACHABLE; return 0; } rtm->rtm_scope = RT_SCOPE_NOWHERE; rtm->rtm_type = RTN_UNICAST; if (r->rt_dev) {#ifdef CONFIG_IP_ALIAS char *colon;#endif struct device *dev; char devname[IFNAMSIZ]; if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1)) return -EFAULT; devname[IFNAMSIZ-1] = 0;#ifdef CONFIG_IP_ALIAS colon = strchr(devname, ':'); if (colon) *colon = 0;#endif dev = dev_get(devname); if (!dev) return -ENODEV; rta->rta_oif = &dev->ifindex;#ifdef CONFIG_IP_ALIAS if (colon) { struct in_ifaddr *ifa; struct in_device *in_dev = dev->ip_ptr; if (!in_dev) return -ENODEV; *colon = ':'; for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) if (strcmp(ifa->ifa_label, devname) == 0) break; if (ifa == NULL) return -ENODEV; rta->rta_prefsrc = &ifa->ifa_local; }#endif } ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr; if (r->rt_gateway.sa_family == AF_INET && *ptr) { rta->rta_gw = ptr; if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST) rtm->rtm_scope = RT_SCOPE_UNIVERSE; } if (cmd == SIOCDELRT) return 0; if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL) return -EINVAL; if (rtm->rtm_scope == RT_SCOPE_NOWHERE) rtm->rtm_scope = RT_SCOPE_LINK; if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) { struct rtattr *rec; struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL); if (mx == NULL) return -ENOMEM; rta->rta_mx = mx; mx->rta_type = RTA_METRICS; mx->rta_len = RTA_LENGTH(0); if (r->rt_flags&RTF_MTU) { rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); rec->rta_type = RTAX_MTU; rec->rta_len = RTA_LENGTH(4); mx->rta_len += RTA_LENGTH(4); *(u32*)RTA_DATA(rec) = r->rt_mtu; } if (r->rt_flags&RTF_WINDOW) { rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); rec->rta_type = RTAX_WINDOW; rec->rta_len = RTA_LENGTH(4); mx->rta_len += RTA_LENGTH(4); *(u32*)RTA_DATA(rec) = r->rt_window; } if (r->rt_flags&RTF_IRTT) { rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len)); rec->rta_type = RTAX_RTT; rec->rta_len = RTA_LENGTH(4); mx->rta_len += RTA_LENGTH(4); *(u32*)RTA_DATA(rec) = r->rt_irtt; } } return 0;}#endif/* Update FIB if: - local address disappeared -> we must delete all the entries referring to it. - device went down -> we must shutdown all nexthops going via it. */int fib_sync_down(u32 local, struct device *dev, int force){ int ret = 0; int scope = RT_SCOPE_NOWHERE; if (force) scope = -1; for_fib_info() { if (local && fi->fib_prefsrc == local) { fi->fib_flags |= RTNH_F_DEAD; ret++; } else if (dev && fi->fib_nhs) { int dead = 0; change_nexthops(fi) { if (nh->nh_flags&RTNH_F_DEAD) dead++; else if (nh->nh_dev == dev && nh->nh_scope != scope) { nh->nh_flags |= RTNH_F_DEAD;#ifdef CONFIG_IP_ROUTE_MULTIPATH fi->fib_power -= nh->nh_power; nh->nh_power = 0;#endif dead++; } } endfor_nexthops(fi) if (dead == fi->fib_nhs) { fi->fib_flags |= RTNH_F_DEAD; ret++; } } } endfor_fib_info(); return ret;}#ifdef CONFIG_IP_ROUTE_MULTIPATH/* Dead device goes up. We wake up dead nexthops. It takes sense only on multipath routes. */int fib_sync_up(struct device *dev){ int ret = 0; if (!(dev->flags&IFF_UP)) return 0; for_fib_info() { int alive = 0; change_nexthops(fi) { if (!(nh->nh_flags&RTNH_F_DEAD)) { alive++; continue; } if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP)) continue; if (nh->nh_dev != dev || dev->ip_ptr == NULL) continue; alive++; nh->nh_power = 0; nh->nh_flags &= ~RTNH_F_DEAD; } endfor_nexthops(fi) if (alive == fi->fib_nhs) { fi->fib_flags &= ~RTNH_F_DEAD; ret++; } } endfor_fib_info(); return ret;}/* The algorithm is suboptimal, but it provides really fair weighted route distribution. */void fib_select_multipath(const struct rt_key *key, struct fib_result *res){ struct fib_info *fi = res->fi; int w; if (fi->fib_power <= 0) { int power = 0; change_nexthops(fi) { if (!(nh->nh_flags&RTNH_F_DEAD)) { power += nh->nh_weight; nh->nh_power = nh->nh_weight; } } endfor_nexthops(fi); fi->fib_power = power;#if 1 if (power <= 0) { printk(KERN_CRIT "impossible 777\n"); return; }#endif } /* w should be random number [0..fi->fib_power-1], it is pretty bad approximation. */ w = jiffies % fi->fib_power; change_nexthops(fi) { if (!(nh->nh_flags&RTNH_F_DEAD) && nh->nh_power) { if ((w -= nh->nh_power) <= 0) { nh->nh_power--; fi->fib_power--; res->nh_sel = nhsel; return; } } } endfor_nexthops(fi);#if 1 printk(KERN_CRIT "impossible 888\n");#endif return;}#endif#ifdef CONFIG_PROC_FSstatic unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi){ static unsigned type2flags[RTN_MAX+1] = { 0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0 }; unsigned flags = type2flags[type]; if (fi && fi->fib_nh->nh_gw) flags |= RTF_GATEWAY; if (mask == 0xFFFFFFFF) flags |= RTF_HOST; if (!dead) flags |= RTF_UP; return flags;}void fib_node_get_info(int type, int dead, struct fib_info *fi, u32 prefix, u32 mask, char *buffer){ int len; unsigned flags = fib_flag_trans(type, dead, mask, fi); if (fi) { len = sprintf(buffer, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", fi->fib_dev ? fi->fib_dev->name : "*", prefix, fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority, mask, fi->fib_mtu, fi->fib_window, fi->fib_rtt); } else { len = sprintf(buffer, "*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u", prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0); } memset(buffer+len, ' ', 127-len); buffer[127] = '\n';}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -