ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

路由output 查找

2022-03-07 19:03:18  阅读:203  来源: 互联网

标签:rt ops ip dst neigh 查找 output 路由


看下以前的文章首先说明一下 Routing与 Neighboring subsystem的关联

1、在路由过程中,需要寻找或创建 struct dst_entry (另一种形式是 struct rtable)。 dst_entry 通过neighbour 域与 struct neighbour 关联。

每个 dst_entry 对应一个 neighbour,这样在路由之后,立刻能找到对应的 neighbour,此后,数据包通过 neighbour->output 送到链路层。

以 UDP 包的发送过程为例,这个过程如下

Udp_sendmsg() ==> ip_route_output() 
        ==> udp_push_pending_frames()==》udp_send_skb==》ip_send_skb==》ip_local_out==》dst_output==》skb->dst->output

Ip_route_output_slow() : 当查不到路由 cache 后(下一跳地址的cache),根据 route rule ,通过 dst_alloc() 创建一个 dst_entry 结构,这同时也是一个 rtable 结构,然后将 dst_entry 的 output 指向 ip_output();

此后,udp_sendmsg 继续调用 ip_send_skb() 来发包;

rth->u.dst.output=ip_output;
Udp_sendmsg() ==> udp_push_pending_frames ==> udp_send_skb==> ip_send_skb==>ip_local_out==》skb->dst->output()//这里的 output 就是 ip_output()
ip_output ==> __ip_finish_output() ==> ip_finish_output2() ==> dst_neigh_output()

  因此,最终数据包是通过dst_neigh_output  也就是 neighbour->output() 往下送的。

IPv4 代码实现:ip_route_output在路由 cache 中查不到路由结果后,查找__mkroute_output->rt_dst_alloc-> route rule ,如果没有合适的路由规则,则失败返回。否则,通过 dst_alloc() 创建一个 dst_entry 结构,这同时也是一个 rtable 结构,此 rtable 结构被挂入 hash 表中。这时候我们已经有了下一跳的 L3地址。

static struct dst_ops ipv4_dst_ops = {
    .family =        AF_INET,
    .protocol =        cpu_to_be16(ETH_P_IP),
    .check =        ipv4_dst_check,
    .default_advmss =    ipv4_default_advmss,
    .mtu =            ipv4_mtu,
    .cow_metrics =        ipv4_cow_metrics,
    .destroy =        ipv4_dst_destroy,
    .ifdown =        ipv4_dst_ifdown,
    .negative_advice =    ipv4_negative_advice,
    .link_failure =        ipv4_link_failure,
    .update_pmtu =        ip_rt_update_pmtu,
    .redirect =        ip_do_redirect,
    .local_out =        __ip_local_out,
    .neigh_lookup =        ipv4_neigh_lookup,//rtable 和 neigh_table绑定
};


static struct rtable *rt_dst_alloc(struct net_device *dev,
                   unsigned int flags, u16 type,
                   bool nopolicy, bool noxfrm, bool will_cache)
{
    struct rtable *rt;

    rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK,
               (will_cache ? 0 : (DST_HOST | DST_NOCACHE)) |
               (nopolicy ? DST_NOPOLICY : 0) |
               (noxfrm ? DST_NOXFRM : 0));

    if (rt) {
        rt->rt_genid = rt_genid_ipv4(dev_net(dev));
        rt->rt_flags = flags;
        rt->rt_type = type;
        rt->rt_is_input = 0;
        
        rt->rt_iif = 0;
        rt->rt_pmtu = 0;
        rt->rt_gateway = 0;
        rt->rt_uses_gateway = 0;
        rt->rt_table_id = 0;
        //初始化其rt_uncached链表指针
        INIT_LIST_HEAD(&rt->rt_uncached);

        rt->dst.output = ip_output;
        if (flags & RTCF_LOCAL)
            rt->dst.input = ip_local_deliver;
    }

    return rt;
}


void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
        int initial_ref, int initial_obsolete, unsigned short flags)
{
    struct dst_entry *dst;

    if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) {
        if (ops->gc(ops))
            return NULL;
    }
    dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC);
    if (!dst)
        return NULL;
    dst->child = NULL;
    dst->dev = dev;
    if (dev)
        dev_hold(dev);
    dst->ops = ops;// 赋值ops
    dst_init_metrics(dst, dst_default_metrics, true);
    dst->expires = 0UL;
    dst->path = dst;
#ifdef CONFIG_XFRM
    dst->xfrm = NULL;
#endif
    dst->input = dst_discard;
    dst->output = dst_discard//创建时
    dst->error = 0;
    dst->obsolete = initial_obsolete;
    dst->header_len = 0;
    dst->trailer_len = 0;
#ifdef CONFIG_IP_ROUTE_CLASSID
    dst->tclassid = 0;
#endif
    atomic_set(&dst->__refcnt, initial_ref);
    dst->__use = 0;
    dst->lastuse = jiffies;
    dst->flags = flags;
    dst->pending_confirm = 0;
    dst->next = NULL;
    if (!(flags & DST_NOCOUNT))
        dst_entries_add(ops, 1);
    return dst;
}

  新版本中都是缓存下一跳地址,所以路由表和neigh表分开,现在是找到下一跳IP, 直接对IP运行对用neigh 相关协议找到IP 对应MAC;

可以看到dst_neigh_output(dst, neigh, skb); 虽然传入的dst参数,但是其实际没有使用dst->ops函数去处理rtable 和neighbour的bind关系

复制代码
1.1 ip_finish_output2() 
1.2 nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr)
1.3 __ipv4_neigh_lookup_noref(dev, nexthop)
  if (!neigh)
    neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
1.4 if(neigh)
  dst_neigh_output(dst, neigh, skb);
复制代码
static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
                   struct sk_buff *skb)
{
    struct hh_cache *hh;

    if (unlikely(dst->pending_confirm)) {
        n->confirmed = jiffies;
        dst->pending_confirm = 0;
    }

    hh = &n->hh;
    if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
        return neigh_hh_output(hh, skb);
    else
        return n->output(n, skb);
}
/*neigh_alloc() 用于分配 neighbour 结构
neigh_create() 进一步设置此结构,对于 ARP 来说,它调用 arp_constructor() ,在这个函数里面,对 neighbour 的 ops 域和 output 域进行设置。
Ops 域,根据底层 driver 的类型进行不同的设置,
对于没有链路层地址的,指向arp_direct_ops
对于没有链路层 cache 的,指向arp_generic_ops
对于有链路层 cache 的, 指向arp_hh_ops

 

标签:rt,ops,ip,dst,neigh,查找,output,路由
来源: https://www.cnblogs.com/codestack/p/15977419.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有