虚拟网络环境试验

一 前言

本来这几天研究eBPF的xdp的,虽然阅读了不少资料,但是测试代码仍然有问题,所以耽误了,在测试过程中发现了虚拟网络环境,又是自己没有接触过的,所以研究下,挺有意思的,写了篇文章分享下。

简单来说,就是构建一套虚拟的网络环境。

二  交叉线和veth

如果玩计算机比较早的朋友,如果没有路由器,集线器这些通讯设备,我们两个计算机想连接打个CS啥的,也是有一种办法的,就是采用双绞线直连,我记得买这种线子的时候,一定要选择交叉线(只是线的顺序不一样做网线的时候做下),才可以计算机对计算机,即同类设备连接,如果是计算机连集线器啥的,用的是直连线,现在用直连线计算机据说也可以适配了,目前没用过。

63635ca8b0ea7a4369628c2fe7ed8b6c.png我们在一个计算机中,也可以虚拟出来类似交叉线的东东,veth即表示两个类似通过交叉线互联的虚拟网卡。

2.1 veth使用

简单实用ip命令创建veth,这个如同上面的交叉线,是两个虚拟网卡做成一对,可以配置同一个网段的ip,也可以互联通信。一般用于不同的网络空间,通过veth连着两个协议栈,更好的理解可以认为是bash中的管道,从一端输入另一端输出。

ip link add veth0 type veth peer name veth1

把参数用中括号括起来方便查看如下:

ip link add [veth0] type veth peer name [veth1]

veth0和veth1是虚拟两个网卡名字,结果通过命令查看:

ip link
...
6: veth1@veth0: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff
7: veth0@veth1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 0a:21:f4:08:f9:92 brd ff:ff:ff:ff:ff:ff

可以看到没设置ip,也没有启动,设置ip,启动下看看效果,如下命令:

#sudo ip addr add 192.168.4.3/24 dev veth0
#sudo ip addr add 192.168.4.2/24 dev veth1

#sudo ip link set veth0 up
#sudo ip link set veth1 up

# ip addr show
6: veth1@veth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff
    inet 192.168.4.2/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::407b:d8ff:fee5:4782/64 scope link 
       valid_lft forever preferred_lft forever
7: veth0@veth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:21:f4:08:f9:92 brd ff:ff:ff:ff:ff:ff
    inet 192.168.4.3/24 scope global veth0
       valid_lft forever preferred_lft forever
    inet6 fe80::821:f4ff:fe08:f992/64 scope link 
       valid_lft forever preferred_lft forever

可以看到ip已经启动,ip也设置好了。现在的网络情况是这样的,如下图:b175f757f9c574f8e1eaa2d5ef2f52a5.png

命令验证如下:

root@ubuntu-lab:~# ping 192.168.4.2 -I lo
ping: Warning: source address might be selected on device other than: lo
PING 192.168.4.2 (192.168.4.2) from 192.168.31.198 lo: 56(84) bytes of data.
64 bytes from 192.168.4.2: icmp_seq=1 ttl=64 time=0.051 ms
^C
--- 192.168.4.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.051/0.051/0.051/0.000 ms
root@ubuntu-lab:~# ping 192.168.4.3 -I lo
ping: Warning: source address might be selected on device other than: lo
PING 192.168.4.3 (192.168.4.3) from 192.168.31.198 lo: 56(84) bytes of data.
64 bytes from 192.168.4.3: icmp_seq=1 ttl=64 time=0.076 ms
64 bytes from 192.168.4.3: icmp_seq=2 ttl=64 time=0.155 ms
^C
--- 192.168.4.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1017ms
rtt min/avg/max/mdev = 0.076/0.115/0.155/0.039 ms
root@ubuntu-lab:~# ping 192.168.4.3 -I eth1
ping: SO_BINDTODEVICE eth1: No such device
root@ubuntu-lab:~# ping 192.168.4.3 -I veth1
PING 192.168.4.3 (192.168.4.3) from 192.168.4.2 veth1: 56(84) bytes of data.

