邻居,可以简单理解为三层上的一跳距离。路由的下一跳可以不是直连的一跳距离(迭代路由),但最终走到邻居子系统的时候就是一跳距离。
linux 迭代路由的用法: https://www.jianshu.com/p/070202b6d3ca

邻居子系统,提供三层地址到二层地址之间的映射,提供二层首部缓存加速二层头的封装,提供二层报文头的封装。
如下,邻居表信息,表达了IP地址是x.x.x.x的下一跳,它的mac地址是xx:xx:xx:xx:xx:xx,通过出接口ethx能够到达。

#ip neigh
172.16.10.34 dev eth1 lladdr 52:54:00:8f:77:cd STALE
172.16.100.2 dev eth1 lladdr 00:1e:08:0a:53:01 STALE
192.168.122.1 dev eth2 lladdr 52:54:00:7a:39:1c STALE
172.16.100.3 dev eth1 lladdr 00:1e:08:0a:b2:f7 STALE
172.16.0.2 dev eth1 lladdr 00:1e:08:15:18:65 STALE
172.16.0.1 dev eth1 lladdr 50:c5:8d:b4:3e:81 REACHABLE
1.1.1.1 dev eth0 lladdr 52:54:00:e4:f7:11 PERMANENT
192.168.121.1 dev eth0 lladdr 52:54:00:8a:20:74 STALE
20.1.1.10 dev eth2.100 lladdr 52:54:00:e4:f7:2a STALE

除此之外,每个表项还有一个状态,需要了解一下其含义,无论是实际环境还是阅读代码都很重要。


/**	Neighbor Cache Entry States.*/#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
#define NUD_PERMANENT	0x80
#define NUD_NONE	0x00/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never changeand make no address resolution or NUD.NUD_PERMANENT is also cannot be deleted by garbage collectors.*/#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)
#define NUD_CONNECTED	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)

下面这张状态机图描述的很清楚。
image.png

NUD_INCOMPLETE  :该状态是请求报文已发送,但尚未收到应答的状态。该状态下还没解析到硬件地址,因此尚无可用硬件地址,如果有报文要输出到该邻居,会将其缓存起来。
这个状态会启动一个定时器,如果在定时器到期时还没有接收到邻居的回应,则会重复发送请求报文,否则发送请求报文的次数打到上限,便会进入NUD_FAILED。
NUD_REACHABLE :该状态以及得到并缓存了邻居的硬件地址。进入该状态首先设置邻居项相关的output函数(该状态使用neighbors_ops结构的connectd_outpt),然后查看是否存在要发送给该邻居的报文。如果在该状态下闲置时间达到上限,便会进入NUD_STATLE。
NUD_STALE :该状态一旦有报文要输出到该邻居,则会进入NUD_DELAY并将该报文输出。如果在该状态下闲置时间达到上限,且此时的引用计数为1,则通过垃圾回收机制将其删除,在该状态下,报文的输出不收限制,使用慢速发送过程
NUD_DELAY :该状态下表示NUD_STATE状态下发送的报文已经发出,需得到邻居的可达性确认的状态。在为接收到邻居的应答或确认时也会定时地重发请求,如果发送请求报文的次数到上限,如果收到邻居的应答,进入NUD_REACHABLE,否则进入NUD_FAILED,在该状态下,报文的输出不收限制,使用慢速发送过程。
NUD_PROBE :过渡状态,和NUD_INCOMPLETE 状态类似,在未收到邻居状态的应答或者确认时,也会定时的重发请求,直到收到邻居的应答、确认、或者尝试发送请求报文的次数达到上限,如果收到应答或者确认就会进入NUD_REACHABLE,如果尝试发送请求到达上限,则进入NUD_FAILD状态,在该状态,报文的输出也不受限制,使用慢速发送过程。
NUD_FAILED  :由于没有收到应答报文而无法访问状态,
NUD_NOARP   :标识邻居无需将三层地址协议映射到二层地址协议。如一些三层overlay的虚拟接口,loopback等。
NUD_PERMANENT : 设置邻居表项的硬件地址为静态。

相关数据结构

struct neigh_table 表示一种邻居协议接口,目前就ipv4的arp和ipv6的nd,由两个全局变量定义,ipv4= arp_tbl, ipv6=nd_tbl。

// ipv4= arp_tbl, ipv6=nd_tbl
struct neigh_table {int			family;           // ipv4\ipv6int			entry_size;    // 邻居表项结构的大小,包括邻居表项和其key的信息,对于ipv4,是根据ipv4地址查询neighbor表项的,所以=sizeof(neighbour)+4int			key_len;       // 就是上面用到的neighbor表项key,三层地址,arp就是ipv4地址__be16			protocol;     // 三层协议类型,ETH_P_IP 或者 ETH_P_IPV6__u32			(*hash)(const void *pkey,const struct net_device *dev,__u32 *hash_rnd);          // 表项hash函数,eg arp_hashbool			(*key_eq)(const struct neighbour *, const void *pkey);int			(*constructor)(struct neighbour *);int			(*pconstructor)(struct pneigh_entry *);void			(*pdestructor)(struct pneigh_entry *);void			(*proxy_redo)(struct sk_buff *skb);char			*id;                   //用来分配neighbour缓存的缓冲池,arp_tabl为arp_cachestruct neigh_parms	parms;      //存储与协议相关的可调节参数struct list_head	parms_list;   int			gc_interval;     // 这四个是垃圾回收的时间参数int			gc_thresh1;int			gc_thresh2;int			gc_thresh3;unsigned long		last_flush;struct delayed_work	gc_work;        // 垃圾回收的工作队列struct timer_list 	proxy_timer;struct sk_buff_head	proxy_queue;atomic_t		entries;                          // 所有邻居项的数目rwlock_t		lock;unsigned long		last_rand;struct neigh_statistics	__percpu *stats;struct neigh_hash_table __rcu *nht;struct pneigh_entry	**phash_buckets;  //存储邻居表项的散列表
};

