当前位置: 首页 > wzjs >正文

免费行情软件网站有哪些网站推广专家十年乐云seo

免费行情软件网站有哪些,网站推广专家十年乐云seo,镇江网站建设费用,怎么用centos做网站文章目录 1. 前言2. skb 数据管理2.1 初始化2.2 数据的插入2.2.1 在头部插入数据2.2.2 在尾部插入数据 2.2 数据的移除 3. 小结 1. 前言 限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。 2. skb 数据管理 数…

文章目录

  • 1. 前言
  • 2. skb 数据管理
    • 2.1 初始化
    • 2.2 数据的插入
      • 2.2.1 在头部插入数据
      • 2.2.2 在尾部插入数据
    • 2.2 数据的移除
  • 3. 小结

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. skb 数据管理

数据结构:

/* include/linux/skbuff.h */struct sk_buff {.../** @len: sk_buff 包含的数据长度(sk_buff::tail - sk_buff::data). *       当在协议层间移动时, @len 会改变: 添加(往下层)或移除(往上层)*		 操作接口 skb_reserve(), skb_put(), skb_push(), skb_pull()*/unsigned int		len,data_len/* 仅用于分片场景下分片(fragment)数据的长度 */;__u16			mac_len/* MAC 头部长度 */,hdr_len;...__be16			protocol; /* ETH_P_IP, ... */__u16			transport_header; /* 传输层数据偏移 */__u16			network_header; /* 网络层数据偏移 */__u16			mac_header; /* MAC/Linker 层数据偏移 */.../* These elements must be at the end, see alloc_skb() for details.  *//** head --> -------------------*         | reserved headroom |* data -->|-------------------|*         |///|*         |///|* tail -->|-------------------|*         |      tailroom     |* end  -->|-------------------|*         |  skb_shared_info  |*         |-------------------|*         |       PAD         |*          -------------------*/sk_buff_data_t		tail; /* 偏移位置: 指向当前数据的尾部,随数据的添加、移除而改变 */sk_buff_data_t		end; /* 偏移位置: 可用数据空间的尾部。end 后还跟有 skb_shared_info */unsigned char		*head, /* 数据指针: 指向可用数据空间数据头部 */*data; /* 数据指针: 指向当前数据开始位置 */unsigned int		truesize; /* sizeof(sk_buff) + size(数据空间大小) + sizeof(skb_shared_info), 由 alloc_skb() 初始化 */refcount_t			users; /* sk_buff 引用计数. skb_get(), kfree_skb() 接口影响 */
};

2.1 初始化

创建 skb 时的初始化:

struct sk_buff *skb;
int frame_len; /* 网卡接收的数据帧长度 */frame_len = ...;
skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
/* include/linux/skbuff.h */static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,unsigned int length)
{return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC);
}static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,unsigned int length, gfp_t gfp)
{struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);if (NET_IP_ALIGN && skb)skb_reserve(skb, NET_IP_ALIGN); /* 在数据头部保留部分空间 */return skb;
}
/* net/core/skbuff.c */struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,gfp_t gfp_mask)
{struct page_frag_cache *nc;unsigned long flags;struct sk_buff *skb;bool pfmemalloc;void *data;/** 数据长度对齐:* 没有特别定义 NET_SKB_PAD 时,是对齐到 cache 行。*/len += NET_SKB_PAD;.../* skb_shared_info 包含在 skb 的数据(长度)内 */len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); len = SKB_DATA_ALIGN(len);...data = page_frag_alloc(nc, len, gfp_mask); /* 分配 @len 数据空间 */...skb = __build_skb(data, len); /* 用 @len 长度数据 @data 构建 skb */...skb_success:skb_reserve(skb, NET_SKB_PAD); /* 在数据头部保留部分空间 */skb->dev = dev; /* 设定 skb 的 所属的 网卡设备对象 */skb_fail:return skb;
}struct sk_buff *__build_skb(void *data, unsigned int frag_size)
{struct skb_shared_info *shinfo;struct sk_buff *skb;unsigned int size = frag_size ? : ksize(data);/* 创建 skb 对象 */skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);...size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));memset(skb, 0, offsetof(struct sk_buff, tail)); /* skb->tail 之前的所有成员清 0 */skb->truesize = SKB_TRUESIZE(size);refcount_set(&skb->users, 1);skb->head = data;skb->data = data;skb_reset_tail_pointer(skb); /* 初始化 tail: 指向数据开始的偏移位置,即 skb->data 所在的偏移位置 */skb->end = skb->tail + size;skb->mac_header = (typeof(skb->mac_header))~0U;skb->transport_header = (typeof(skb->transport_header))~0U;/* make sure we initialize shinfo sequentially */shinfo = skb_shinfo(skb);memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));atomic_set(&shinfo->dataref, 1);return skb;
}