^C
--- 192.168.4.3 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2033ms

root@ubuntu-lab:~# ping 192.168.4.2 -I veth0
PING 192.168.4.2 (192.168.4.2) from 192.168.4.3 veth0: 56(84) bytes of data.
^C

在用 ping 192.168.4.3 -I lo 命令我们对veth0 抓包也没有抓到ping包,说明是走的lo回环。

root@ubuntu-lab:/home/miao/xdp-test# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
root@ubuntu-lab:/home/miao/xdp-test# echo 0 > /proc/sys/net/ipv4/conf/veth0/rp_filter
root@ubuntu-lab:/home/miao/xdp-test#  echo 0 > proc/sys/net/ipv4/conf/veth1/rp_filter
root@ubuntu-lab:/home/miao/xdp-test# echo 1 > /proc/sys/net/ipv4/conf/veth1/accept_local
root@ubuntu-lab:/home/miao/xdp-test# echo 1 > /proc/sys/net/ipv4/conf/veth0/accept_local

rp_filter (Reverse Path Filtering)参数定义了网卡对接收到的数据包进行反向路由验证的规则。1(默认值)表示源IP必须是路由可达的,同时入口接口恰好是路由表查到的接口;2 表示源IP必须是路由可达的,但放松为任意接口可达即可;0 表示不检查源IP

所谓反向路由校验,就是在一个网卡收到数据包后,把源地址和目标地址对调后查找路由出口,从而得到反身后路由出口。然后根据反向路由出口进行过滤。
当rp_filter的值为1时,要求反向路由的出口必须与数据包的入口网卡是同一块,否则就会丢弃数据包。
当rp_filter的值为2时,要求反向路由必须是可达的,如果反路由不可达,则会丢弃数据包。
这是因为Linux还有一个检测源IP地址的机制,若收到的IP报文源IP与本机上某一个IP相同,那么内核默认丢弃这个报文。这其实也很好理解,正常情况下,如果收到一个IP报文的源地址属于自己,那么可能这个IP报文是伪造的。但也有一些特殊的场景可能用到,例如LVS机器的DR模式或者隧道模式,恰好LVS机器又处在响应的路径里,此时响应源IP是一个VIP,恰好与LVS机器上环回接口配置的一致。
accept_local可以改变默认的行为,把它设为1则接受源IP是本机中的IP的报文通过。

其实ping下不返回,则抓下包:

root@ubuntu-lab:/home/miao/xdp-test# ping 192.168.4.2 -I veth0
PING 192.168.4.2 (192.168.4.2) from 192.168.4.3 veth0: 56(84) bytes of data.

root@ubuntu-lab:/home/miao/ebpfkit-master# tcpdump -i veth1 -vv -n
tcpdump: listening on veth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
06:41:20.542005 IP (tos 0x0, ttl 64, id 11454, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.4.3 > 192.168.4.2: ICMP echo request, id 31, seq 941, length 64
06:41:21.565565 IP (tos 0x0, ttl 64, id 11710, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.4.3 > 192.168.4.2: ICMP echo request, id 31, seq 942, length 64


# 返回的报文是从lo过来的,所以ping没有返回
root@ubuntu-lab:/home/miao/ebpfkit-master# tcpdump -i lo -vv -n
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
11:35:42.893121 IP (tos 0x0, ttl 64, id 3593, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.4.2 > 192.168.4.3: ICMP echo reply, id 50, seq 325, length 64
11:35:43.917182 IP (tos 0x0, ttl 64, id 3726, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.4.2 > 192.168.4.3: ICMP echo reply, id 50, seq 326, length 64
11:35:44.942339 IP (tos 0x0, ttl 64, id 3738, offset 0, flags [none], proto ICMP (1), length 84)
    192.168.4.2 > 192.168.4.3: ICMP echo reply, id 50, seq 327, length 64

其实看到上面的抓包,veth1 网卡收到包了但是返回从lo返回,返回的时候没办法指定网卡。

2.2 加路由让ping返回走特定网卡

添加路由信息:

root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add pref 1000 tab local
root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add fwmark 100 pref 100 tab 100
# 目的是为了路由信息提到local之前
root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule add pref 1000 tab local
root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule del pref 0 tab local

root@ubuntu-lab:/home/miao/ebpfkit-master# ip route add 192.168.4.2/32 dev veth0 src 192.168.4.3 tab 100
root@ubuntu-lab:/home/miao/ebpfkit-master# ip route add 192.168.4.3/32 dev veth1 src 192.168.4.2 tab 100

# 给出去报文加标识
root@ubuntu-lab:/home/miao/xdp-test# iptables -t mangle -A OUTPUT -d 192.168.4.2/32 -j MARK --set-mark 100

然后还是不行,检查了很多配置,检查一天还是没ping通,查看路由:

root@ubuntu-lab:~# ip route get 192.168.4.2
local 192.168.4.2 dev lo table local src 192.168.4.2 uid 0 
    cache <local> 
root@ubuntu-lab:~# ip route get 192.168.4.3
local 192.168.4.3 dev lo table local src 192.168.4.3 uid 0 
    cache <local>

通过配置来看,走的仍然是lo,用的是缓存,但是没有办法清理lo路由,因为:

root@ubuntu-lab:~# ip route ls tab 100
192.168.4.2 dev veth0 scope link src 192.168.4.3 
192.168.4.3 dev veth1 scope link src 192.168.4.2 
root@ubuntu-lab:~# ip route ls tab 1000
Error: ipv4: FIB table does not exist.
Dump terminated

目前没有找到办法清理。但是veth更多的是用来转发,比如我们发到veth0的数据可以自动转发到veth1,反之亦然。

三 交换机“bridge”

上面聊的veth,每队通信都要通过路由配置来做,非常麻烦,这个在实际使用如果虚拟网络环境太多,路由都搞的很复杂不值得。

现实中,上大学宿舍多人组网,要么是集线器,要么是交换机,同样在网络环境中,我们也可以通过一个软件实现brige,然后多个虚拟网卡连在一起,借助纯软件实现通信。docker 有种网络模式就是这样通信的,如下图:98937575159e78965026173177e0b601.png

清理下环境,重新试验:

#删除veth,删除veth0,veth1自动也删除了。
root@ubuntu-lab:/home/miao/ebpfkit-master# ip link  del veth0
#清理路由配置
#ip route del  192.168.4.2/32 dev veth0 src 192.168.4.3 tab 100
#ip route del  192.168.4.3/32 dev veth1 src 192.168.4.2 tab 100
root@ubuntu-lab:/home/miao/ebpfkit-master# ip rule del fwmark 100

3.1 新建虚拟网络环境

Network namespace是linux内核提供的进行网络隔离的功能,每个网络空间都有自己的网络协议栈,路由表,lo等。Docker的网络环境就是通过Network namespace进行网络隔离的。准备搭建的环境如下:9f2fb04cc166b1cfb49ecd7c5320d8e6.png

我们新建了两个不同的网络空间,设置不同的网络段,目标是通过bridge来相互ping通,达到网络互联的目的,再多容器都可以通过连接到bridge来达到相互通信的目的。

建立虚拟网络空间

root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns add ns1
root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns add ns2
root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns
ns2
ns1

创建veth对

root@ubuntu-lab:/home/miao/ebpfkit-master# ip link add veth1 type veth peer name veth1_p
root@ubuntu-lab:/home/miao/ebpfkit-master# ip link set veth1 netns ns1
root@ubuntu-lab:/home/miao/ebpfkit-master# ip link add veth2 type veth peer name veth2_p
root@ubuntu-lab:/home/miao/ebpfkit-master# ip link set veth2 netns ns2

配置ip和启动

ip netns exec ns1 ip addr add 192.168.5.101/24 dev veth1
ip netns exec ns1 ip link set veth1 up

ip netns exec ns2 ip addr add 192.168.5.102/24 dev veth2
ip netns exec ns2 ip link set veth2 up

查看配置结果:

root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns1 ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
9: veth1@if8: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0
root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns2 ip link list
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
11: veth2@if10: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state LOWERLAYERDOWN mode DEFAULT group default qlen 1000
    link/ether ca:18:9d:4c:8b:bc brd ff:ff:ff:ff:ff:ff link-netnsid 0


root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns1 ifconfig
veth1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.5.101  netmask 255.255.255.0  broadcast 0.0.0.0
        ether 42:7b:d8:e5:47:82  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@ubuntu-lab:/home/miao/ebpfkit-master# ip netns exec ns2 ifconfig
veth2: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.5.102  netmask 255.255.255.0  broadcast 0.0.0.0
        ether ca:18:9d:4c:8b:bc  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

3.2 创建虚拟bridge,虚拟网卡连接bridge

命令如下:

#创建bridge
#brctl addbr br0
#将veth一端连接到bridge
ip link set dev veth1_p master br0
ip link set dev veth2_p master br0
#设置bridge的ip
ip addr add  192.168.5.1/24 dev br0

bridge和veth的启动:

ip link set veth1_p up
ip link set veth2_p up
ip link set br0 up

查看网络信息:

root@ubuntu-lab:/home/miao/ebpfkit-master# brctl show
bridge name bridge id  STP enabled interfaces
br0  8000.d246bc47bc05 no  veth1_p

配置好后的ip示意图:d2c6613a18161eb3e6fa679e87d4c724.png

搞定之后,利用ping测试下:

root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 192.168.5.102
PING 192.168.5.102 (192.168.5.102) 56(84) bytes of data.
64 bytes from 192.168.5.102: icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from 192.168.5.102: icmp_seq=2 ttl=64 time=0.085 ms
64 bytes from 192.168.5.102: icmp_seq=3 ttl=64 time=0.085 ms

root@ubuntu-lab:/home/miao# ip netns exec ns2 ping 192.168.5.101
PING 192.168.5.101 (192.168.5.101) 56(84) bytes of data.
64 bytes from 192.168.5.101: icmp_seq=1 ttl=64 time=0.106 ms
64 bytes from 192.168.5.101: icmp_seq=2 ttl=64 time=0.093 ms
64 bytes from 192.168.5.101: icmp_seq=3 ttl=64 time=0.058 ms

刚开始也是不通的,后来发现原因,bridge 开启了iptables功能,导致所有经过br0的网络包都受到iptables的限制,docker为了安全性,将iptables的filter 表的FORWARD链默认设置成drop了,所以导致了ping的包被drop导致的。

关键是这条路由啊:

root@ubuntu-lab:/home/miao# iptables -A FORWARD -i br0 -j ACCEPT

3.3 换换网段测试看看

虽然测试的时候用的ip是属于同一个网段,但是 br0的ip设置在ping的时候是没有用的,更改下试试

root@ubuntu-lab:/home/miao# ip addr del  192.168.5.1/24 dev br0
root@ubuntu-lab:/home/miao# ip addr add  192.168.6.1/24 dev br0

ping测试的效果不受到影响:

root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 192.168.5.102
PING 192.168.5.102 (192.168.5.102) 56(84) bytes of data.
64 bytes from 192.168.5.102: icmp_seq=1 ttl=64 time=0.092 ms
64 bytes from 192.168.5.102: icmp_seq=2 ttl=64 time=0.095 ms
^C
--- 192.168.5.102 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1038ms
rtt min/avg/max/mdev = 0.092/0.093/0.095/0.001 ms
root@ubuntu-lab:/home/miao# ip netns exec ns2 ping 192.168.5.101
PING 192.168.5.101 (192.168.5.101) 56(84) bytes of data.
64 bytes from 192.168.5.101: icmp_seq=1 ttl=64 time=0.090 ms
64 bytes from 192.168.5.101: icmp_seq=2 ttl=64 time=0.063 ms
^C
--- 192.168.5.101 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1012ms
rtt min/avg/max/mdev = 0.063/0.076/0.090/0.013 ms
root@ubuntu-lab:/home/miao#

虽然每个网络空间的里面的br0的ip不对了,但是仍然不受到影响:

root@ubuntu-lab:/home/miao#  ip -n ns1 route
default via 192.168.5.1 dev veth1 
192.168.5.0/24 dev veth1 scope link 
root@ubuntu-lab:/home/miao# ip -n ns2 route
default via 192.168.5.1 dev veth2 
192.168.5.0/24 dev veth2 scope link

继续换下,让两个网络的ip属于不同网段玩玩。

root@ubuntu-lab:/home/miao# ip netns exec ns2 ip addr del 192.168.5.102/24 dev veth2
root@ubuntu-lab:/home/miao# ip netns exec ns2 ip addr add 10.25.5.102/24 dev veth2

root@ubuntu-lab:/home/miao# ip netns exec ns2 ip route
10.25.5.0/24 dev veth2 proto kernel scope link src 10.25.5.102 
root@ubuntu-lab:/home/miao# ip -n ns2 route add 192.168.5.0/24 dev veth2
root@ubuntu-lab:/home/miao# ip -n ns1 route add 10.25.5.0/24 dev veth1

root@ubuntu-lab:/home/miao# ip netns exec ns1 ip route
10.25.5.0/24 dev veth1 scope link 
192.168.5.0/24 dev veth1 scope link 
root@ubuntu-lab:/home/miao# ip netns exec ns2 ip route
10.25.5.0/24 dev veth2 proto kernel scope link src 10.25.5.102 
192.168.5.0/24 dev veth2 scope link 

root@ubuntu-lab:/home/miao# ip addr
12: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether d2:46:bc:47:bc:05 brd ff:ff:ff:ff:ff:ff
    inet 192.168.6.1/24 scope global br0


root@ubuntu-lab:/home/miao# ip netns exec ns1 ping 10.25.5.102
PING 10.25.5.102 (10.25.5.102) 56(84) bytes of data.
64 bytes from 10.25.5.102: icmp_seq=1 ttl=64 time=0.089 ms
64 bytes from 10.25.5.102: icmp_seq=2 ttl=64 time=0.103 ms
64 bytes from 10.25.5.102: icmp_seq=3 ttl=64 time=0.089 ms

哇竟然真的还是通的,br0,veth0,veth1分别设置了三个网段的地址,配置好路由后仍然不影响他们之间的通讯的。虚拟网络空间的命令执行有些类似于docker,看看下面的命令 :

root@ubuntu-lab:/home/miao# ip netns exec ns1 /bin/bash
root@ubuntu-lab:/home/miao# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
9: veth1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.5.101/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::407b:d8ff:fee5:4782/64 scope link 
       valid_lft forever preferred_lft forever
root@ubuntu-lab:/home/miao# exit
exit

可以进入网络空间,也可以像上面那样,直接在网络空间执行命令。为了区分不同的网络空间提示符,可以在执行exec命令的时候修改下:

oot@ubuntu-lab:/home/miao#  ip netns exec ns1 /bin/bash --rcfile <(echo "PS1=\"namespace ns1> \"")
namespace ns1> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
9: veth1@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 42:7b:d8:e5:47:82 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 192.168.5.101/24 scope global veth1
       valid_lft forever preferred_lft forever
    inet6 fe80::407b:d8ff:fee5:4782/64 scope link 
       valid_lft forever preferred_lft forever
namespace ns1> exit
exit
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值