【P4语言学习】Parser解析器

摘要:
解析器,它在格式头下描述解析工具。在P4程序中,始终有一个起始解析器和一个结束节点。启动解析器,我们称之为start:parserstart{returnnext_parser;//next_parser解析器}终止节点,采用特定的协议格式,通常为:returningress;结束解析器处理阶段,进入MatchAction的Ingress阶段。

参考文章:王垠:谈谈Parser

簡單介紹 P4 語言(一)- Parser

什么是Parser

传统的parser,一般出现在编译器和编译原理课程中,援引《谈谈Parser》的定义:

首先来科普一下。所谓 parser,一般是指把某种格式的文本(字符串)转换成某种数据结构的过程。最常见的 parser,是把程序文本转换成编译器内部的一种叫做“抽象语法树”(AST)的数据结构。也有简单一些的 parser,用于处理 CSV,JSON,XML 之类的格式。

也就是说,parser 是编译器用来 将人们编写的程序代码,转换成编译器读的懂的代码 的工具,parsing 是这个过程。
机器本身能够读懂的代码,往往具有复杂的逻辑数据结构,不能直接读懂程序员写的代码,这个时候就需要parser了。

那么在P4语言中的parser,我认为和编译过程中的parser相类似:数据包到达Switch的时候,并不能马上进行Match-Action匹配,需要 parser解析器 进行处理加工成MA单元能够匹配的程序。那么这个过程,可以通过P4程序代码的Parser模块进行定义。

P4中的Parser

P4中的Parser解析器模块,包括两个方面:
(1)Header,说明底层解析器解析数据报的时候,有哪些格式(字段长度,值限制等等)的Header可以使用,这些格式下Header的处理细节是什么。
(2)Parser,说明处理该格式Header下的解析工具。

Header

Header定义代码:

header_type ethernet_t {        //header类型:以太网类型
    fields {                    //域
        dst_addr : 48;          //目的地址字段长度:48bit
        src_addr : 48;          //源地址字段长度:48bit
        ether_type : 16;        //以太网类型字段长度:16bit
    }
}

Header实例化代码:

header ethernet_t ethernet;

Header可以类比为C语言中的Structure,在以太网格式域内,将一些特定属性(字段字节长度)说明清楚。
我们可以写一个独立的说明Header的p4程序,并将它include到比较重要的p4程序中。
也就是说,定义的时候说明一些固有属性;那么我们要使用它的时候,就需要把它实例化出来了。

类比,C语言中的Structure定义如下:

struct Node{
    int data;
    Node* next;
}

实例化如下:

struct Node n;

类比之后,就发现其实不难理解。Header实例化的过程,也可以叫做 header instance。

Parser

parser也一样,可以在一个p4程序里面(比如命名为parser.p4)定义,方便编程重构。

按照我的理解,parser工具和工具之间有相互调用的关系,可以通过类似if-else的逻辑判断选用何种parser。

在P4程序中,永远有一个起始的parser,和一个结束的节点。
起始parser,我们叫做start:

parser start {
    return next_parser;    //next_parser 特定协议格式的parser
}

终止节点,一般是:

return ingress;

结束解析器处理阶段,来到Match-Action的Ingress阶段。

援引《简单介绍 P4语言》的这段话:

在每一個 parser 中都會依據目前所分析的內容來決定下一個 parser,直到回傳的內容為 “ingress”(或其他 control function) 為止.

这个目前所分析的内容,我认为是协议类型,当前所要处理的数据报的协议类型(比如IPv4,比如Ethernet等等)决定了要使用的下一个parser工具。
当最后return ingress进入Ingress阶段,或者其他功能模块的时候,结束parsing解析过程。

代码分析(以 处理IPv4数据报 为例):

parser start {                //parsing,开始调用parser工具。
    return parse_ethernet;    //当前处理的是以太网协议字段,调用处理以太网的parser。
}

parser parse_ethernet {       //处理以太网协议的parser
    extract(ethernet);        //extract,parser工具解析 格式为以太网的Header实例ethernet。
    return select(latest.ether_type) {        //select,类似if-else的逻辑判断,判断条件是以太网字段的长度,根据判断条件决定调用何种工具。
        0x0800 : parse_ipv4;                  //latest.ether_type : 0x0800 ---> 调用处理Ipv4的parser。
        default : ingress;                    //latest.ether_type 属性不为 0x0800 ---> 调用ingress,结束解析。
    }
}

parser parse_ipv4 {            //处理Ipv4协议的parser。
    extract(ipv4);             //解析Ipv4协议。
    return ingress;            //调用ingress,结束。
}

這邊有幾個需要補充的東西:

   1) extract : 將目前的 Packet 以特定的 header 取出來,取出來的資料長度以 header 定義的為主
   2) return : 透過 return 的方式決定要前往哪個 parser、control function(後面會補充),可以直接 return 或是使用 select。
   3) select(select_exp) : 蠻像 C 語言中的 switch case,依據特定的 field 數值去決定要哪一個 parser 或是 control function。
   4) select_exp : 依據 spec,他可以是:
      *  field_ref : 如 ethernet.ether_type
      *  latest.field_name : 以最後 extract 的 header 為主,取用他的 field
      *  current (offset, length) : 以目前的 packet offset 位置開始某固定長度所取得的數值。