我们用一张图来描述 skb 的初始状态:

在这里插入图片描述

skb 数据管理,主要依靠 tail, end, head, data 这几个成员。从图中可见,在初始时:

head: 指向数据的开始位置。
data: 指向可用数据的开始位置,跳过了头部保留空间。
tail: 当前已填充数据的结尾位置偏移。
end: 数据可用空间结尾位置偏移。

2.2 数据的插入

数据插入位置可以是 头部尾部

2.2.1 在头部插入数据

头部插入数据,首先通过 *skb_push() 系列 API 按插入数据长度移动数据位置指针,然后执行数据拷贝。

如进行 IP 数据分片时:

int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb,int (*output)(struct net *, struct sock *, struct sk_buff *))
{...skb_reset_transport_header(frag); /* 设置 传输层 数据偏移位置 */__skb_push(frag, hlen); /* 往后移动数据指针,在头部为 网络层协议头(L3) 划分一部分空间 */skb_reset_network_header(frag); /* 设置 网络层 数据偏移位置 */memcpy(skb_network_header(frag), iph, hlen); /* 在 头部 插入 网络层 数据 */...
}
/* include/linux/skbuff.h *//* 设置 传输层(L4) TCP/UDP 头部数据偏移位置 */
static inline void skb_reset_transport_header(struct sk_buff *skb)
{skb->transport_header = skb->data - skb->head;
}/** 从头部增加 @len 长度数据后调用: * . skb->data 后退 @len 个位置 (skb->data -= len)* . skb->len 增大 @len*/
void *skb_push(struct sk_buff *skb, unsigned int len);
static inline void *__skb_push(struct sk_buff *skb, unsigned int len)
{skb->data -= len;skb->len  += len;return skb->data;
}/* 设置 网络层(L3) IP 头部数据偏移位置 */
static inline void skb_reset_network_header(struct sk_buff *skb)
{skb->network_header = skb->data - skb->head;
}/* 返回 网络层 (L3) IP 头部位置 (struct ip_header *) */
static inline unsigned char *skb_network_header(const struct sk_buff *skb)
{return skb->head + skb->network_header;
}

从这里的示例代码可以看到,在头部插入数据,分为两步:

1. 通过 __skb_push() 移动数据指针
2. 然后再将数据拷贝到指定位置

可见,*skb_push() 系列 API 只会移动数据指针,并不会做数据拷贝操作。

2.2.2 在尾部插入数据

尾部插入数据,首先执行数据拷贝,然后通过 *skb_put() 系列 API 按拷贝的数据长度移动 skb 数据位置指针。

如网卡接收数据时:

static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
{.../* 分配 skb 缓冲(细节见前面分析) */     skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);/* 拷贝接收的数据(RING BUFFE 中的数据)到 skb 缓冲 */skb_copy_to_linear_data(skb,rx_q->rx_skbuff[entry]->data,frame_len);skb_put(skb, frame_len); /* 移动数据指针 */...
}
/* include/linux/skbuff.h */static inline void skb_copy_to_linear_data(struct sk_buff *skb,const void *from,const unsigned int len)
{memcpy(skb->data, from, len);
}#ifdef NET_SKBUFF_DATA_USES_OFFSET
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{return skb->head + skb->tail;
}static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{skb->tail = skb->data - skb->head;
}static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{skb_reset_tail_pointer(skb);skb->tail += offset;
}#else /* NET_SKBUFF_DATA_USES_OFFSET */
static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb)
{return skb->tail;
}static inline void skb_reset_tail_pointer(struct sk_buff *skb)
{skb->tail = skb->data;
}static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
{skb->tail = skb->data + offset;
}#endif /* NET_SKBUFF_DATA_USES_OFFSET */
/* net/core/skbuff.c *//** 增加数据长度,在【尾部】增加数据时使用: * . 前进数据【尾部偏移】 skb->tail += len* . 增大数据长度 skb->len += len* 返回: 数据旧的尾部位置数据指针。*/
void *skb_put(struct sk_buff *skb, unsigned int len)
{void *tmp = skb_tail_pointer(skb);SKB_LINEAR_ASSERT(skb);skb->tail += len;skb->len  += len;if (unlikely(skb->tail > skb->end)) /* 超出了数据尾部空间 */skb_over_panic(skb, len, __builtin_return_address(0));return tmp;
}
EXPORT_SYMBOL(skb_put);

2.2 数据的移除

处于效率的考虑,skb 数据的移除,并不是真的移除,而是仅仅移动数据指针位置。通过 *skb_pull() 系列 API 执行数据的移除:

/* net/core/skbuff.c */void *skb_pull(struct sk_buff *skb, unsigned int len)
{return skb_pull_inline(skb, len);
}
EXPORT_SYMBOL(skb_pull);
/* include/linux/skbuff.h *//** 从头部拉取 @len 长度数据后调用: * . skb->data 前进 @len 个位置 (skb->data += len)* . skb->len 减小 @len*/
static inline void *skb_pull_inline(struct sk_buff *skb, unsigned int len)
{return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
}/** 从头部拉取 @len 长度数据后调用: * . skb->data 前进 @len 个位置 (skb->data += len)* . skb->len 减小 @len*/
void *skb_pull(struct sk_buff *skb, unsigned int len);
static inline void *__skb_pull(struct sk_buff *skb, unsigned int len)
{skb->len -= len;BUG_ON(skb->len < skb->data_len);return skb->data += len;
}

3. 小结

本文简答的对 skb 数据管理的最基本情形 - 线性数据的插入删除 - 做了描述,事实上,skb 的数据的管理,远比这个要更复杂,譬如 IP 分片的非线性数据管理skb_shared_info 的管理等等,以后有机会再和大家一起探讨。

http://www.dtcms.com/wzjs/461438.html

相关文章:

  • form e哪个网站做推广资源seo
  • 网站备案协议书seo网站关键词优化怎么做
  • 万能本地视频播放器金昌网站seo
  • 鹿邑网站建设房地产销售工作内容
  • 微信公众号人工客服咨询班级优化大师免费下载
  • 街道口做网站公司如何提升网站seo排名
  • 中国工程建设标准化网站网站编辑怎么做
  • 潍坊360做网站怎么样网站模板建站
  • 安全培训网站网店培训班
  • 做交友网站 犯法吗2023年新闻摘抄十条
  • 浙江住房和建设厅网站商业网站设计
  • 网站一站 手机微信600 900迅雷磁力链bt磁力种子
  • iis做的网站提示500成都网络营销品牌代理机构
  • 从零开始学网站建设企业培训公司
  • 做房地产网站建设广州网站优化公司排名
  • 北京公司摇号志鸿优化设计
  • 沐风wordpress整站seo服务
  • 安阳哪里有做网站的百度竞价sem
  • 丹东网站制作百度推广公司
  • 改图网站百度下载2022新版安装
  • 明珠信息港网站建设专家百度seo排名优化如何
  • 北京做网站一般多少钱搜索关键词排名查询
  • 杭州网站建设技术百度提交入口
  • wordpress 上传网站吗头条收录提交入口
  • 做哪个网站有效果今天最新的新闻
  • 企业网站建设方案投标书百度快照客服
  • 我图网类网站建设美容美发培训职业学校
  • 网站备案号格式说明书软文推广服务
  • 网站建设及维护服务器北京百度科技有限公司电话
  • 设计论坛吉林seo推广