linux网络协议栈分析笔记9-arp邻居子系统2

linux网络协议栈分析笔记10-arp邻居子系统3 还是回到neigh_resolve_output() int neigh_resolve_output(struct sk_buff *skb) {      struct dst_entry *dst = skb_dst(skb);      struct neighbour *neigh;      int rc = 0;      if (!dst || !(neigh = 阅读详情
上回说到流量输出会走到neigh_resolve_output  我们来看看邻居这玩意能玩点什么花样,传说的arp学习在哪里
int neigh_resolve_output(struct sk_buff *skb)
{
     struct dst_entry *dst = skb_dst(skb);
     struct neighbour *neigh;
     int rc = 0;

     if (!dst || !(neigh = dst->neighbour))        异常退出
          goto discard;

     __skb_pull(skb, skb_network_offset(skb));

     if (!neigh_event_send(neigh, skb)) {           判断邻居项是否有可用状态,如果可用,则把数据包发送出去
           int err;
          struct net_device *dev = neigh->dev;
          if (dev->header_ops->cache && !dst->hh) {
               write_lock_bh(&neigh->lock);
               if (!dst->hh)
                    neigh_hh_init(neigh, dst, dst->ops->protocol);
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);
               write_unlock_bh(&neigh->lock);
          } else {
               read_lock_bh(&neigh->lock);
               err = dev_hard_header(skb, dev, ntohs(skb->protocol),
                               neigh->ha, NULL, skb->len);
               read_unlock_bh(&neigh->lock);
          }
          if (err >= 0)
               rc = neigh->ops->queue_xmit(skb);
          else
               goto out_kfree_skb;
     }
out:
     return rc;
discard:
     NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
                dst, dst ? dst->neighbour : NULL);
out_kfree_skb:
     rc = -EINVAL;
     kfree_skb(skb);
     goto out;
}
这里叫邻居事件发送,自己瞎叫的
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)  
{
     neigh->used = jiffies;
     if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))            假设带着NUD_NONE进来的
          return __neigh_event_send(neigh, skb);
     return 0;
}
这里开始涉及状态的东西了   先对NUD状态描述下
#define NUD_INCOMPLETE     0x01       一个请求已发送出去,但还没收到应答,在这个状态不使用任何硬件地址
#define NUD_REACHABLE     0x02         邻居的地址被放入缓存,并且知道该邻居是可到达的

#define NUD_STALE     0x04                
#define NUD_DELAY     0x08
#define NUD_PROBE     0x10            这三个用于状态转换阶段,当本地主机确定邻居是否可到达时,状态会发生改变   

#define NUD_FAILED     0x20            由于请求失败,将邻居标记为不可达

/* Dummy states */
#define NUD_NOARP     0x40                 用于标记不要任何协议进行L3到L2的地址映射的邻居
#define NUD_PERMANENT     0x80         邻居的L2地址是静态配置,因此不需要邻居协议进行地址解析
#define NUD_NONE     0x00                   邻居项刚被创建,还没有状态可用


派生状态
NUD_IN_TIMER :               当某一邻居项的状态不是很清晰时,邻居子系统就为其运行一个定时器
#define NUD_IN_TIMER     (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)
   
#define NUD_VALID     (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
NUD_CONNECTED  :      这个状态为NUD_VALID的子状态,没有未决的确认要处理
#define NUD_CONNECTED     (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)