说明一下 select(select_exp),我们可以根据Header的某些特定属性,来决定调用何种parser。这个属性可以是前面提到的 1)当前parser所处理的协议,所属的Header域属性,也可以是 2)最后解析的Header的域(不一定是当前处理的),还可以是 3)current,参考上文。
类比于C语言中的if-else,就很好理解了。

parser 异常处理 exception

parser 也提供了异常处理exception,格式如下:

parser_error parser_exception_name;

parser_exception_name 有很多种,比如 p4_pe_out_of_packet 等等。

如果我们要执行一个exception,我们需要先定义好 exception handler。

parser_exception p4_pe_out_of_packet {
    /* statements */
    /* return or parser_drop */
}

处理一个exception的方法有很多,但是最后的结果只会有两个,(1)运行指定的function,(2)将该包drop掉。

Egress阶段

与Ingress之前的解析器处理阶段相对应的是 Match-Action 的动作逻辑阶段,需要把Ingress时做的修改,比如add header、modiffy header等等,重新装到packet里面去。

2016/9/28

免责声明:文章转载自《【P4语言学习】Parser解析器》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇APP的UI自动化测试框架及平台化探索显卡1060和1660测试对比下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Nginx Upstream模块源码分析(上)

Upstream模块是一个很重要的模块,很多其他模块都会使用它来完成对后端服务器的访问, 达到反向代理和负载均衡的效果。例如Fastcgi、Memcached、SessionSticky等。 如果自己实现这部分功能,采用传统的实现方式,很可能会阻塞Nginx降低其性能,因为Nginx是全异步非阻塞的。 所以要想不破坏其优美的架构,就得按照其规范实现很...

PHP 使用 header 方式实现文件下载功能

header() 函数向客户端发送原始的 HTTP 报头。 下载文件要用的的请求头: header("Content-type:application/octet-stream"); header("Accept-Ranges:bytes"); header("Accept-Length:" . $file_Size); header("Content-D...

php 访问java接口数据

$header = []; $header[] = 'Accept:application/json'; $header[] = 'Content-Type:application/json;charset=utf-8'; $data = $_GPC['mobile']; $ch = curl_init();...

perl5 第九章 关联数组/哈希表

第九章 关联数组/哈希表 by flamephoenix 一、数组变量的限制二、定义三、访问关联数组的元素四、增加元素五、创建关联数组六、从数组变量复制到关联数组七、元素的增删八、列出数组的索引和值九、用关联数组循环十、用关联数组创建数据结构  1、(单)链表  2、结构  3、树一、数组变量的限制    在前面讲的数组变量中,可以通过下标访问其中的元素。...

spring mvc Response header content type

Xml代码 <bean >      <property name="messageConverters">    <list>     <ref bean="mappingJacksonHttpMessageConverter" /><!-- json转换器 -->    </list&g...

Nginx 目录浏览基础与进阶

目录 1、简述 2、配置目录浏览 3、进阶版配置 3.1 添加第三方模块 3.2 修改配置文件 3.3 重启测试 3.4 自定义主题 1、简述 Nginx作为一款优秀的web服务器,其默认不允许列出站点的整个目录,如果需要配置,需要单独打开此功能 此功能一般用于单独开设虚拟主机供内网如下载文件等功能使用,其他情况下为了安全,一般不会开启此...