struct neighbour 定义邻居表项,包括状态,二层和三层协议地址,缓存的二层首部,出接口,还有一些函数指针。

其中 output 为数据报文输出函数,用来将报文输出到邻居,其回调根据状态变化而变化,邻居可达时为 connected_output,NUD_CONNECTED 转换成 NUD_STALE 或者 NUD_DELAY,neigh_suspect 会强制进行可达性的确认,通过把 neighbor->output 指向 neigh_ops->output, 也就是 neigh_resolve_output。
neigh_ops 中定义了地址解析请求发送函数,数据报文发送函数(一个通用报文发送函数和一个connected状态下发送函数)。


struct neighbour {struct neighbour __rcu	*next;struct neigh_table	*tbl;                    // arp_tbl反指struct neigh_parms	*parms;              //用于调节邻居协议的参数unsigned long		confirmed;         //记录最近一次确认该邻居可达的时间,传输层通过neigh_confirm确认更新,邻居系统通过neigh_update 更新unsigned long		updated;           //记录最近一次被neigh_update 更新的时间rwlock_t		lock;atomic_t		refcnt;struct sk_buff_head	arp_queue;      // 在发送第一个报文时,需要新的邻居项,发送报文被缓存到arp_queue队列中,然后会调用solicit()发送请求报文。unsigned int		arp_queue_len_bytes;struct timer_list	timer;unsigned long		used;atomic_t		probes;__u8			flags;__u8			nud_state;__u8			type;__u8			dead;seqlock_t		ha_lock;unsigned char		ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];    // 与存储在primary_key 中的三层地址相对应的二层硬件地址struct hh_cache		hh;                                    // 指向缓存二层协议首部的hh_cache结构,完整的二层头,不只是二层地址// 输出函数,用来将报文输出到邻居,其回调根据状态变化而变化,邻居可达时为 connected_output;// NUD_REACHBLE 转换成 NUD_STALE 或者 NUD_DELAY,neigh_suspect 会强制进行可达性的确认,通过把 neighbor->output 指向 neigh_ops->output, 也就是 neigh_resolve_output	int			(*output)(struct neighbour *, struct sk_buff *);   const struct neigh_ops	*ops;          // 邻居项函数指针:实现了三层到二层dev_queue_xmitstruct rcu_head		rcu;struct net_device	*dev;              // 通过此网络设备可以访问到改邻居,即下一跳出接口u8			primary_key[0];     //存储哈希函数使用的三层协议地址,ipv4 或 ipv6地址
};

在创建邻居表项调用__neigh_create时,会调用neighbor的构造函数,arp协议就是arp_constructor,对邻居表项进行了初始化,根据设备类型和特性支持挂载了不同的output 和 ops函数。


struct neigh_ops {int            family;void            (*solicit)(struct neighbour *, struct sk_buff *);// 发送请求报文函数。在发送一个报文时,需要更新邻居表项,发送报文会缓存到arp_queue中,然后调用solicit函数发送请求报文。void            (*error_report)(struct neighbour *, struct sk_buff *); // 邻居项缓存着未发送的报文,而该邻居项又不可达时, 被调用来向三层报告错误的函数。int            (*output)(struct neighbour *, struct sk_buff *); //通用输出报文函数,做邻居状态等校验,流程上会比connected_output 慢一些int            (*connected_output)(struct neighbour *, struct sk_buff *);//当邻居可达NUD_CONNECT的时候,肯定处于邻居可用状态,直接构造和封装二层头发送。
};// 不支持 header cache的设备
static const struct neigh_ops arp_generic_ops = {.family =		AF_INET,.solicit =		arp_solicit,.error_report =		arp_error_report,.output =		neigh_resolve_output,.connected_output =	neigh_connected_output,
};// 支持header cache的设备
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,
};
// 无头处理设备,直接做报文发送,封装的dev_queue_xmit
static const struct neigh_ops arp_direct_ops = {.family =		AF_INET,.output =		neigh_direct_output,.connected_output =	neigh_direct_output,
};static int arp_constructor(struct neighbour *neigh)
{__be32 addr = *(__be32 *)neigh->primary_key;struct net_device *dev = neigh->dev;struct in_device *in_dev;struct neigh_parms *parms;rcu_read_lock();in_dev = __in_dev_get_rcu(dev);if (!in_dev) {rcu_read_unlock();return -EINVAL;}neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr);parms = in_dev->arp_parms;__neigh_parms_put(neigh->parms);neigh->parms = neigh_parms_clone(parms);rcu_read_unlock();// 没有头操作,就不需要做二层封装,也不需要arp,几个output函数都是直接调用dev_queue_xmit发送if (!dev->header_ops) {neigh->nud_state = NUD_NOARP;neigh->ops = &arp_direct_ops;neigh->output = neigh_direct_output;} else {/* Good devices (checked by reading texts, but only Ethernet istested)ARPHRD_ETHER: (ethernet, apfddi)ARPHRD_FDDI: (fddi)ARPHRD_IEEE802: (tr)ARPHRD_METRICOM: (strip)ARPHRD_ARCNET:etc. etc. etc.ARPHRD_IPDDP will also work, if author repairs it.I did not it, because this driver does not work evenin old paradigm.*/// 邻居类型判断,组播、广播、P2P接口、loopback接口,打了NOARP的接口都不需要arpif (neigh->type == RTN_MULTICAST) {neigh->nud_state = NUD_NOARP;arp_mc_map(addr, neigh->ha, dev, 1);} else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) {neigh->nud_state = NUD_NOARP;memcpy(neigh->ha, dev->dev_addr, dev->addr_len);} else if (neigh->type == RTN_BROADCAST ||(dev->flags & IFF_POINTOPOINT)) {neigh->nud_state = NUD_NOARP;memcpy(neigh->ha, dev->broadcast, dev->addr_len);}// arp_generic_ops 和 arp_hh_ops 的最大区别是后者最二层头缓存,前者不需要而是使用硬件地址临时封装;// 支持二层头cache的设备才挂载 arp_hh_opsif (dev->header_ops->cache)neigh->ops = &arp_hh_ops;elseneigh->ops = &arp_generic_ops;// 可用状态挂载 connected_output,ops->connected_output 和 ops->output 的区别是前者不需要做邻居状态等信息// 的校验,从而更快if (neigh->nud_state & NUD_VALID)neigh->output = neigh->ops->connected_output;elseneigh->output = neigh->ops->output;}return 0;
}

IP报文发送的最后阶段,ip_finish_output2函数中通过邻居子系统将数据包输出到网络设备。
1、ip_finish_output2首先查询neighbor表项,如果不存在,调用__neigh_create创建并初始化邻居表项;
2、调用dst_neigh_output 函数发送数据报文。

  • neigh为NUD_CONNECTED 状态且缓存了报文头,直接贴头发送,就是常说的快转;neigh->hh 设置的时机,一个是在第一次进入NUD_CONNECTED状态后,发送数据报文时(正常流程应该是缓存的报文)调用neigh_hh_init 制作二层头;二是在neigh_update中更新neigh状态时,如果二层地址发生变化,调用neigh_update_hhs更新二层头。
  • 否则调用neigh->output,当 neigh 进入 NUD_CONNECTED , neigh_connect 把 neigh->output 的函数指向 neigh->ops->connected_output,此时neighbor中已经保存了邻居二层地址,它会在调用 dev_queue_xmit 之前填充 L2 头部,把包直接发出去。当从 NUD_REACHBLE 转换成 NUD_STALE|NUD_DELAY ,neigh_suspect 会强制进行可达性的确认,通过把neighbor->output 指向 neigh_ops->output, 也就是 neigh_resolve_output。其中根据neigh的状态不同流程也有很大不同,函数中做了较详细的注解。
/** 此函数通过邻居子系统将数据包输出到网络设备。*/
static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
{struct dst_entry *dst = skb_dst(skb);struct rtable *rt = (struct rtable *)dst;struct net_device *dev = dst->dev;unsigned int hh_len = LL_RESERVED_SPACE(dev);struct neighbour *neigh;u32 nexthop;if (rt->rt_type == RTN_MULTICAST) {IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTMCAST, skb->len);} else if (rt->rt_type == RTN_BROADCAST)IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len);/* Be paranoid, rather than too clever. */if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {struct sk_buff *skb2;skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));if (!skb2) {kfree_skb(skb);return -ENOMEM;}if (skb->sk)skb_set_owner_w(skb2, skb->sk);consume_skb(skb);skb = skb2;}if (lwtunnel_xmit_redirect(dst->lwtstate)) {int res = lwtunnel_xmit(skb);if (res < 0 || res == LWTUNNEL_XMIT_DONE)return res;}rcu_read_lock_bh();// 从路由中取下一跳,分两种情况,指定下一跳的从路由的 rt_gateway 取,未指定路由的,取报文的dst ip// 这就是前面我们说的配置路由时指定nexthop和不指定的区别,不指定后面会构造请求dst ip mac的arp报文nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);// 正式进入 neighbor 子系统,发送流程,路由的本质是找到下一跳,而下一跳是通过 neighbor 子系统 管理的neigh = __ipv4_neigh_lookup_noref(dev, nexthop);if (unlikely(!neigh))neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);if (!IS_ERR(neigh)) {int res = dst_neigh_output(dst, neigh, skb);rcu_read_unlock_bh();return res;}rcu_read_unlock_bh();net_dbg_ratelimited("%s: No header cache and no neighbour!\n",__func__);kfree_skb(skb);return -EINVAL;
}static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,struct sk_buff *skb)
{const struct hh_cache *hh;if (dst->pending_confirm) {unsigned long now = jiffies;dst->pending_confirm = 0;/* avoid dirtying neighbour */if (n->confirmed != now)n->confirmed = now;}/*// neigh为NUD_CONNECTED 状态且缓存了报文头,直接贴头发送,就是常说的快转模式;//否则,需要根据当前的nud_state 状态,调用不同的函数处理// * 当 neigh 进入 NUD_CONNECTED , neigh_connect 把 neigh->output 的函数指向 neigh->ops->connected_output,也就是 neigh_connected_output,它会在调用 dev_queue_xmit 之前填充 L2 头部,把包直接发出去。* 当从 NUD_REACHBLE 转换成 NUD_STALE ,neigh_suspect 会强制进行可达性的确认,通过把 neighbor->output 指向 neigh_ops->output, 也就是 neigh_resolve_output。*/hh = &n->hh;if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)return neigh_hh_output(hh, skb);elsereturn n->output(n, skb);
}
int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
{int rc = 0;/* neigh_event_send,完成收到数据报文后的邻居表项状态校验,同时作为邻居子系统状态机的一部分,是一个事件入口,完成状态机操作如第一次收到数据报文,会触发状态NUD_NONE -> NUD_INCOMPLETE、缓存报文、发送arp request等。详细流程见函数内注解函数返回 1 表示无法直接发送数据报文(丢弃或缓存),0 表示可以发送数据报文*/ if (!neigh_event_send(neigh, skb)) {int err;struct net_device *dev = neigh->dev;unsigned int seq;// 制作二层头cache,支持的设备 cache函数不为空,如eth口,eth_header_cacheif (dev->header_ops->cache && !neigh->hh.hh_len)neigh_hh_init(neigh);do {// 构造并封装二层头,注意上面的二层 header cache 在 dst_neigh_output 函数中使用,// 只有在没有cache的时候才会走到这里__skb_pull(skb, skb_network_offset(skb));seq = read_seqbegin(&neigh->ha_lock);err = dev_hard_header(skb, dev, ntohs(skb->protocol),neigh->ha, NULL, skb->len);} while (read_seqretry(&neigh->ha_lock, seq));if (err >= 0)// 发送数据报文rc = dev_queue_xmit(skb);elsegoto out_kfree_skb;}
out:return rc;
out_kfree_skb:rc = -EINVAL;kfree_skb(skb);goto out;
}
EXPORT_SYMBOL(neigh_resolve_output);/* As fast as possible without hh cache */int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb)
{struct net_device *dev = neigh->dev;unsigned int seq;int err;// connected状态下,不需要做状态校验do {// 构造并封装二层头,注意上面的二层 header cache 在 dst_neigh_output 函数中使用,// 只有在没有cache的时候才会走到这里__skb_pull(skb, skb_network_offset(skb));seq = read_seqbegin(&neigh->ha_lock);err = dev_hard_header(skb, dev, ntohs(skb->protocol),neigh->ha, NULL, skb->len);} while (read_seqretry(&neigh->ha_lock, seq));if (err >= 0)// 发送数据报文err = dev_queue_xmit(skb);else {err = -EINVAL;kfree_skb(skb);}return err;
}
EXPORT_SYMBOL(neigh_connected_output);

上面 neigh_resolve_output 调用的的 neigh_event_send 比较重要。涉及一些非稳定状态下的状态机迁移。特别是数据报文触发的邻居地址解析流程也在里面。
状态机是什么,状态机元素包括event、state、action,可以概括为: 某一个状态下,收到某个事件,触发一个动作,使动作迁移到新的状态。状态机可以从事件入口去看。邻居子系统的一些事件更新状态及的入口如:
neigh_timer_handler,定时器超时事件导致的状态机更新
neigh_event_send,数据报文接收事件导致的状态机更新
neigh_update,协议报文接收事件导致的状态机更新,这个实际上不准确,直接的状态运行是在调用它的函数中,如收到arp request/reply报文(arp_process),静态配置arp表项(neigh_add)等。


static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{unsigned long now = jiffies;if (neigh->used != now)neigh->used = now;// 邻居状态的这几个状态对于数据报文接收事件是稳定状态,这里不需要做任何action,特别是第一个,// NUD_DELAY|NUD_PROBE 状态需要等待邻居地址解析应答报文到来或者定时器超时来确认下一个状态。if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE)))return __neigh_event_send(neigh, skb);return 0;
}int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
{int rc;bool immediate_probe = false;write_lock_bh(&neigh->lock);rc = 0;// 邻居状态可用,返回0,可以做报文发送if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))goto out_unlock_bh;// dead,不可用,释放报文if (neigh->dead)goto out_dead;// 这里是简单的状态机处理,加上 neigh_timer_handlerif (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {// NUD_NONE 状态分支// 对应/proc/sys/net/ipv4/neigh/eth1/ 下的 mcast_solicit 和 app_solicit配置,// 控制使用发送邻居地址探测报文的次数,不为0则可以做探测,否则 nud_state = NUD_FAILED并释放报文if (NEIGH_VAR(neigh->parms, MCAST_PROBES) +NEIGH_VAR(neigh->parms, APP_PROBES)) {unsigned long next, now = jiffies;atomic_set(&neigh->probes,NEIGH_VAR(neigh->parms, UCAST_PROBES));// NUD_NONE -> NUD_INCOMPLETEneigh->nud_state     = NUD_INCOMPLETE;neigh->updated = now;next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME),HZ/2);neigh_add_timer(neigh, next);// 第一次,会立即出发arp requestimmediate_probe = true;} else {// NUD_NONE -> NUD_FAILEDneigh->nud_state = NUD_FAILED;neigh->updated = jiffies;write_unlock_bh(&neigh->lock);kfree_skb(skb);return 1;}} else if (neigh->nud_state & NUD_STALE) {// NUD_STALE 需要发送报文时,立即切换为 NUD_DELAY 状态,并触发定时器(处理函数=neigh_timer_handler),其// 会调用 neigh_probe --> neigh->ops->solicit 构造arp requet// NUD_CONNECTED | NUD_DELAY | NUD_PROBE | NUD_STALE 状态下数据报文都能正常发送,不需要缓存报文neigh_dbg(2, "neigh %p is delayed\n", neigh);neigh->nud_state = NUD_DELAY;neigh->updated = jiffies;neigh_add_timer(neigh, jiffies +NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME));}// NUD_INCOMPLETE 状态下,缓存数据报文,此时arp request报文已经发出去了,等待reply或定时器超时即可// 返回1,外面什么不做if (neigh->nud_state == NUD_INCOMPLETE) {if (skb) {while (neigh->arp_queue_len_bytes + skb->truesize >NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) {struct sk_buff *buff;buff = __skb_dequeue(&neigh->arp_queue);if (!buff)break;neigh->arp_queue_len_bytes -= buff->truesize;kfree_skb(buff);NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards);}skb_dst_force(skb);__skb_queue_tail(&neigh->arp_queue, skb);neigh->arp_queue_len_bytes += skb->truesize;}rc = 1;}
out_unlock_bh:if (immediate_probe)// neigh_probe 调用neigh->ops->solicit发送地址解析请求报文,// immediate_probe=false的情况下(如上面切换 NUD_DELAY 状态)等定时器超时(neigh_timer_handler),// 也会调用 neigh_probeneigh_probe(neigh);elsewrite_unlock(&neigh->lock);local_bh_enable();return rc;out_dead:if (neigh->nud_state & NUD_STALE)goto out_unlock_bh;write_unlock_bh(&neigh->lock);kfree_skb(skb);return 1;
}
EXPORT_SYMBOL(__neigh_event_send);