int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{
     int rc;
     unsigned long now;

     write_lock_bh(&neigh->lock);

     rc = 0;
     if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
          goto out_unlock_bh;

     now = jiffies;

     if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
          if (neigh->parms->mcast_probes + neigh->parms->app_probes) {                  .mcast_probes = 3,
               atomic_set(&neigh->probes, neigh->parms->ucast_probes);    重发arp请求的次数 .ucast_probes =  3,
               neigh->nud_state     = NUD_INCOMPLETE;    设状态为NUD_INCOMPLETE,
                neigh->updated = jiffies;
               neigh_add_timer(neigh, now + 1);                  且设置定时器
          } else {
               neigh->nud_state = NUD_FAILED;
               neigh->updated = jiffies;
               write_unlock_bh(&neigh->lock);

               kfree_skb(skb);
               return 1;
          }
     } else if (neigh->nud_state & NUD_STALE) {
          NEIGH_PRINTK2("neigh %p is delayed.\n", neigh);
          neigh->nud_state = NUD_DELAY;
          neigh->updated = jiffies;
          neigh_add_timer(neigh,
                    jiffies + neigh->parms->delay_probe_time);
     }

     if (neigh->nud_state == NUD_INCOMPLETE) {          如果是NUD_INCOMPLETE状态
          if (skb) {
     if (skb_queue_len(&neigh->arp_queue) >=检查队列长度,应该是每个邻居项都有一个可供缓存待解析的skb
                   neigh->parms->queue_len) {            .queue_len =          3,
                    struct sk_buff *buff;
                    buff = __skb_dequeue(&neigh->arp_queue);
                    kfree_skb(buff);                             取出一个  释放掉     
                    NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);
               }
               __skb_queue_tail(&neigh->arp_queue, skb);     把这个新的放进去
          }
          rc = 1;
     }
out_unlock_bh:
     write_unlock_bh(&neigh->lock);
     return rc;
}
上面这段函数的主要作用将邻居状态置成NUD_INCOMPLETE,并启动定时器,我们看下定时器里干了啥

setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n);
neigh_timer_handler():
     大概看了看,都是定时器到期后处理各种状态迁移,找到我们分析的状态
     if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
          struct sk_buff *skb = skb_peek(&neigh->arp_queue);
          /* keep skb alive even if arp_queue overflows */
          if (skb)
               skb = skb_copy(skb, GFP_ATOMIC);
          write_unlock(&neigh->lock);
          neigh->ops->solicit(neigh, skb);               在arp_constructor()中被置上
          atomic_inc(&neigh->probes);
          kfree_skb(skb);

static const struct neigh_ops arp_hh_ops = {
     .family =          AF_INET,
     .solicit =          arp_solicit,
     .error_report =          arp_error_report,
     .output =          neigh_resolve_output,
     .connected_output =     neigh_resolve_output,
     .hh_output =          dev_queue_xmit,
     .queue_xmit =          dev_queue_xmit,
};

->arp_solicit()    
      ->arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr,dst_ha, dev->dev_addr, NULL);
通过arp_send发送ARP REQUEST报文

发送看累了,看看arp的接收吧
static int arp_rcv(struct sk_buff *skb, struct net_device *dev,
             struct packet_type *pt, struct net_device *orig_dev)
{
     struct arphdr *arp;

     /* ARP header, plus 2 device addresses, plus 2 IP addresses.  */
     if (!pskb_may_pull(skb, arp_hdr_len(dev)))
          goto freeskb;

     arp = arp_hdr(skb);
     if (arp->ar_hln != dev->addr_len ||
         dev->flags & IFF_NOARP ||
         skb->pkt_type == PACKET_OTHERHOST ||
         skb->pkt_type == PACKET_LOOPBACK ||
         arp->ar_pln != 4)
          goto freeskb;

     if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
          goto out_of_mem;                                                                     一系列的合法性检查

     memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));  这里把skb的cb区域用作neighbour_cb结构空间

     return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);

freeskb:
     kfree_skb(skb);
out_of_mem:
     return 0;
}     

struct arphdr          arp头结构
{
     __be16          ar_hrd;       硬件地址格式
     __be16          ar_pro;        协议地址格式
     unsigned char     ar_hln;      硬件地址长度
     unsigned char     ar_pln;     协议地址长度
     __be16          ar_op;         命令代码

#if 0
     /*
       *     Ethernet looks like this : This bit is variable sized however...
       */
     unsigned char          ar_sha[ETH_ALEN];     /* sender hardware address     */
     unsigned char          ar_sip[4];          /* sender IP address          */
     unsigned char          ar_tha[ETH_ALEN];     /* target hardware address     */
     unsigned char          ar_tip[4];          /* target IP address          */
#endif

};

