📄 ipmr.c
字号:
else { atomic_inc(&skb->users); skb2 = skb; } if (skb2 == NULL) { ip_rt_put(rt); return; } vif->pkt_out++; vif->bytes_out+=skb->len; dst_release(skb2->dst); skb2->dst = &rt->u.dst; iph = skb2->nh.iph; ip_decrease_ttl(iph);#ifdef CONFIG_FIREWALL if (call_fw_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { kfree_skb(skb2); return; } if (call_out_firewall(PF_INET, vif->dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { kfree_skb(skb2); return; }#endif if (vif->flags & VIFF_TUNNEL) { ip_encap(skb2, vif->local, vif->remote);#ifdef CONFIG_FIREWALL /* Double output firewalling on tunnels: one is on tunnel another one is on real device. */ if (call_out_firewall(PF_INET, dev, skb2->nh.iph, NULL, &skb2) < FW_ACCEPT) { kfree_skb(skb2); return; }#endif ((struct ip_tunnel *)vif->dev->priv)->stat.tx_packets++; ((struct ip_tunnel *)vif->dev->priv)->stat.tx_bytes+=skb2->len; } IPCB(skb2)->flags |= IPSKB_FORWARDED; /* * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally * not only before forwarding, but after forwarding on all output * interfaces. It is clear, if mrouter runs a multicasting * program, it should receive packets not depending to what interface * program is joined. * If we will not make it, the program will have to join on all * interfaces. On the other hand, multihoming host (or router, but * not mrouter) cannot join to more than one interface - it will * result in receiving multiple packets. */ if (skb2->len <= rt->u.dst.pmtu) skb2->dst->output(skb2); else ip_fragment(skb2, skb2->dst->output);}int ipmr_find_vif(struct device *dev){ int ct; for (ct=0; ct<maxvif; ct++) { if (vifc_map&(1<<ct) && vif_table[ct].dev == dev) return ct; } return ALL_VIFS;}/* "local" means that we should preserve one skb (for local delivery) */int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local){ int psend = -1; int vif, ct; vif = cache->mfc_parent; cache->mfc_pkt++; cache->mfc_bytes += skb->len; /* * Wrong interface: drop packet and (maybe) send PIM assert. */ if (vif_table[vif].dev != skb->dev) { int true_vifi; if (((struct rtable*)skb->dst)->key.iif == 0) { /* It is our own packet, looped back. Very complicated situation... The best workaround until routing daemons will be fixed is not to redistribute packet, if it was send through wrong interface. It means, that multicast applications WILL NOT work for (S,G), which have default multicast route pointing to wrong oif. In any case, it is not a good idea to use multicasting applications on router. */ goto dont_forward; } cache->mfc_wrong_if++; true_vifi = ipmr_find_vif(skb->dev); if (true_vifi < MAXVIFS && mroute_do_assert && /* pimsm uses asserts, when switching from RPT to SPT, so that we cannot check that packet arrived on an oif. It is bad, but otherwise we would need to move pretty large chunk of pimd to kernel. Ough... --ANK */ (mroute_do_pim || cache->mfc_ttls[true_vifi] < 255) && jiffies - cache->mfc_last_assert > MFC_ASSERT_THRESH) { cache->mfc_last_assert = jiffies; ipmr_cache_report(skb, true_vifi, IGMPMSG_WRONGVIF); } goto dont_forward; } vif_table[vif].pkt_in++; vif_table[vif].bytes_in+=skb->len; /* * Forward the frame */ for (ct = cache->mfc_maxvif-1; ct >= cache->mfc_minvif; ct--) { if (skb->nh.iph->ttl > cache->mfc_ttls[ct]) { if (psend != -1) ipmr_queue_xmit(skb, cache, psend, 0); psend=ct; } } if (psend != -1) ipmr_queue_xmit(skb, cache, psend, !local);dont_forward: if (!local) kfree_skb(skb); return 0;}/* * Multicast packets for forwarding arrive here */int ip_mr_input(struct sk_buff *skb){ struct mfc_cache *cache; int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL; /* Packet is looped back after forward, it should not be forwarded second time, but still can be delivered locally. */ if (IPCB(skb)->flags&IPSKB_FORWARDED) goto dont_forward; if (!local) { if (IPCB(skb)->opt.router_alert) { if (ip_call_ra_chain(skb)) return 0; } else if (skb->nh.iph->protocol == IPPROTO_IGMP && mroute_socket) { /* IGMPv1 (and broken IGMPv2 implementations sort of Cisco IOS <= 11.2(8)) do not put router alert option to IGMP packets destined to routable groups. It is very bad, because it means that we can forward NO IGMP messages. */ raw_rcv(mroute_socket, skb); return 0; } } cache = ipmr_cache_find(skb->nh.iph->saddr, skb->nh.iph->daddr); /* * No usable cache entry */ if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) { int vif; if (local) { struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); ip_local_deliver(skb); if (skb2 == NULL) return -ENOBUFS; skb = skb2; } vif = ipmr_find_vif(skb->dev); if (vif != ALL_VIFS) { ipmr_cache_unresolved(cache, vif, skb); return -EAGAIN; } kfree_skb(skb); return 0; } ip_mr_forward(skb, cache, local); if (local) return ip_local_deliver(skb); return 0;dont_forward: if (local) return ip_local_deliver(skb); kfree_skb(skb); return 0;}#ifdef CONFIG_IP_PIMSM_V1/* * Handle IGMP messages of PIMv1 */int pim_rcv_v1(struct sk_buff * skb, unsigned short len){ struct igmphdr *pim = (struct igmphdr*)skb->h.raw; struct iphdr *encap; if (!mroute_do_pim || len < sizeof(*pim) + sizeof(*encap) || pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER || reg_dev == NULL) { kfree_skb(skb); return -EINVAL; } encap = (struct iphdr*)(skb->h.raw + sizeof(struct igmphdr)); /* Check that: a. packet is really destinted to a multicast group b. packet is not a NULL-REGISTER c. packet is not truncated */ if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || ntohs(encap->tot_len) + sizeof(*pim) > len) { kfree_skb(skb); return -EINVAL; } skb->mac.raw = skb->nh.raw; skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; skb->dev = reg_dev; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); skb->dst = NULL; ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; netif_rx(skb); return 0;}#endif#ifdef CONFIG_IP_PIMSM_V2int pim_rcv(struct sk_buff * skb, unsigned short len){ struct pimreghdr *pim = (struct pimreghdr*)skb->h.raw; struct iphdr *encap; if (len < sizeof(*pim) + sizeof(*encap) || pim->type != ((PIM_VERSION<<4)|(PIM_REGISTER)) || (pim->flags&PIM_NULL_REGISTER) || reg_dev == NULL || (ip_compute_csum((void *)pim, sizeof(*pim)) && ip_compute_csum((void *)pim, len))) { kfree_skb(skb); return -EINVAL; } /* check if the inner packet is destined to mcast group */ encap = (struct iphdr*)(skb->h.raw + sizeof(struct pimreghdr)); if (!MULTICAST(encap->daddr) || ntohs(encap->tot_len) == 0 || ntohs(encap->tot_len) + sizeof(*pim) > len) { kfree_skb(skb); return -EINVAL; } skb->mac.raw = skb->nh.raw; skb_pull(skb, (u8*)encap - skb->data); skb->nh.iph = (struct iphdr *)skb->data; skb->dev = reg_dev; memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); skb->protocol = __constant_htons(ETH_P_IP); skb->ip_summed = 0; skb->pkt_type = PACKET_HOST; dst_release(skb->dst); ((struct net_device_stats*)reg_dev->priv)->rx_bytes += skb->len; ((struct net_device_stats*)reg_dev->priv)->rx_packets++; skb->dst = NULL; netif_rx(skb); return 0;}#endif#ifdef CONFIG_RTNETLINKstatic intipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm){ int ct; struct rtnexthop *nhp; struct device *dev = vif_table[c->mfc_parent].dev; u8 *b = skb->tail; struct rtattr *mp_head; if (dev) RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_minvif; ct < c->mfc_maxvif; ct++) { if (c->mfc_ttls[ct] < 255) { 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 = 0; nhp->rtnh_hops = c->mfc_ttls[ct]; nhp->rtnh_ifindex = vif_table[ct].dev->ifindex; nhp->rtnh_len = sizeof(*nhp); } } mp_head->rta_type = RTA_MULTIPATH; mp_head->rta_len = skb->tail - (u8*)mp_head; rtm->rtm_type = RTN_MULTICAST; return 1;rtattr_failure: skb_trim(skb, b - skb->data); return -EMSGSIZE;}int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait){ struct mfc_cache *cache; struct rtable *rt = (struct rtable*)skb->dst; start_bh_atomic(); cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); if (cache==NULL || (cache->mfc_flags&MFC_QUEUED)) { struct device *dev; int vif; int err; if (nowait) { end_bh_atomic(); return -EAGAIN; } dev = skb->dev; if (dev == NULL || (vif = ipmr_find_vif(dev)) == ALL_VIFS) { end_bh_atomic(); return -ENODEV; } skb->nh.raw = skb_push(skb, sizeof(struct iphdr)); skb->nh.iph->ihl = sizeof(struct iphdr)>>2; skb->nh.iph->saddr = rt->rt_src; skb->nh.iph->daddr = rt->rt_dst; skb->nh.iph->version = 0; err = ipmr_cache_unresolved(cache, vif, skb); end_bh_atomic(); return err; } /* Resolved cache entry is not changed by net bh, so that we are allowed to enable it. */ end_bh_atomic(); if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) cache->mfc_flags |= MFC_NOTIFY; return ipmr_fill_mroute(skb, cache, rtm);}#endif/* * The /proc interfaces to multicast routing /proc/ip_mr_cache /proc/ip_mr_vif */ int ipmr_vif_info(char *buffer, char **start, off_t offset, int length, int dummy){ struct vif_device *vif; int len=0; off_t pos=0; off_t begin=0; int size; int ct; len += sprintf(buffer, "Interface BytesIn PktsIn BytesOut PktsOut Flags Local Remote\n"); pos=len; for (ct=0;ct<maxvif;ct++) { char *name = "none"; vif=&vif_table[ct]; if(!(vifc_map&(1<<ct))) continue; if (vif->dev) name = vif->dev->name; size = sprintf(buffer+len, "%2d %-10s %8ld %7ld %8ld %7ld %05X %08X %08X\n", ct, name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out, vif->flags, vif->local, vif->remote); len+=size; pos+=size; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) break; } *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; return len;}int ipmr_mfc_info(char *buffer, char **start, off_t offset, int length, int dummy){ struct mfc_cache *mfc; int len=0; off_t pos=0; off_t begin=0; int size; int ct; len += sprintf(buffer, "Group Origin Iif Pkts Bytes Wrong Oifs\n"); pos=len; for (ct=0;ct<MFC_LINES;ct++) { start_bh_atomic(); mfc=mfc_cache_array[ct]; while(mfc!=NULL) { int n; /* * Interface forwarding map */ size = sprintf(buffer+len, "%08lX %08lX %-3d %8ld %8ld %8ld", (unsigned long)mfc->mfc_mcastgrp, (unsigned long)mfc->mfc_origin, mfc->mfc_parent == ALL_VIFS ? -1 : mfc->mfc_parent, (mfc->mfc_flags & MFC_QUEUED) ? mfc->mfc_unresolved.qlen : mfc->mfc_pkt, mfc->mfc_bytes, mfc->mfc_wrong_if); for(n=mfc->mfc_minvif;n<mfc->mfc_maxvif;n++) { if(vifc_map&(1<<n) && mfc->mfc_ttls[n] < 255) size += sprintf(buffer+len+size, " %2d:%-3d", n, mfc->mfc_ttls[n]); } size += sprintf(buffer+len+size, "\n"); len+=size; pos+=size; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) { end_bh_atomic(); goto done; } mfc=mfc->next; } end_bh_atomic(); }done: *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; if (len < 0) { len = 0; } return len;}#ifdef CONFIG_PROC_FS static struct proc_dir_entry proc_net_ipmr_vif = { PROC_NET_IPMR_VIF, 9 ,"ip_mr_vif", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, ipmr_vif_info};static struct proc_dir_entry proc_net_ipmr_mfc = { PROC_NET_IPMR_MFC, 11 ,"ip_mr_cache", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, ipmr_mfc_info};#endif #ifdef CONFIG_IP_PIMSM_V2struct inet_protocol pim_protocol = { pim_rcv, /* PIM handler */ NULL, /* PIM error control */ NULL, /* next */ IPPROTO_PIM, /* protocol ID */ 0, /* copy */ NULL, /* data */ "PIM" /* name */};#endif/* * Setup for IP multicast routing */ __initfunc(void ip_mr_init(void)){ printk(KERN_INFO "Linux IP multicast router 0.06 plus PIM-SM\n"); register_netdevice_notifier(&ip_mr_notifier);#ifdef CONFIG_PROC_FS proc_net_register(&proc_net_ipmr_vif); proc_net_register(&proc_net_ipmr_mfc);#endif }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -