P4语言编程快速开始 实践一

参考:P4语言快速开始 感谢杨老师的分享!

前言及P4程序请参考原文,本文主要是对文章中的两个动手实例的实践记录。

1.通过behavioral-model运行simple_router样例

执行命令:

cd p4factory/targets/simple_router
make bm
sudo ./behavioral-model

在本地启动一个behavior-model,默认使用PD RPC服务的地址为127.0.0.1:9090

当在同一台宿主机上启动多个bmv2时,可以使用--pd-server=IP:PORT指定不同的端口,以防止端口占用冲突。更多参数可以使用-h参数查看CLI帮助。

执行./behavioral-model之后显示如下:

Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 2 length 107; first bytes:
33330000 00fffffffbfffffffaffffffcb ffffffaf6d3effffff8c ffffff86ffffffdd600b
new packet, len : 107, ingress : 2
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb924000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 0 length 107; first bytes:
33330000 00fffffffb1213 ffffff91ffffffdefffffffe30 ffffff86ffffffdd6008
new packet, len : 107, ingress : 0
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb928000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 6 length 107; first bytes:
33330000 00fffffffbfffffffa51 fffffff66e382d ffffff86ffffffdd600e
new packet, len : 107, ingress : 6
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb91c000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 1 length 107; first bytes:
33330000 00fffffffb1effffffee 1943ffffffc0ffffffb8 ffffff86ffffffdd6003
new packet, len : 107, ingress : 1
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb934000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 7 length 107; first bytes:
33330000 00fffffffb3e7a ffffffb10bffffff97ffffffe8 ffffff86ffffffdd600a
new packet, len : 107, ingress : 7
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb920000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 4 length 107; first bytes:
33330000 00fffffffbffffff92ffffffe4 4a34ffffff9fffffffeb ffffff86ffffffdd600b
new packet, len : 107, ingress : 4
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb914000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 5 length 107; first bytes:
33330000 00fffffffb2e33 672a7cffffffef ffffff86ffffffdd600f
new packet, len : 107, ingress : 5
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb918000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 0 length 107; first bytes:
33330000 00fffffffb4a23 66ffffffe1724a ffffff86ffffffdd600d
new packet, len : 107, ingress : 0
rmt proc returns 0
Packet in on port 6 length 107; first bytes:
33330000 00fffffffbffffffde59 680dffffffc046 ffffff86ffffffdd600e
new packet, len : 107, ingress : 6
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb928000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb91c000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 2 length 107; first bytes:
33330000 00fffffffbffffffd2ffffffd8 19ffffffce47ffffff99 ffffff86ffffffdd6009
new packet, len : 107, ingress : 2
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb924000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 3 length 107; first bytes:
33330000 00fffffffbfffffff6ffffffdb 21fffffffbffffffa97f ffffff86ffffffdd600d
new packet, len : 107, ingress : 3
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb930000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 4 length 107; first bytes:
33330000 00fffffffbffffffdaffffffec ffffffd4ffffff8fffffffed33 ffffff86ffffffdd600a
new packet, len : 107, ingress : 4
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb914000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
Packet in on port 5 length 107; first bytes:
33330000 00fffffffb1221 447dffffffd3ffffff94 ffffff86ffffffdd6006
new packet, len : 107, ingress : 5
rmt proc returns 0
ingress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
one checksum is incorrect
Applying table ipv4_lpm
Lookup key for ipv4_lpm:
    ipv4_dstAddr: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
total length for outgoing meta: 24
copying metadata
deparsing standard_metadata
deparsing routing_metadata
queuing system: packet dequeued
egress port set to 0
instance type set to 0
egress_pipeline: packet dequeued
parsing start
parsing parse_ethernet
payload length: 93
extracting metadata
extracting all metadata for 0x7fb918000940
Applying table send_frame
Lookup key for send_frame:
    standard_metadata_egress_port: 0x00000000, 
table miss, applying default action
no default action, doing nothing
total length for outgoing pkt: 107
deparsing ethernet
outgoing thread: packet dequeued
outgoing thread: sending pkt: Size[107]: Port[0]
In client_init

之后运行./run_cli.bash脚本,访问simple_router的运行时API:

root@FZUSDNLab:/home/sdn/p4factory/targets/simple_router# ./run_cli.bash 
Using default thrift server and port localhost:9090
(Cmd) ?

Documented commands (type help <topic>):
========================================
EOF                      dump_table              mc_node_destroy   
add_entry                exit                    mc_node_update    
add_entry_with_member    get_first_entry_handle  modify_entry      
add_entry_with_selector  get_next_entry_handles  quit              
add_member               help                    set_default_action
add_member_to_group      mc_associate_node       show_actions      
create_group             mc_dissociate_node      show_entry        
delete_entry             mc_mgrp_create          show_tables       
delete_group             mc_mgrp_destroy       
delete_member            mc_node_create        

(Cmd) 

2.通过run_demo.bash脚本 运行启动simple_router示例

注:如果之前进行了第一步,请重启再重新开启虚拟端口,方法是进入p4factory/tools目录下,执行:

./veth_setup.sh

进入simple_router目录,执行run_demo.bash脚本使用mininet构建网络拓扑:

./run_demo.bash

执行后效果如下:

root@FZUSDNLab:/home/sdn/p4factory/targets/simple_router# ./run_demo.bash 
*** Creating network
*** Adding hosts:
h1 h2 
*** Adding switches:
s1 
*** Adding links:
(h1, s1) (h2, s1) 
*** Configuring hosts
h1 h2 
*** Starting controller