进入arp_process()
     ->arp = arp_hdr(skb);  获得ARP头

     ->if (arp->ar_op != htons(ARPOP_REPLY) &&arp->ar_op != htons(ARPOP_REQUEST))   
                    goto out;                        不是reply 也不是 request 那是啥呢?
     ->     
          arp_ptr= (unsigned char *)(arp+1);
          sha     = arp_ptr;                       发送端以太网首址
          arp_ptr += dev->addr_len;
          memcpy(&sip, arp_ptr, 4);           发送端ip地址
          arp_ptr += 4;
          arp_ptr += dev->addr_len;
          memcpy(&tip, arp_ptr, 4);           目的IP地址
     
     ->
     if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))    环回或多播
          goto out;
     ->
if (arp->ar_op == htons(ARPOP_REQUEST) &&                 收到一个请求包
         ip_route_input(skb, tip, sip, 0, dev) == 0) {
          rt = skb_rtable(skb);  
          addr_type = rt->rt_type;
          if (addr_type == RTN_LOCAL) {                             若是送往本机的arp请求包
               int dont_send = 0;
               if (!dont_send)
                    dont_send |= arp_ignore(in_dev,sip,tip);
               if (!dont_send && IN_DEV_ARPFILTER(in_dev))
                    dont_send |= arp_filter(sip,tip,dev);
               if (!dont_send) {
                    n = neigh_event_ns(&arp_tbl, sha, &sip, dev);           更新arp邻居表
                    if (n) {
                         arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);  发送arp应答
                         neigh_release(n);
                    }
               }
               goto out;
          } else if (IN_DEV_FORWARD(in_dev)) {          代理arp
                   if (addr_type == RTN_UNICAST  && rt->u.dst.dev != dev &&
                    (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
                    n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                    if (n)
                         neigh_release(n);

                    if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED ||
                        skb->pkt_type == PACKET_HOST ||
                        in_dev->arp_parms->proxy_delay == 0) {
                         arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
                    } else {
                         pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
                         in_dev_put(in_dev);
                         return 0;
                    }
                    goto out;
               }
          }
     }         
n = __neigh_lookup(&arp_tbl, &sip, dev, 0);       对arp应答包的处理          用源ip去邻居表里查是否有邻居项

     if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) {
          /* Unsolicited ARP is not accepted by default.
             It is possible, that this option should be enabled for some
             devices (strip is candidate)
          */
          if (n == NULL &&
              arp->ar_op == htons(ARPOP_REPLY) &&
              inet_addr_type(net, sip) == RTN_UNICAST)
               n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
     }

     if (n) {
          int state = NUD_REACHABLE;             如果存在

          int override;

          /* If several different ARP replies follows back-to-back,
             use the FIRST one. It is possible, if several proxy
             agents are active. Taking the first reply prevents
             arp trashing and chooses the fastest router.
          */
          override = time_after(jiffies, n->updated + n->parms->locktime);

          /* Broadcast replies and request packets
             do not assert neighbour reachability.
          */
          if (arp->ar_op != htons(ARPOP_REPLY) ||
              skb->pkt_type != PACKET_HOST)
               state = NUD_STALE;
          neigh_update(n, sha, state, override ? NEIGH_UPDATE_F_OVERRIDE : 0);        更新邻居项状态
          neigh_release(n);
     }

涉及到状态迁移的东西挺复杂的,我们就不深入分析了,这里只是输出下大体流程和主要数据结构的组织,关于arp表项的状态迁移
转网上达人的分析共同学习:
在上图中,我们看到只有arp缓存项的reachable状态对于外发包是可用的,对于stale状态的arp缓存项而言,它实际上是不可用的。如果此时有人要发包,那么需要进行重新解析,对于常规的理解,重新解析意味着要重新发送arp请求,然后事实上却不一定这样,因为Linux为arp增加了一个“事件点”来“不用发送arp请求”而对arp协议生成的缓存维护的优化措施,事实上,这种措施十分有效。这就是arp的“确认”机制,也就是说,如果说从一个邻居主动发来一个数据包到本机,那么就可以确认该包的“上一跳”这个邻居是有效的,然而为何只有到达本机的包才能确认“上一跳”这个邻居的有效性呢?因为Linux并不想为IP 层的处理增加负担,也即不想改变IP 层的原始语义。
 
Linux维护一个stale状态其实就是为了保留一个neighbour结构体,在其状态改变时只是个别字段得到修改或者填充。如果按照简单的实现,只保存一个reachable状态即可,其到期则删除arp缓存表项。Linux的做法只是做了很多的优化,但是如果你为这些优化而绞尽脑汁,那就悲剧了... 

