目录

  • 1. 申明
  • 2. 目的
  • 3. 背景知识
  • 3.1 Ethernet协议的作用和历史
  • 3.2 Ethernet承载IP的例子
  • 4. 代码demo
  • 5. 专栏知识链接
  • 6. 写在最后


1. 申明

本文章属于原创,其中参考的代码及文章在结尾处标明,侵删。

2. 目的

本文是为了解析Ethernet协议及其上层承载的协议所写demo。

3. 背景知识

3.1 Ethernet协议的作用和历史

  1. 以太网是使用最广泛的局域网技术。由于其简单、成本低、可扩展性强、与IP网能够很好地结合等特点,以太网技术的应用正从企业内部网络向公用电信网领域迈进。以太网接入是指将以太网技术与综合布线相结合,作为公用电信网的接入网,直接向用户提供基于IP的多种业务的传送通道。以太网技术的实质是一种二层的媒质访问控制技术,可以在五类线上传送,也可以与其它接入媒质相结合,形成多种宽带接入技术。以太网与电话铜缆上的VDSL相结合,形成EoVDSL技术;与无源光网络相结合,产生EPON技术;在无线环境中,发展为WLAN技术。
  2. 以太网技术作为数据链路层的一种简单、高效的技术,以其为核心,与其它物理层技术相结合,形成以太网技术接入体系。EoVDSL方式结合了以太网技术和VDSL技术的特点,与ADSL和(五类线上的)以太网技术相比,具有一定的潜在优势。WLAN技术的应用不断推广,EPON技术的研究开发正取得积极进展。随着上述“可运营、可管理”相关关键技术问题的逐步解决,以太网技术接入体系将在宽带接入领域得到更加广泛的应用。
  3. 同时,以太网技术的应用正在向城域网领域扩展。IEEE802.17RPR技术在保持以太网原有优点的基础上,引入或增强了自愈保护、优先级和公平算法、OAM等功能,是以太网技术的重要创新。对以太网传送的支持,成为新一代SDH设备(MSTP)的主要特征。10G以太网技术的迅速发展,推动了以太网技术在城域网范围内的广泛应用,WAN接口(10Gbase-W)的引入为其向骨干网领域扩展提供了可能。
  4. 总之,以太网技术由于其简单、低成本、易扩展的优势,在用户桌面系统和企业内部网络已非常普及,随着技术的发展创新,其应用领域正逐步向接入网、城域网、甚至广域网/骨干网方面拓展,形成基于IP/Ethernet的端到端无缝连接。

3.2 Ethernet承载IP的例子

android手机使用ethernet ethernet接入_协议栈


字段含义:

  1. Destination/目的字段:标识目标通信方的MAC地址 (6bytes)
  2. Source/源字段:标识发送端的MAC地址 (6bytes)
  3. Type/类型值:标志上层协议 (2bytes)

MAC地址:

  1. 所有设备的MAC地址是全球唯一的.
  2. MAC地址大小为6字节
  3. MAC地址的前半部分被称为"OUI代码"厂商唯一标识符, 后半部分厂商自动分配

4. 代码demo

#include <stdint.h>

/* mac 地址长度 */
#define MAC_ADDR_BTYES_LEN      6
/* ethernet头总长度 */
#define MAC_TOTAL_BTYES_LEN     14
/* 上层承载协议类型 */
#define PROTOCOL_UNKNOW         0
#define PROTOCOL_IPV4           1
#define PROTOCOL_IPV6           2
#define PROTOCOL_MPLS           3
#define PROTOCOL_VLAN           4
#define PROTOCOL_PPPOE          5
#define PROTOCOL_8021AD         6

typedef struct
{
	uint8_t dest_addr[MAC_ADDR_BTYES_LEN];
	uint8_t src_addr[MAC_ADDR_BTYES_LEN];
	uint16_t next_protocol_type;
} st_ethernet_hdr;

static inline int get_eth_next_protocol(st_ethernet_hdr *dr)
{
	switch (ntohs(dr->next_protocol_type)) {
		case 0x0800:
			return PROTOCOL_IPV4;
		case 0x86dd:
			return PROTOCOL_IPV6;
		case 0x8847:
		case 0x8848:
			return PROTOCOL_MPLS;
		case 0x8100:
		case 0x9100:
			return PROTOCOL_VLAN;
		case 0x8864:
			return PROTOCOL_PPPOE;
		case 0x88a8:
			return PROTOCOL_8021AD;

		default:
			return PROTOCOL_UNKNOW;
	}

	return PROTOCOL_UNKNOW;
}

/*
  解码ethernet协议
  @param1 pdata:    原始数据pdata的指针
  @param2 len:      原始数据的长度

  @return int:
                PROTOCOL_UNKNOW : faild
                other value     : succeed
*/
int decode_ethernet(uint8_t *pdata, uint8_t len)
{
	if (UNLIKELY(len < MAC_TOTAL_BTYES_LEN)) {
		return PROTOCOL_UNKNOW;
	}

	st_ethernet_hdr *pethernet = (st_ethernet_hdr *)(pdata);

	return get_eth_next_protocol(pethernet);
}

划重点: 为了解码Ethernet层,需要传入起始正确的数据和长度,在解码返回值不为PROTOCOL_UNKNOW时,说明解析成功,此时应该在调用函数之后,将指向数据的指针和长度分别偏移MAC_TOTAL_BTYES_LEN,即14bytes,来跳过Ethernet层。