*** Starting 1 switches
s1 Starting P4 switch s1
/home/sdn/p4factory/targets/simple_router/behavioral-model --name s1 --dpid 0000000000000001 -i s1-eth1 -i s1-eth2 --listener 127.0.0.1:11111 --pd-server 127.0.0.1:22222 
switch has been started

**********
h1
default interface: eth0 10.0.0.10   00:04:00:00:00:00
**********
**********
h2
default interface: eth0 10.0.1.10   00:04:00:00:00:01
**********
Ready !
*** Starting CLI:
mininet> 

注意,此时PD服务端口不再是9090,直接运行run_cli.bash脚本无法访问simple_router的运行时CLI。
有两种方法解决这个问题,一种是修改bash脚本,这里请参照原文。

另外一种是直接采用-c参数指定端口号,笔者采用的是这种方法:

./run_cli.bash -c 127.0.0.1:22222

效果如下:

root@ubuntu:/home/wasdns/p4factory/targets/simple_router# ./run_cli.bash -c 127.0.0.1:22222
(Cmd)

查看此时P4交换机中的流表:

(Cmd) show_tables
forward
ipv4_lpm
send_frame
(Cmd) dump_table forward
No entry handle found
(Cmd) dump_table ipv4_lpm
No entry handle found
(Cmd) dump_table send_frame
No entry handle found
(Cmd) 

此时P4交换机中有三张流表,但是都没有内容。

证明了在只有数据平面的情况下,不同host之间是没有办法正常通信的。此时也有两种方法充当控制平面。

(1)通过运行run_add_demo_entries.bash脚本下发流表。其内容如下:

python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry send_frame 1 rewrite_mac 00:aa:bb:00:00:00" -c localhost:22222
python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry send_frame 2 rewrite_mac 00:aa:bb:00:00:01" -c localhost:22222
python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry forward 10.0.0.10 set_dmac 00:04:00:00:00:00" -c localhost:22222
python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry forward 10.0.1.10 set_dmac 00:04:00:00:00:01" -c localhost:22222
python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry ipv4_lpm 10.0.0.10 32 set_nhop 10.0.0.10 1" -c localhost:22222
python ../../cli/pd_cli.py -p simple_router -i p4_pd_rpc.simple_router -s $PWD/tests/pd_thrift:$PWD/../../testutils -m "add_entry ipv4_lpm 10.0.1.10 32 set_nhop 10.0.1.10 2" -c localhost:22222

执行./run_add_demo_entries.bash为P4交换机增添表项。

执行之后如下:

Inserted entry with handle 0
Inserted entry with handle 1
Inserted entry with handle 0
Inserted entry with handle 1
Inserted entry with handle 0
Inserted entry with handle 1

在CLI中查看流表:

1.forward:

(Cmd) dump_table forward
Entry handle 0
    key:
        routing_metadata_nhop_ipv4: 0x0a00000a (10 0 0 10), 
    action:
        set_dmac
    action data:
        dmac: 0x000400000000,   
Entry handle 1
    key:
        routing_metadata_nhop_ipv4: 0x0a00010a (10 0 1 10), 
    action:
        set_dmac
    action data:
        dmac: 0x000400000001,   
(Cmd)

2.ipv4_lpm

(Cmd) dump_table ipv4_lpm
Entry handle 0
    key:
        ipv4_dstAddr: 0x0a00000a (10 0 0 10),   
    prefix_length:
        32
    action:
        set_nhop
    action data:
        nhop_ipv4: 0x0a00000a (10 0 0 10),  port: 0x00000001 (0 0 0 1), 
Entry handle 1
    key:
        ipv4_dstAddr: 0x0a00010a (10 0 1 10),   
    prefix_length:
        32
    action:
        set_nhop
    action data:
        nhop_ipv4: 0x0a00010a (10 0 1 10),  port: 0x00000002 (0 0 0 2), 
(Cmd)

3.send_frame

(Cmd) dump_table send_frame
Entry handle 0
    key:
        standard_metadata_egress_port: 0x00000001 (0 0 0 1),    
    action:
        rewrite_mac
    action data:
        smac: 0x00aabb000000,   
Entry handle 1
    key:
        standard_metadata_egress_port: 0x00000002 (0 0 0 2),    
    action:
        rewrite_mac
    action data:
        smac: 0x00aabb000001,   
(Cmd)

在mininet中能够ping通:

885822-20170115233337853-489099479.png

(2)编写command.txt,并通过behavioral-model/tools/runtimeCLI下发流表。

在运行之前,请先安装bmv2(behavioral-model),可以参考我的另外一篇博客:P4 前端编译器p4c-bm、后端编译器bmv2命令安装 make error问题

command.txt内容如下:

table_set_default send_frame _drop
table_set_default forward _drop
table_set_default ipv4_lpm _drop
table_add send_frame rewrite_mac 1 => 00:aa:bb:00:00:00
table_add send_frame rewrite_mac 2 => 00:aa:bb:00:00:01
table_add forward set_dmac 10.0.0.10 => 00:04:00:00:00:00
table_add forward set_dmac 10.0.1.10 => 00:04:00:00:00:01
table_add ipv4_lpm set_nhop 10.0.0.10/32 => 10.0.0.10 1
table_add ipv4_lpm set_nhop 10.0.1.10/32 => 10.0.1.10 2

原文中命令有误,是无法执行的,这里先暂时使用第一种方法,后续会补充上。

从这些流表下发方法中也可以认识到以下几点:
a)没有控制面下发的流表,仅数据面无法工作。
b)控制面下发的流表必须与P4程序中定义的table相吻合,从匹配字段(match-field)到动作(action).
c)P4定义的数据面所对应的控制面,可以是控制器、运行时CLI,也可以是SAI等。

2017/1/15

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值