linux中是如何维护这个state状态的?
在Linux实现的ARP状态机中,最复杂的就是stale状态了,在此状态中的arp缓存表项面临着生死抉择,抉择者就是本地发出的包,如果本地发出的包使用了这个stale状态的arp缓存表项,那么就将状态机推进到delay状态,如果在“垃圾收集”定时器到期后还没有人使用该邻居,那么就有可能删除这个表项了,到底删除吗?这样看看有木有其它路径使用它,关键是看路由缓存,路由缓存虽然是一个第三层的概念,然而却保留了该路由的下一条的ARP缓存表项,这个意义上,Linux的路由缓存实则一个转发表而不是一个路由表。 

如果有外发包使用了这个表项,那么该表项的ARP状态机将进入delay状态,在delay状态中,只要有“本地”确认的到来(本地接收包的上一跳来自该邻居),linux 还是不会发送ARP请求的,但是如果一直都没有本地确认,那么Linux就将发送真正的ARP请求了,进入probe状态。因此可以看到,从stale状态开始,所有的状态只是为一种优化措施而存在的,stale状态的ARP缓存表项就是一个缓存的缓存,如果Linux只是将过期的reachable状态的arp缓存表项删除,语义是一样的,但是实现看起来以及理解起来会简单得多! 

再次强调,reachable过期进入stale状态而不是直接删除,是为了保留neighbour结构体,优化内存以及CPU利用,实际上进入stale状态的arp缓存表项时不可用的,要想使其可用,要么在delay状态定时器到期前本地给予了确认,比如tcp收到了一个包,要么delay状态到期进入probe状态后arp请求得到了回应。否则还是会被删除。
LINUX邻居子系统(一) 邻居子系统是linux网络协议栈中非常庞大的一块,也是比较混乱复杂的一块,不过有一点感觉挺好玩的就是 它不涉及太多具体协议的内容,所以阅读起来还不算太复杂 而且它很多时候自成一个小小的系统运转(所以才叫子系统),不需要外界太多的管理(ARP,ND等协议的管理),这也是它的一个特色。 不过感觉它也承担了一部分第二层的功能(二层协议首部的封装) 它嵌入在网络层和数据链路层之间(但是又不能把它叫 阅读详情

相关推荐

linux网络协议栈分析笔记8-arp邻居子系统1

我们进入arp协议,我们看看linux中号称邻居子系统是啥样的 static struct packet_type arp_packet_type __read_mostly = {      .type =     cpu_to_be16(ETH_P_ARP),         .func =     arp_rcv, }; 还记得那个netif_receive_skb吧,选择

白水煮鸡蛋 1848

深入理解Linux网络技术内幕 第27章 邻居子系统-通用基础结构

邻居子系统-通用基础结构数据结构L3协议和邻居通用接口neigh->ops初始化neigh->output和neigh->nud_state初始化邻居信息更新-neigh_update 数据结构 struct neigh_table 描述邻居协议参数和所用函数。 struct neighbour 存储邻居相关信息。该结构描述主机的L3地址,主机有多个L3地址也就有多个该结构。 L3协议和邻居通用接口 Linux内核通过虚拟函数表将L3协议和L2传输函数链接起来。邻居系统的虚拟函数表由str

weixin_44793395的博客 1278

linux之网络子系统(11)- 地址解析协议arp 源码分析和邻居通用框架

框架图:(在一本书上的图)为什么需要邻居子系统?因为在网络上发送报文的时候除了需要知道目的IP地址还需要知道邻居的L2 MAC地址,为什么是邻居的L2 MAC地址而不是目的地的L2地址?这是因为目的地网络可能和源主机不在同一个网段,因此需要借助其他离目的地近的网关帮我们传输,此时网关就是邻居。如果目的地和源主机在同一个LAN上的话,它们就是邻居。邻居子系统的核心功能 就是完成L3地址到L2地址的映射,也即使ARP协议,并提供网络层和驱动程序底层之间的接口。

z20230508的博客 1707

深层解析ARP协议

ARP状态机中,实际上生效的状态仅有reachable一项,当状态机从reachable进入stale状态的时候,为了保留neighbour结构体,优化内存以及CPU利用,实际上 arp缓存表项仅仅是表现为不可用,而不是直接删除。每一个ARP缓存表都对应的存在一个ARP状态机,而从图中可以看到 arp 缓存表仅在Reachable状态对于外发包是可用的,而Stale状态实际是不可用的,可以理解为Linux维护stale只是为了保留一个neighbour结构体,在其状态改变时只是个别字段得到修改或者填充。

mikumikuZuo的博客 2861

linux内核协议栈 邻居协议之 arp 数据包收发处理流程

前言 在arp初始化时,通过调用dev_add_pack将arp协议的接收处理函数添加到了三层协议数据包处理函数相关的hash链表ptype_base中(关于三层协议数据包处理函数相关的hash链表,请参考文档http://blog.youkuaiyun.com/lickylin/article/details/22900401)。当底层接收到属于本机的arp数据包时,就会调用arp_rcv进行后续处理。 1 arp数据包文接收arp_rcv() 功能:对接收到的arp数据包的处理函数 首先对arp数据...

7108

探索Linux内核网络协议栈:自定义协议与IPv6邻居发现的交互分析

协议交互诊断通过和精准日志定位触发源,区分标准协议与自定义协议。选择性禁用功能禁用IPv6前评估对网络服务的影响,尤其是依赖IPv6的组件。防御性编码在内核调试工具结合ftracekdump等工具深入分析内核行为,提升调试效率。通过上述方法,开发者既能理解内核协议栈的底层机制,又能有效调试自定义协议模块,确保网络功能的稳定性和可维护性。1. 问题背景:周期性调用的函数在Linux内核网络模块开发中,开发者可能会发现自定义的发送函数(如)被频繁调用。

数字人生 260

ARP状态

(以下内容都基于linux内核2.4.0源码)     在include/net/neighbour.h中定义了ARP有限状态机所对应的各种状态:    27 #define NUD_INCOMPLETE 0x0128 #define NUD_REACHABLE 0x0229 #define NUD_STALE 0x0430 #define NUD_DELAY 0x0831 #define NUD

松哥(jccz_zys)的专栏 9241

Unity坦克物理系统:履带驱动与力场建模实战指南

在游戏物理仿真中,履带车辆的运动建模远超传统轮式控制器的范畴。其核心在于摒弃WheelCollider的滚动幻觉,转向基于牛顿力学的力与力矩协同求解——通过主推进力场、转向力矩场和地面反作用力场三重叠加,实现对质量、摩擦、惯性及坡度阻力的真实响应。这种建模方式不仅支撑坦克爬坡、陷泥、侧倾等复杂行为,更保障了多人同步与高帧率下的物理稳定性。Physics Tank Maker 正是这一思路的工业级落地,它将PhysX底层机制与坦克动力学深度耦合,提供可调参数、事件驱动视觉反馈及标准扩展接口,成为面向严肃模拟类

weixin_29535577的博客 562

linux网络协议栈源码分析 - 邻居子系统邻居状态转移

linux内核邻居子系统状态转移

arm7star的博客 1626

逆向工程的艺术:如何绕过PDD的长连接机制实现高效抓包

本文深入解析了如何通过逆向工程技术绕过拼多多(PDD)的长连接机制实现高效抓包。详细介绍了动态调试方案、关键函数Hook技巧及流量解密重组方法,帮助开发者在非Root环境下捕获并解析PDD的加密数据。结合Python工具链,实现稳定数据采集,适用于电商数据分析和反爬策略研究。

weixin_29058331的博客 674

招行收款通SM2加密解密全流程解析:PHP开发者必看

本文详细解析了招商银行收款通服务中SM2加密解密的完整流程,特别针对PHP开发者提供了从密钥管理到签名验签的实战指南。涵盖国密算法基础、PHP环境配置、密钥安全存储及生产环境优化方案,帮助开发者快速实现高安全性的支付系统集成。

weixin_30632089的博客 651

Linux网络协议栈3--neighbor子系统

邻居,可以简单理解为三层上的一跳距离。路由的下一跳可以不是直连的一跳距离(迭代路由),但最终走到邻居子系统的时候就是一跳距离。 linux 迭代路由的用法: https://www.jianshu.com/p/070202b6d3ca 邻居子系统,提供三层地址到二层地址之间的映射,提供二层首部缓存加速二层头的封装,提供二层报文头的封装。 如下,邻居表信息,表达了IP地址是x.x.x.x的下一跳,它的mac地址是xx:xx:xx:xx:xx:xx,通过出接口ethx能够到达。 #ip neigh 172.16

bigsheng2的博客 1948

PCB作为智能小车底盘的设计方法与工程实践

PCB底盘是一种将机械结构与电子设计深度融合的嵌入式系统集成方案,其本质是利用印制电路板的高精度制造能力(±0.05mm孔位公差)和FR-4材料的结构强度(弯曲强度345MPa),替代传统亚克力或铝合金底盘。该方案通过封装库驱动的正向设计、机械层语义化定义及机电协同布局,实现安装基准统一、共地平面优化与RF天线集成等技术价值。广泛应用于教育机器人、AGV小车、模块化开发平台等对空间紧凑性、量产一致性与电磁兼容性有严苛要求的移动嵌入式场景,尤其适合具备EDA工具使用能力的电子工程师主导的跨学科开发流程。

weixin_36064575的博客 127

Linux内核分析 - 网络[九]:邻居表

内核版本:2.6.34 这部分的重点是三个核心的数据结构-邻居表、邻居缓存、代理邻居表,以及NUD状态转移图。       总的来说,要成功添加一条邻居表项,需要满足两个条件:1. 本机使用该表项;2. 对方主机进行了确认。同时,表项的添加引入了NUD(Neighbour Unreachability Detection)机制,从创建NUD_NONE到可用NUD_REACHABLE需要经历

wangpengqi的专栏 4578

ROS-订阅与处理激光雷达scan话题

激光雷达通常有四个性能衡量指标:测距分辨率、扫描频率(有时也用扫描周期)、角度分辨率及可视范围。测距分辨率衡量在一个给定的距离下测距的精确程度,通常与距离真实值相差在5-20mm;扫描频率衡量激光雷达完成一次完整扫描的快慢,通常在10Hz及以上;角度分辨率直接决定激光雷达一次完整扫描能返回多少个样本点;可视范围指激光雷达完整扫描的广角,可视范围之外即为盲区。

weixin_42438635的博客 4477

高通平台 Android T 蓝牙技术全解析:架构、代码与实现原理

协议栈、配置文件和服务都运行在一个独立的用户空间进程。

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 100

linux网络协议栈(四)链路层 (3)邻居子系统&ARP

4.3、邻居子系统+ARP: 4.3.1、什么是邻居: 所谓邻居就是二层直连的两个主机,如A与B直连或者A与B通过二层交换机连接,都是邻居。邻居子系统的作用是就是实现L3地址和L2地址的映射关系。 邻居子系统本身只实现一个通用架构,具体实现按照具体的L3协议和L2协议确定,如对于IPV4/ethernet,ARP协议就是邻居子系统的实现内容,对于IPV6/ethernet则是ND协议,对于其

u010246947的专栏 3293

移动端实战指南:深入理解 & 接入 IAB OMSDK

OMSDK(OpenMeasurementSDK)是IABTechLab推出的标准化测量工具,用于统一移动端/原生App广告的可见性和验证流程。其核心包括Native库(采集设备数据)和OMID JavaScript层(实现通信),通过标准化接口让开发者只需接入一套SDK即可兼容多个测量厂商,减少冲突和性能损耗。v1.4版本强化了对CTV和原生App场景的支持,而v1.5新增了画中画检测等功能。集成流程需通过IAB技术实验室注册下载,并遵循严格的命名空间规则。测试阶段需嵌入验证脚本并通过指定工具验证

帅次的博客 1187

linux网络协议栈:邻居子系统

一:邻居子系统概述          邻居子系统是从物理来说是指在同一个局域网内的终端。从网络拓扑的结构来说,是指他们之间相隔的距离仅为一跳,他们属于同一个突冲域          邻居子系统的作用:          它为第三层协议与第二层协议提供地址映射关系。          提供邻居头部缓存,加速发包的速度 二:邻居子系统在整个协议栈的地位          发送数据的时候,要

风之伤 1740

47_AI智能体核心业务之全局主控Agent:智能对话系统的统一指挥中心

本文介绍了全局主控Agent的架构设计与实现,该组件作为智能对话系统的统一指挥中心,提供标准化的多模式处理接口。系统支持普通对话、工具命令执行和流式响应三种处理模式,通过智能工作流路由协调多个处理引擎。统一的消息封装和异步架构设计确保了系统的高性能和可扩展性,已成功处理300万次用户请求,平均响应时间1.2秒。

在科技的浪潮中,我们寻找着创新的火种,在代码的海洋里,我们编织着智慧的网。腾飞开源,就是这样一个由技术精英汇聚而成的博客平台,我们致力于分享在Java、Python、IoT和人工智能等领域的最新研究成果和实战经验。 在腾飞开源的博客上,你会看到紧跟技术前 339

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

linux网络协议栈arp_process

/* * Process an arp request. */ static int arp_process(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct in_device *in_dev = __in_dev_get_rcu(dev); struct arphdr *arp; unsigned char *arp_ptr; struct rtable *rt; unsigned char *s..

徐维溢的博客 937

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Linux中arp表的老化机制

转发网址:https://www.cnblogs.com/lsgxeva/p/13749751.html Linux内核网络协议栈中自动维护着一堆网络协议,这堆网络协议在内核中也是不同的存在,对于arp,Linux内核就提供了一种缓存机制来维护这张表。 实际的使用场景是,网络设备维护的arp表与内核维护的arp表相同步,一旦有变化,便通过钩子通知到上层的arp模块。但对于网络设备的arp模块来说,还需要实现一个arp老化时间的功能,这个功能的实现便也依靠了linux内核的arp表老化。 内核是如何维护

caofengtao1314的专栏 4739

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

linux kernel子系统,Linux网络子系统内核分析

1.选择路由若要将数据包发至PC2,则Linux系统通过查询路由表可知168.1.1.10(目的地址)的网关地址为192.168.1.1,此时Linux系统选择网卡1发送数据包。2.邻居子系统(通过arp协议建立起邻居的信息)选择网卡1发送数据时,首先将数据包发给邻居(网关),再由邻居转发至后面,若要发送给邻居,则必须知道邻居的MAC地址,若不知道邻居的MAC地址,则需要通过arp请求包获取邻居的...

weixin_29863809的博客 414

Linux 邻接(Neighbor)子系统架构与 NUD 状态机

从内核研发的视角看,一切网络协议皆为“状态机+队列”的折腾与调度。邻接子系统利用一个优雅精湛的 NUD 状态检测图,实现了网络上层发送操作解耦、底层的异步等待容错,以及海量缓存重试功能。掌握了及其迁移逻辑,以后面对玄学的“局域网丢包”和“首包高延迟”,你也能做到了然于胸。

huayidw的博客 732

《TRex设计与实现》:五、邻居协议

TRex支持多种邻近协议测试功能,包括ARP、ICMP和IPv6邻居发现。通过服务模式切换,用户可通过控制台或API执行DUT测试。v2.50版本新增Linux命名空间支持,允许将多个网络命名空间绑定到物理接口,每个命名空间可独立配置网络参数并模拟真实客户端。

专注于网络通信领域的农民工 1164

Linux 网络设备驱动开发(三)-网卡驱动深层分析

之前我们介绍了网卡是怎么把一个数据包发送到网络上的,但是这只是Linux网络系统中的一个非常小的部分。对于内核怎么把用户数据传递给网卡,以及内核怎么把网卡收到的数据传递给用户是一个庞大的知识。 学过计算机网络的都知道,当用户需要发送数据的时候,需要根据路由表找到数据包下一站该发送到哪个路由器,这个路由器叫做这个网卡的邻居。如果邻居的MAC地址不知道,还需要通过ARP协议获取的路由去的MAC地址,这个过程交给邻居子系统来完成。 分析过程还是依据第一节课中的5层模型来分析: 1、系统调用接口 2、协议无关层 3

canwang的博客 777
上一篇: linux网络协议栈分析笔记8-arp邻居子系统1
下一篇: linux网络协议栈分析笔记10-arp邻居子系统3
白水煮鸡蛋
博客等级 码龄15年 106粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值