以arp协议为例,收到协议报文,neighbor的状态变化。
arp_process 函数在内核中处理一个arp报文,简单概括:
1、收到arp request:
  1)如果tip是本机,使用收包接口设备(并不是tip所在的接口)的mac应答arp reply,并学习sip的arp表项。
  2)如果tip地址类型不是本地(tip的路由是转发类型的),且接收设备支持转发,这种情况下如果开启了代理arp功能,则做arp 代理处理,即用自己的mac地址回arp reply,将流量引到本设备(一般是网关设备)。并学习sip的arp表项。
  3)tip不是本地ip,接收设备又没有配置arp proxy,甚至tip在本地查不到路由的情况,则只有收到的是免费arp会触发学习sip的arp表项。其它情况不会创建表项,防止大量表项但实际上又用不到。
  4)收到arp request,会将本机已经存在或者新建的邻居表项修改为stale状态。
2、收到的是arp reply,修改邻居表项为 NUD_REACHABLE状态。
3、更新邻居表项状态附带的操作:
  1)更换 neigh->output 数据报文输出函数,NUD_CONNECTED指向ops->connected_output,其他指向ops->output;
  2)arp报文中新的二层地址(无论是sip的smac 还是tip的dmac),更新neighbor表项的二层地址和二层头cache;
  3)reset 状态及超时定时器;
  4)状态如果从 ! NUD_VALID --> NUD_VALID状态,说明邻居从不可用到可用,会将表项上缓存的报文发送出去。

static int arp_process(struct net *net, struct sock *sk, 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 *sha;__be32 sip, tip;u16 dev_type = dev->type;int addr_type;struct neighbour *n;struct dst_entry *reply_dst = NULL;bool is_garp = false;/* arp_rcv below verifies the ARP header and verifies the device* is ARP'able.*/if (!in_dev)goto out_free_skb;arp = arp_hdr(skb);// arp 报文合法性校验switch (dev_type) {default:if (arp->ar_pro != htons(ETH_P_IP) ||htons(dev_type) != arp->ar_hrd)goto out_free_skb;break;case ARPHRD_ETHER:case ARPHRD_FDDI:case ARPHRD_IEEE802:/** ETHERNET, and Fibre Channel (which are IEEE 802* devices, according to RFC 2625) devices will accept ARP* hardware types of either 1 (Ethernet) or 6 (IEEE 802.2).* This is the case also of FDDI, where the RFC 1390 says that* FDDI devices should accept ARP hardware of (1) Ethernet,* however, to be more robust, we'll accept both 1 (Ethernet)* or 6 (IEEE 802.2)*/if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&arp->ar_hrd != htons(ARPHRD_IEEE802)) ||arp->ar_pro != htons(ETH_P_IP))goto out_free_skb;break;case ARPHRD_AX25:if (arp->ar_pro != htons(AX25_P_IP) ||arp->ar_hrd != htons(ARPHRD_AX25))goto out_free_skb;break;case ARPHRD_NETROM:if (arp->ar_pro != htons(AX25_P_IP) ||arp->ar_hrd != htons(ARPHRD_NETROM))goto out_free_skb;break;}/* Understand only these message types */if (arp->ar_op != htons(ARPOP_REPLY) &&arp->ar_op != htons(ARPOP_REQUEST))goto out_free_skb;/**	Extract fields*/// arp 头信息提取arp_ptr = (unsigned char *)(arp + 1);sha	= arp_ptr;arp_ptr += dev->addr_len;memcpy(&sip, arp_ptr, 4);arp_ptr += 4;switch (dev_type) {
#if IS_ENABLED(CONFIG_FIREWIRE_NET)case ARPHRD_IEEE1394:break;
#endifdefault:arp_ptr += dev->addr_len;}memcpy(&tip, arp_ptr, 4);
/**	Check for bad requests for 127.x.x.x and requests for multicast*	addresses.  If this is one such, delete it.*/if (ipv4_is_multicast(tip) ||(!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip)))goto out_free_skb;/**	For some 802.11 wireless deployments (and possibly other networks),*	there will be an ARP proxy and gratuitous ARP frames are attacks*	and thus should not be accepted.*/if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP))goto out_free_skb;/**     Special case: We must set Frame Relay source Q.922 address*/if (dev_type == ARPHRD_DLCI)sha = dev->broadcast;if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb))reply_dst = (struct dst_entry *)iptunnel_metadata_reply(skb_metadata_dst(skb),GFP_ATOMIC);/* Special case: IPv4 duplicate address detection packet (RFC2131) */// sip==0,是dhcp服务器用来检测它所分发的地址释放重复if (sip == 0) {if (arp->ar_op == htons(ARPOP_REQUEST) &&inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL &&!arp_ignore(in_dev, sip, tip))arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip,sha, dev->dev_addr, sha, reply_dst);goto out_consume_skb;}// arp请求报文,需要能查到tip的路由,正常情况下tip应该是本机ipif (arp->ar_op == htons(ARPOP_REQUEST) &&ip_route_input_noref(skb, tip, sip, 0, dev) == 0) {rt = skb_rtable(skb);addr_type = rt->rt_type;// 如果是本地路由,说明请求本机IP地址的二层地址if (addr_type == RTN_LOCAL) {int dont_send;// 两个arp控制的特性过滤,对应的都有系统参数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) {// neigh_event_ns中会做src ip的邻居表项的学习,新建或更新邻居表项。更新neighbor为stale状态n = neigh_event_ns(&arp_tbl, sha, &sip, dev);if (n) {// 发送arp reply,不管tip实际在哪个dev,lladdr都用的报文接收devarp_send_dst(ARPOP_REPLY, ETH_P_ARP,sip, dev, tip, sha,dev->dev_addr, sha,reply_dst);// neigh->refcnt--,新建的至少还剩下1(neigh_alloc和__neigh_create分别hold一次)neigh_release(n);}}goto out_consume_skb;} else if (IN_DEV_FORWARD(in_dev)) {/* 地址类型不是本地,TIP的路由是转发类型的,且接收设备支持转发,如果开启了代理arp功能,则做arp 代理即用自己的mac地址回arp reply,将流量引到本设备(一般是网关设备)net.ipv4.conf.xx.proxy_arp == 是否启用arpnet.ipv4.conf.xx.proxy_arp_pvlan 回应代理arp的数据包从接收此代理arp请求的接口发出去 */if (addr_type == RTN_UNICAST  &&(arp_fwd_proxy(in_dev, dev, rt) ||arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||(rt->dst.dev != dev &&pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) {// 同样是做src ip的邻居表项的学习,新建或更新邻居表项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 ||NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) {// 发送代理arp replyarp_send_dst(ARPOP_REPLY, ETH_P_ARP,sip, dev, tip, sha,dev->dev_addr, sha,reply_dst);} else {// arp proxy延时处理,skb入proxy_queue,其定时器pneigh_enqueue(&arp_tbl,in_dev->arp_parms, skb);goto out_free_dst;}goto out_consume_skb;}}}/* Update our ARP tables */// 1、arp reply处理,更新邻居状态// 2、arp request的某些情况,如未找到tip的路由、非本地tip,但是又未开arp proxy。这些情况不需要回reply,但也更新邻居状态n = __neigh_lookup(&arp_tbl, &sip, dev, 0);if (IN_DEV_ARP_ACCEPT(in_dev)) {unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);/* Unsolicited ARP is not accepted by default.It is possible, that this option should be enabled for somedevices (strip is candidate)*/is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&addr_type == RTN_UNICAST;// 如果本地neighbor表项不存在,arp reply包会触发新建neigh,// arp request走到这里要么找不到tip路由,要么tip非local,只会创建免费arp request的邻居表项,// 其他忽略,否则可能创建大量表项但实际上又用不到if (!n &&((arp->ar_op == htons(ARPOP_REPLY)  &&addr_type == RTN_UNICAST) || is_garp))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 proxyagents are active. Taking the first reply preventsarp trashing and chooses the fastest router.*/override = time_after(jiffies,n->updated +NEIGH_VAR(n->parms, LOCKTIME)) ||is_garp;/* Broadcast replies and request packetsdo not assert neighbour reachability.*/// reply包触发neighbor更新为 NUD_REACHABLE,request包更新为 NUD_STALEif (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);}out_consume_skb:consume_skb(skb);out_free_dst:dst_release(reply_dst);return NET_RX_SUCCESS;out_free_skb:kfree_skb(skb);return NET_RX_DROP;
}/*更新邻居状态,重置定时器更新二层地址、二层头cache,更新邻居数据报文发送函数,邻居可用后,发送缓存的数据报文
*/
int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,u32 flags)
{u8 old;int err;int notify = 0;struct net_device *dev;int update_isrouter = 0;write_lock_bh(&neigh->lock);dev    = neigh->dev;old    = neigh->nud_state;err    = -EPERM;if (!(flags & NEIGH_UPDATE_F_ADMIN) &&(old & (NUD_NOARP | NUD_PERMANENT)))goto out;if (neigh->dead)goto out;// 进入NUD_FAILED 状态,释放一些资源(定时器、缓存报文)if (!(new & NUD_VALID)) {neigh_del_timer(neigh);if (old & NUD_CONNECTED)neigh_suspect(neigh);neigh->nud_state = new;err = 0;notify = old & NUD_VALID;if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&(new & NUD_FAILED)) {// (NUD_INCOMPLETE | NUD_PROBE)状态下,可能缓存了数据报文或arp报文,这里释放掉neigh_invalidate(neigh);notify = 1;}goto out;}/* Compare new lladdr with cached one */// 取新得二层地址if (!dev->addr_len) {/* First case: device needs no address. */lladdr = neigh->ha;} else if (lladdr) {/* The second case: if something is already cachedand a new address is proposed:- compare new & old- if they are different, check override flag*/if ((old & NUD_VALID) &&!memcmp(lladdr, neigh->ha, dev->addr_len))lladdr = neigh->ha;} else {/* No address is supplied; if we know something,use it, otherwise discard the request.*/err = -EINVAL;if (!(old & NUD_VALID))goto out;lladdr = neigh->ha;}if (new & NUD_CONNECTED)neigh->confirmed = jiffies;neigh->updated = jiffies;/* If entry was valid and address is not changed,do not change entry state, if new one is STALE.*/err = 0;update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER;if (old & NUD_VALID) {if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) {update_isrouter = 0;if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) &&(old & NUD_CONNECTED)) {lladdr = neigh->ha;new = NUD_STALE;} elsegoto out;} else {if (lladdr == neigh->ha && new == NUD_STALE &&!(flags & NEIGH_UPDATE_F_ADMIN))new = old;}}// reset定时器,修改neigh状态if (new != old) {neigh_del_timer(neigh);if (new & NUD_PROBE)atomic_set(&neigh->probes, 0);if (new & NUD_IN_TIMER)neigh_add_timer(neigh, (jiffies +((new & NUD_REACHABLE) ?neigh->parms->reachable_time :0)));neigh->nud_state = new;notify = 1;}// 更新二层地址、更新二层头cacheif (lladdr != neigh->ha) {write_seqlock(&neigh->ha_lock);memcpy(&neigh->ha, lladdr, dev->addr_len);write_sequnlock(&neigh->ha_lock);neigh_update_hhs(neigh);if (!(new & NUD_CONNECTED))neigh->confirmed = jiffies -(NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1);notify = 1;}if (new == old)goto out;// 更换 neigh->output 函数,NUD_CONNECTED指向ops->connected_output,其他指向ops->outputif (new & NUD_CONNECTED)neigh_connect(neigh);elseneigh_suspect(neigh);if (!(old & NUD_VALID)) {// 走到这里 new 是 NUD_VALID的,old如果是!NUD_VALID,说明邻居从不可用到可用,可以发送缓存的数据报文了struct sk_buff *skb;/* Again: avoid dead loop if something went wrong */while (neigh->nud_state & NUD_VALID &&(skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {struct dst_entry *dst = skb_dst(skb);struct neighbour *n2, *n1 = neigh;write_unlock_bh(&neigh->lock);rcu_read_lock();/* Why not just use 'neigh' as-is?  The problem is that* things such as shaper, eql, and sch_teql can end up* using alternative, different, neigh objects to output* the packet in the output path.  So what we need to do* here is re-lookup the top-level neigh in the path so* we can reinject the packet there.*/n2 = NULL;if (dst) {n2 = dst_neigh_lookup_skb(dst, skb);if (n2)n1 = n2;}n1->output(n1, skb);if (n2)neigh_release(n2);rcu_read_unlock();write_lock_bh(&neigh->lock);}__skb_queue_purge(&neigh->arp_queue);neigh->arp_queue_len_bytes = 0;}
out:if (update_isrouter) {neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ?(neigh->flags | NTF_ROUTER) :(neigh->flags & ~NTF_ROUTER);}write_unlock_bh(&neigh->lock);if (notify)neigh_update_notify(neigh);return err;
}
EXPORT_SYMBOL(neigh_update);
查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. A41网页前端第一次培训

    学习网址&#xff1a;【优极限】 HTMLCSSJavaScriptjQuery前端必学教程&#xff0c;小白教学&#xff0c;前端基础全套完成版_哔哩哔哩_bilibili 1.安装hbuilder X 了解如何使用该软件 2.了解HTML主要标签作用 <!--标题标签h1~h6大小依次递减尽量减少使用标题标签-->…...

    2024/4/18 4:38:52
  2. MeterSphere之项目设置

    MeterSphere模型我们可以这样理解 系统: 每个独立部署的 MeterSphere 即称为一套系统 系统级角色: 角色的权限范围为整个系统&#xff0c;常见的角色&#xff0c;如系统管理员&#xff0c;可管理整个系统内的租户、用户及测试资源, 同时可变更修改系统级配置参数 工作空间&…...

    2024/4/18 23:39:01
  3. 《SELF-ATTENTION GENERATIVE ADVERSARIAL NETWORKFOR SPEECH ENHANCEMENT》

    研究动机 现存的GAN模型都是依赖CNN的&#xff0c;没有考虑到时序依赖&#xff0c;为了解决时序问题&#xff0c;本文提出了基于自注意力机制的SEGAN网络。 INTRODUCTION 一方面&#xff0c;自注意力机制成功用到语音任务上的时序任务&#xff1b;另一方面&#xff0c;该机制在…...

    2024/4/26 11:41:53
  4. 【算法2-2】线性复杂度优化 / 离散化

    P1950 长方形 题目链接&#xff1a;P1950 长方形 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include <iostream> #include <stack> #include <cstring> using namespace std; char a[1010][1010]; int h[1010], g1[1010], g2[1010];int main() {long…...

    2024/4/13 18:03:28
  5. Pytorch(0)-环境搭建

    1.anaconda下载 2.查看是否有独立显卡以确定 Pytorch的下载参数 3.安装Pytorch 1.anaconda下载 Anaconda | Individual Edition 2.查看是否有独立显卡以确定 Pytorch的下载参数 3种查看方式 &#xff1a; 1.任务管理器-GPU型号 2.设备管理器3.命令行 nvidia-sm…...

    2024/4/13 18:03:38
  6. 『迷你教程』递归神经网络及数学赋权通俗理解

    文章目录什么是递归神经网络递归神经网络的训练RNN类型RNNS的优缺点不同RNN结构对于序列或时间序列数据&#xff0c;传统的前馈网络&#xff08; feedforward networks &#xff09;不能用于 Train 和 Prediction。需要一种能够保留过去或历史信息的机制来预测未来的价值。递归…...

    2024/4/19 13:15:10
  7. 5.Java方法

    Java方法 什么是方法 System.out.println(); //System 代表的就是一个类&#xff0c;out就是该类下的一个对象&#xff0c;println()就是一个方法方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建&#xff0c;在其他地方被引用方法的设计原则就是要…...

    2024/4/17 1:27:23
  8. 解决spring-boot项目的yml文件没有绿叶子图标

    大坑...

    2024/4/26 22:01:21
  9. Nginx 配置高可用的集群

    一 配置 /etc/keepalived/keepalivec.conf 配置文件 # 全局定义 global_defs {notification_email {acassenfirewall.locfailoverfirewall.locsysadminfirewall.loc}notification_email_from Alexandre.Cassenfirewall.locsmtp_server 192.168.17.129smtp_connect_timeout 30r…...

    2024/4/13 18:04:23
  10. Android自定义控件:带你掌握一款多特效的智能loadingView

    } 下面以measureWidth为例&#xff1a; private int measureWidth(int widthMeasureSpec) { int result; int specMode MeasureSpec.getMode(widthMeasureSpec); int specSize MeasureSpec.getSize(widthMeasureSpec); //这里是精准模式&#xff0c;比如match_content,…...

    2024/4/18 15:56:02
  11. linux-网络协议栈1--从中断到上送协议栈

    注&#xff1a; 内核代码是 4.9 版本 协议栈从报文接收说起&#xff0c;报文接收从网卡驱动说起。 两种方式&#xff0c;NAPI 和 非NAPI。 NAPI(New API) 是Linux内核针对网络数据传输做出的一个优化措施。 其目的是在大量数据传输时&#xff0c; 在收到硬件中断后&#xff…...

    2024/4/17 21:46:44
  12. 指令集体系结构

    寄存器体系结构 指令集体系结构&#xff08;ISA&#xff09;几乎都划分到通用寄存器体系结构中&#xff0c;主要包括 寄存器-存储器ISA&#xff0c;在指令中访问存储器载入-存储ISA&#xff0c;通过载入或者存储指令来访问寄存器 存储器寻址在操作数对齐的情况下访问速度更快…...

    2024/4/13 18:04:13
  13. 单调队列_滑动窗口

    题目 给定一个大小为 n≤106 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; 该数组为 [1 3 -1 -3 5 3 6 7]&#xff0c;k 为 3。 窗口位置最…...

    2024/4/13 18:04:23
  14. 分类案例:XGB中的样本不均衡问题

    参数设置 分类问题中经常会存在样本不平衡的现象&#xff0c;XGB中存在着调节样本不平衡的参数scale_pos_weight&#xff0c;通常我们在参数中输入的是负样本量与正样本量之比分类案例 创建不平衡数据集import numpy as np import xgboost as xgb import matplotlib.pyplot as …...

    2024/4/5 3:12:11
  15. 『迷你教程』机器学习的算术、几何和谐波均值及Python实现

    文章目录什么是平均值&#xff1f;算术平均值几何平均数谐波平均值如何选择正确的均值&#xff1f;有没有听过均值分为 算术、几何和谐波均值 三种&#xff1f;是否知道这三者的联系和区别&#xff1f; 计算变量或数字列表的平均值是机器学习中的常见操作。 这是每天都可以直…...

    2024/4/19 5:11:22
  16. 面向对象入门(类和对象)

    day1-面向对象入门(类和对象) 知识点1-类和对象 java程序: 需求:打印数组中所有的元素,打印格式为: [元素1&#xff0c;元素2&#xff0c;元素3&#xff0c;元素&#xff0c;…&#xff0c;元素n] public class Test {public static void main(String[] args) {/*面向过程编程…...

    2024/4/13 18:04:08
  17. 6-PACK: Category-level 6D Pose Tracker with Anchor-Based Keypoints学习笔记

    摘要 提出了一种基于RGB-D数据的类别级6D物体姿态跟踪的深度学习方法–6-PACK(6-Pack)。我们的方法实时跟踪已知对象类别(如碗、笔记本电脑和杯子)的新颖对象实例。6-pack学习通过几个3D关键点紧凑地表示对象&#xff0c;基于这些关键点&#xff0c;可以通过关键点匹配来估计对…...

    2024/4/13 18:04:03
  18. Linux-迭代路由

    Linux 的迭代路由的支持不像传统路由器那么好&#xff0c;用法比较特别。 如果这么配置&#xff0c;会提示网络不可达。 #ip addr 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2…...

    2024/4/13 18:04:13
  19. SpringCloud Day13---SpringCloud Alibaba Seata 处理分布式事务

    文章目录16. SpringCloud Alibaba Seata处理分布式事务16.1 分布式事务问题16.2 Seata简介16.2.1 是什么16.2.2 能干嘛16.2.3 去哪下16.2.4 怎么玩16.3 Seata-Server安装16.3.1 官网地址16.3.2 下载版本16.3.3 seata-server-0.9.0.zip解压到指定目录并修改conf目录下的file.con…...

    2024/4/13 18:04:38
  20. ipvlan-l3s模式

    ipvlan 三种模式&#xff0c;l2、l3、l3s&#xff0c;前两种网上资料很多&#xff0c;但第三种却很少&#xff0c;自己看了下代码记录一下。 为什么要看ipvlan&#xff1f;它特别适合做多租户nat场景&#xff0c;这种场景下&#xff0c;用户的内网VPC地址网段可能是重叠的&…...

    2024/4/19 10:53:00

最新文章

  1. 基于SpringBoot的“房产销售平台”的设计与实现(源码+数据库+文档+PPT)

    基于SpringBoot的“房产销售平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统整体模块图 登录窗口界面 房源信息管理窗口界…...

    2024/4/28 8:45:40
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. ROS2高效学习第十章 -- ros2 高级组件之大型项目中的 launch 其二

    ros2 高级组件之大型项目中的 launch 1 前言和资料2 正文2.1 启动 turtlesim&#xff0c;生成一个 turtle &#xff0c;设置背景色2.2 使用 event handler 重写上节的样例2.3 turtle_tf_mimic_rviz_launch 样例 3 总结 1 前言和资料 早在ROS2高效学习第四章 – ros2 topic 编程…...

    2024/4/28 3:06:27
  4. 图像处理相关知识 —— 椒盐噪声

    椒盐噪声是一种常见的图像噪声类型&#xff0c;它会在图像中随机地添加黑色&#xff08;椒&#xff09;和白色&#xff08;盐&#xff09;的像素点&#xff0c;使图像的质量降低。这种噪声模拟了在图像传感器中可能遇到的问题&#xff0c;例如损坏的像素或传输过程中的干扰。 椒…...

    2024/4/23 15:25:06
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/28 3:28:32
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/27 17:58:04
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/28 1:28:33
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/27 17:59:30
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/28 1:34:08
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/28 1:22:35
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/27 23:24:42
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/28 5:48:52
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57