1.BGP边界网关协议:
1.概念:
-
BGP不产生路由,负责搬运路由
-
使用范围:在AS之间使用的协议
-
基于TCP封装,端口号:179
-
AS自治系统:取值范围 1-65535,公有AS 1-64511,私有AS 64512-65535
-
协议特点:
- BGP是一种路径矢量型路由协议
- 没有算法
- 传递网络掩码,支持VLSM(可变长子网掩码)、CIDR(无类别域间路由,超网技术)
- BGP协议中存在大量的属性(是一种基于规则的路由协议)
- BGP协议支持路由认证
- 支持BGP路由聚合(汇总)
- BGP是一种非常消耗资源的路由协议
-
BGP的协议版本:
- 有类别:V1,V2,V3
- 无类别:V4(仅仅支持IPv4单播路由传递),V4+(支持IPv4单播路由,IPv6单播,IPv4组播,IPv6组播,VPNV4,VPNV6等)
- 默认仅仅支持传递IPV4单播路由,传递其他方式路由时需要开启(激活)
-
更新地址:单播更新
-
更新方式:触发更新,增量更新
2.适合使用BGP的网络环境:
- 传输AS
- 多宿主
- 需要对进入和离开的流量进行强大的策略控制时
3.BGP邻居关系:
- IBGP:内部BGP邻居,同一个AS之内的BGP设备的邻居关系
- EBGP:外部BGP邻居,不同AS之间的BGP设备构建的邻居关系
4.BGP消息数据包:
-
open报文:建立BGP邻居关系,只发送一次
-
BGP邻居建立的条件:
- router-id必须不同
- BGP认证一致
- 指定正确的AS号
- 建立TCP三次握手的两端路由可达
-
图示:
-
-
keepalive报文:保活,维持BGP邻居关系;keepalive 时间(保活)默认为60s,Hold 时间(超时)默认为180s
-
update报文:更新
-
通告路由:
- IBGP路由通告时间为15S
- EBGP路由通告时间为30S
-
撤销路由:
-
-
notification报文:报告(错误报告)
5.BGP邻居状态机制:
- IDLE初始化:检测双方建立邻居的IP地址是否可以通信,然后建立尝试建立TCP连接(TCP报文随机一方先发送)
- Connet连接:建立TCP连接成功后,被动响应一方的状态
- Active活动:建立TCP连接成功后,主动发送一方的状态
- Opensent:主动发送open报文的一方状态;发送open报文,建立BGP的邻居(open报文随机一方先发送)
- Openconfirm:收到open报文的一方状态;报文确认
- Established邻居状态:收到对方的keepalive报文(保活)的一方状态
6.BGP的路由黑洞:
-
在同一个AS中,考虑成本,不会所有设备均运行BGP协议;
-
大量的IBGP邻居关系间,为非直连建邻;故必然出现大量单播非直连传递路由信息;最终形成BGP设备路由表可达;而实际流量在递归到非BGP设备时被丢弃
-
即:控制层面显示可达,数据层面在非BGP设备处不可达
-
解决方法:
-
在边界设备上将BGP重収布引入IGP协议(仅仅引入EBGP邻居学习幵加表的路由)
-
在AS内建立全互联的IBGP邻居关系
-
减少IBGP邻居关系的数量,打破IBGP水平分割
- 路由反射器
- EBGP 联邦
-
MPLS
-
7.BGP的防环机制:
-
IBGP(AS内):IBGP水平分割机制;next-hop,起源者属性,簇ID列表
-
IBGP水平分割:
- AS-by-AS规则:一个AS为一个整体,故BGP路由内部传递时,其属性默认没有发生任何变化,故将导致IBGP关系间的环路
- IBGP水平分割机制:IBGP只传一跳规则,通过一个IBGOP邻居学习路由不能传递给其他的IBGP邻居
- IBGP水平分割的打破:路由反射器、EBGP联邦
-
-
EBGP(AS之间 ):
- 在BGP的路由条目中存在各种属性用于选路,其中有一种AS-Path属性
- AS-Path用于记录该条目经过的所有AS编号
- EBGP水平分割就是利用AS-Path属性,接收到路由条目中,若出现本地的AS编号记录将拒绝接收该条目
8.配置:
1.BGP建立:
-
先保证路由可达
-
启用BGP协议:
bgp [num] # num为AS自治系统编号 复制代码
-
手工指定router-id
router-id [本地路由器RID] 复制代码
-
手工指定邻居:
peer [对端的直连接口IP地址] as-number [对端的bgp号] 复制代码
-
修改更新源(环回接口):默认更新源为到达peer的本地出接口地址
peer [对端的环回接口IP地址] connect-interface [本地的环回接口号] 复制代码
-
注意:IBGP邻居之间禁止双端全部缺省路由
-
修改EBGP之间多跳(EBGP之间数据包TTL默认为1 ),EBGP环回使用环回建立邻居时跳数等于2
peer [对端的环回接口IP地址] ebgp-max-hop [num] # num值应大于1,默认跳数255 # 作用:1.关闭EBGP之间直连检测 2.修改EBGP数据包的TTL值 复制代码
2.宣告网络:
-
本地通过BGP协议学习的路由将自动传递给本地的其他BGP邻居,需要考虑IBGP水平分割;
-
宣告是宣告本地路由表中任何来源的非BGP路由(直连,静态,IBGP等)
-
EBGP邻居宣告网段时,源更新地址不能和宣告环回地址相同(建邻的路由和BGP传递过来的路由是同一个),否则无法生成有效最优路由
-
BGP宣告问题:
- 在BGP协议种,本地设备可以宣告本地路由表中所有直连,静态,IGP产生的路由;
- 由于在实际工程中,一个AS内部存在大量的未运行BGP协议的路由器;它们的用户网段,需要边界IBGP协议的设备来代替它们宣告共享到其他的AS
- 所以,边界IBGP设备宣告本地路由表中路由条目时,默认将携带COST值;携带COST的路由会被传递给本地设备的EBGP邻居 / IBGP邻居
- 本AS中不是本地设备的EBGP邻居学到的路由度量值会清零,导致选路问题;所以建立所有存在EBGP邻居的边界IBGP路由器均宣告本AS中路由条目
- 作用:用于其他AS判断多个EBGP邻居,谁离目标更近
-
配置:
network [IP网段] [子网掩码] 复制代码
3.查看BGP表和详情属性:
-
查看BGP 邻居表摘要:
display bgp peer 复制代码
字段名 说明 peer 对方的更新源地址 V(version) bgp版本号 AS 自治系统号 MsgRcvd 收到了多少信息 MsgSent 发送了多少信息 OutQ 出项消息队列 Up / Down 邻居建立时间 PrefRcv 收到了多少路由更新数量 -
查看BGP 邻居表详情:
display bgp peer verbose 复制代码
字段名 说明 Configured(已配置) 本地配置的hold超时时间,keepalive保活时间 Received(接收到) 对方配置的hold超时时间,keepalive保活时间 Negotiated(协商后) 双方协商后的hold超时时间,keepalive保活时间 -
查看BGP 路由表:
display bgp routing-table 复制代码
status codes状态码 说明 * - valid 有效路由,目标网段加到路由表的条件之一 > - best 最优路由,目标网段加到路由表的条件之一 d - damped 惩罚路由 h - history 惩罚路由 i- internal IBGP邻居学习到的路由 s - suppressed 路由抑制 s - stale 陈旧路由 Origin起源码 说明 i - IGP 自身通告路由(network) e - EGP 来自EGP的路由 ? - incomplete 无知起源路由(重发布路由),通过重发布,将IGP产生的路由发布到BGP 列表属性字段 说明 MED 度量 NextHop 下一跳 LocPrf 本地优先级 PrefVal 权重属性(虚拟优先级) Origin 起源 -
查看BGP的IP路由表
display ip routing-table protocol bgp 复制代码
BGP 路由优先级 说明 EBGP:255 IBGP:255 Local BGP : 255 -
注意:
- EBGP邻居之间传递路由最小间隔为30S
- IBGP邻居之间传递路由最小间隔为15S
4.开启负载均衡:
load-balancing as-path-ignore # 先进入BGP进程,仅对EBGP路由有效
# 负载均衡的两条线路对端必须指向同一AS,且在BGP表中仅显示最佳,但路由表中出现负载均衡现象
复制代码
4.路由不优的问题:
-
原因:1.下一跳不可达 2.IBGP同步
-
下一跳属性规则:
- network 引入 默认next-hop 属性为0.0.0.0
- network通告路由传递给IBGP邻居或EBGP邻居时,下一跳默认为更新源地址(即建立TCP三次握手的对方IP地址)
- IBGP学习路由传递给EBGP邻居时,下一跳为EBGP的更新源地址(EBGP邻居路由传递给EBGP邻居时也一样)
- EBGP学习路由传递给IBGP邻居时,下一跳不发生改变
-
修改下一跳为本地: 将通过EBGP学习到的路由传给下一个路由器时显示的下一跳修改成本设备
peer [对端IP地址] next-hop-local 复制代码
-
备注:
- 在思科中,默认将IGP协议通告进入BGP时,将原IGP路由的下一跳地址作为BGP路由的下一跳属性;传递给其他IBGP邻居时,IBGP邻居发现路由的下一跳属性为自己的接口地址,启用下一跳防环机制,组织路由加表,下一跳属性具有防环功能
- 在华为中,将路由通告在BGP时,下一跳属性为0.0.0.0,并且传递给其他IBGP邻居时下一跳属性直接变为更新源地址,下一跳属性不存在放环功能,再修改优先级的时候可能导致路由环路。
-
特殊说明:
-
路由器R1、R2、R3(R1、R2为IBGP邻居,R1和R3、R2和R3为EBGP邻居)在同一个MA网段;但IBGP邻居两在同一个AS,EBGP邻居不在同一个AS;
-
正常R1从R2学习到R4传递给R3的路由,下一跳自动显示为R3(最佳路径)
-
形成条件:
- R1、R2、R3必须使用MA网段的物理接口建立邻居关系
- ICMP重定向开启(默认开启)
-
ICMP重定向:一台路由器在转发一个流量时,发现流量在本地的入口和查询完路由表的出口为同一个接口,告知上一跳设备本地的下一跳地址,帮助上一跳设备找到最佳的下一跳地址
-
在BGP中仅查看某各邻居发送或接收到的BGP路由
display bgp routing-table peer [对端更新源地址] [received-routes/advertised-routes] # received-routes:接收到的路由 # advertised-routes:发送的路由 复制代码
-
5.对等体组:
-
将多个peer 划入一个group中,针对group实施BGP邻居关系建立的配置
-
优点:
- 减少BGP配置
- 将多个peer划入一个group仅仅针对一个group一次性消耗CPU 内存等资源,所以可以节约资源
-
创建group
group [组名] [internal/external] # 默认internal(IBGP) 复制代码
-
修改更新源:(因为在同一AS中,不需要单独建立BGP邻居命令as-number )
peer [组名] connect-interface [本地的环回接口号] 复制代码
-
将peer划入对等体组:将想和本设备建立邻居的更新源加入组中,对端路由同种操作
peer [IP地址] group [组名] 复制代码
-
查看
display bgp peer 复制代码
6.路由反射器:
-
反射规则: 非非不传(非客户端收到的路由不能传递给其他的非客户端)
-
在路由反射器中,由于破坏了IBGP水平分割机制,可能导致路由环路,所以引入了起源者属性和簇ID属性进行防环
-
设置路由反射器: 设置路由反射器的客户端,同时宣告自身为路由反射器中心
peer [对端IP地址] reflect-client # 设置对端为本设备的客户端,本设备为中心;中心将学到的路由传递给客户端 复制代码
-
可选:设置路由反射器的cluster-id:(防环)
reflector cluster-id [RRID] # 设置本设备的簇ID,默认为本设备的RID 复制代码
-
查看反射之后的路由:
display bgp routing-table [路由IP网段] # 在反射器之后的设备查看 复制代码
7.EBGP联邦:
-
先部署小AS,再声明大AS
-
注意: 联邦EBGP邻居既有IBGP邻居特性又有EBGP邻居特性
-
IBGP特性:
- 下一跳问题
- 学习到的路由标记为IBGP
-
EBGP特性:邻居建立过程中存在EBGP邻居的非直连检测和TTL问题
-
联邦EBGP防环:引入联邦AS序列号进行防环(不AS-path 区别 1.不计入选路 2.当传递出大的AS时消失)
-
配置:
-
在同一个联邦内的路由器配置小AS
bgp [AS号] router-id [路由器RID] peer ...... 复制代码
-
声明大的AS号:
confederation id [AS号] 复制代码
-
在需要建立联盟EBGP之间指定peer-as(需要先声明,再建立了EBGP邻居)
confederation peer-as [对方的AS号] # 联盟内小AS与小AS建立EBGP邻居前,需要互相指定对方的AS号 复制代码
-
修改EBGP邻居之间的条数
-
查看接收到的联邦 IBGP邻居路由和联邦 EBGP邻居路由
display bgp routing-table [] 复制代码
-
8.BGP的社团属性:
-
社团属性:可选可传递属性
-
标准社团属性:定义BGP路由的传播范围
-
扩展社团属性:针对传递的路由信息进行标记
-
默认不传播,不存在
-
标准社团属性配置:
-
添加社团属性:
-
设置策略列表:
route-policy [列表名] permit node [序列号] if-match [条件] apply community [社团属性] # 已定义的社团属性:Internet可以传递给所有邻居,no-advertise不能传递给任何邻居 # no-export不能传递出大的AS,no-export-subconfed不能传递出小的AS 复制代码
-
调用:
peer [对端更新源地址] route-policy [列表名] [import/export] # 先进入BGP进程 复制代码
-
-
向对端传播标准社团属性:
peer [对端更新源地址] advertise-community # 先进入BGP进程,传递标准团体属性 复制代码
-
在其他路由器查看社团属性:
display bgp routing-table [路由网段] 复制代码
-
-
扩展社团属性配置:
-
添加社团属性:
-
使用社团属性列表抓取扩展团体属性
ip community-filter basic [列表名] permit [num]:[num] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] if-match community-filter [列表名] apply community [社团属性] 复制代码
-
调用:
peer [对端更新源地址] route-policy [列表名] [import/export] # 先进入BGP进程 复制代码
-
-
向对端传播扩展社团属性:
peer [对端更新源地址] advertise-ext-community # 先进入BGP进程,传递扩展团体属性 复制代码
-
在其他路由器查看社团属性:
display bgp routing-table [路由网段] 复制代码
-
9.BGP的自动汇总:(可选)
-
自动汇总只针对重发布的路由
-
当代的路由器设备,默认就关闭了BGP的自动汇总功能
-
自动汇总规则与正常BGP协议共享,或在BGP协议通过network宣告命令产生的路由条目无关
-
宣告由于重发布
-
在开启了自动汇总的前提下,重发布进入的路由将不携带子网掩码,按主类掩码进入;不携带本地到目标网段的度量值,度量值为0;若关闭自动汇总,进入路由将正常携带掩码,且携带度量,此时和宣告路由仅起源属性不同;故建议不要开启自动汇总
-
配置:
summary automatic # 开启自动汇总,一般不开启;先进入BGP进程 复制代码
import-route [其他协议名] [进程号] # 批量宣告网络 复制代码
10.BGP的认证:
peer [对端的更新源地址] password cipher [密码] # 先进入BGP进程,邻居间需要密钥一致
复制代码
11.BGP聚合(汇总):
-
利用BGP的宣告特征来简化了汇总配置量
-
宣告特征:本地路由表中任何方式产生的路由均可被BGP宣告
-
流程:1在AS边界的BGP路由起上配置一条到达聚合地址的空接口防环路由,2.将其宣告到BGP协议中
-
在实际工程中,由于AS之间一定存在大量的EBGP邻居关系,因此仅汇总不能做到优选路径,必须在传递聚合条目的同时,再传递部分的明细路由来选路控制
-
在进行路由聚合时,会丢弃某些属性(AS-Path等),导致网络故障(严重的会出现路由环路),还有一些属性会自动生成一些默认值
-
配置:
-
方式一:
-
不宣告各明细网段
-
配置汇总网段的空接口:
ip route-static [汇总网段地址] [子网掩码/长度] null 0 复制代码
-
宣告汇总网段:
network [汇总网段] # 如果需要个别明细路由,直接再宣告明细网段 复制代码
-
-
方式二:
-
宣告汇总网段:
network [汇总网段] 复制代码
-
汇总明细路由
aggregate [汇总后的网段] [子网掩码/长度] # 此时聚合与所有明细条目均传递 aggregate [汇总后的网段] [子网掩码/长度] detail-suppressed # 仅仅发送聚合路由,抑制所有的明细路由发送 复制代码
-
配置汇总网段的空接口:
ip route-static [汇总网段地址] [子网掩码/长度] null 0 复制代码
-
-
路由传递干涉策略:
-
※ 抑制列表:抑制抓取到路由网段
-
抓取流量:
ip ip-prefix [列表名] permit [目标IP网段] [子网掩码/长度] 复制代码
-
设置策略列表
route-policy [列表名] permit node [序列号] if-match ip-prefix [列表名] 复制代码
-
在BGP中调用抑制列表:
aggregate [汇总网段] [子网掩码/长度] suppress-policy [策略列表名] # 先进入BGP进程 复制代码
-
-
Route-map:在BGP中将route-map当分发列表用,抑制抓取到路由网段
-
先做了没有抑制明细路由的汇总
-
抓取流量:
ip ip-prefix [列表名] permit [目标IP网段] [子网掩码/长度] 复制代码
-
设置策略列表,拒绝抓取流量网段
route-policy [列表名] deny node [序列号] if-match ip-prefix [列表名] 复制代码
-
在BGP中调用:
peer [邻居的更新源地址] route-policy [策略列表名] export # 先进入BGP进程 # export:控制层面的出项(路由传递出的方向) # import:控制层面的入向 复制代码
-
-
分发列表:抑制抓取到路由网段
-
先做了没有抑制明细路由的汇总
-
抓取流量:
ip ip-prefix [列表名] deny [目标IP网段] [子网掩码/长度] ip ip-prefix [列表名] permit 0.0.0.0 0 less-equal 32 复制代码
-
在BGP中调用:
filter-policy ip-prefix [列表名] export # 先进入BGP进程 # export:控制层面的出项(路由传递出的方向) # import:控制层面的入向 复制代码
-
-
※ 前缀列表:BGP协议中可以直接将前缀列表作为分发列表调用,抑制抓取到路由网段
-
先做了没有抑制明细路由的汇总
-
抓取流量:
ip ip-prefix [列表名] deny [目标IP网段] [子网掩码/长度] ip ip-prefix [列表名] permit 0.0.0.0 0 less-equal 32 复制代码
-
在BGP中调用:
peer [邻居的更新源地址] ip ip-prefix [列表名] export # 先进入BGP进程 复制代码
-
-
-
12.BGP的选路规则:
-
规则:(前提:多条BGP路由目标相同,且均可优(下一条可达,同步关闭),具有相同的优先级)
- 优选权重值最高的路由(本地属性,不传递,权限最高的属性,可以干涉EBGP/IBGP选路)
- 优选本地优先级最高的路由(IBGP邻居间传递,最常干涉IBGP关系的选路)
- 优选 手动聚合 > 自动聚合 > network > import > 从对等体学到的
- 优选AS_Path短的路由(EBGP/IBGP关系均可被干涉,但只能在EBGP邻居间修改)
- 优选起源类型 IGP > EGP > Incomplete(可在控制层面任意接口修改)
- 优选来组同一AS的路由MED值最小的(最常干涉EBGP选路的属性)
-
如果属性无法解决选路问题,需要考虑如下
- 优选从EBGP学来的路由(EBGP > IBGP)
- 优先AS内部IGP的Metric最小的路由
- 优选Cluster_List最短的路由
- 优选Orginator_ID最小的路由
- 优选Router_ID最小的路由器发布的路由
- 优选具有较小IP地址的邻居学来的路由
-
BGP 路由惩罚:
-
特点:
- 被惩罚的路由不能参与选路,不能加入本地的IP路由表,不能传递
- 路由惩罚仅仅针对EBGP邻居学习的路由
-
惩罚值:路由条目每翻滚一次,惩罚值增加1000,路由属性每翻滚一次惩罚值增加500(不可修改),华为中最大惩罚值 默认为16000
-
惩罚门限:超过了惩罚门限开启进行路由惩罚,默认值为2000
-
重用门限:当惩罚值低于该值,重新使用该路由信息,默认为750
-
半衰期:默认为15分钟
-
配置:
- 启用BGP路由惩罚:
dampening [半衰期时间] [重用门限值] [惩罚门限值] [最大惩罚值] # 半衰期:默认为15分钟,重用门限:默认为750,惩罚门限:默认值为2000,最大惩罚值:16000 复制代码
- 查看路由惩罚参数:
display bgp routing-table dampening parameter 复制代码
- 查看被惩罚的路由:
display bgp routing-table dampened 复制代码
- (重启)清楚所有被惩罚的路由信息:
reset bgp dampening # 在用户模式下 复制代码
-
-
负载分担:去往不同的目标,将流量分担不同的链路上
-
负载均衡:到同一个目标基于多条路径同时传输
-
针对属性的修改来实现负载分担,正常时在BGP协议控制层面流量的入或出口上匹配信息,修改属性
-
权重属性:PrefVal
-
属性名 传播范围 默认值 取值范围 优先 权重 不传播,本地有效(私有) 0 0 - 65535 越大越优 -
修改对端传递过来的路由权重(全局修改)
peer [对端的更新源地址] preferred-value [权重值] # 先进入BGP进程 复制代码
-
修改对端传递过来的部分路由权重
-
抓取流量:
ip ip-prefix [列表名] permit [IP网段] [子网掩码/长度] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] apply preferred-value [权重值] # 加上空表,表示过行其他所有 复制代码
-
在BGP中调用:
peer [对端更新源地址] route-policy [列表名] import # 先进入BGP进程 复制代码
-
-
-
本地优先级:LocPrf
-
属性名 传播范围 默认值 取值范围 优先 本地优先级 IBGP邻居间 100 0 - 255 越大越优 -
最常用于干涉IBGP选路
-
修改本地优先级:(全局)
defalut local-preference [优先值] # 先进入BGP 复制代码
-
修改本地优先级:(部分)
-
抓取流量:
ip ip-prefix [列表名] permit [IP网段] [子网掩码/长度] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] apply local-preference [优先值] # 加上空表,表示过行其他所有 复制代码
-
在BGP中调用:
peer [对端更新源地址] route-policy [列表名] export # 先进入BGP进程 复制代码
-
-
-
下一跳:NextHop
-
路径:AS-Path
-
一条目在传递过程中将记录所有经过的AS编号,优选经过的AS数量最小的路径
-
AS-PATH只能在真正的EBGP关系间传递时可以添加(不能减少)
-
因为该属性同时用于EBGP水平分割:若存在本地AS号,将拒绝该条目
-
即可干涉EBGP关系,也可干涉IBGP关系选路,但修改时只能在EBGP关系进行
-
修改AS-PATH:
-
抓取流量:
ip ip-prefix [列表名] permit [IP网段] [子网掩码/长度] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] apply as-path [AS号] ..... additive # 加上空表,表示过行其他所有 复制代码
-
在BGP中调用:
peer [对端更新源地址] route-policy [列表名] [export/import] # 先进入BGP进程,EBGP邻居的出或入方向配置 复制代码
-
-
-
起源:Origin
-
修改Origin:
-
抓取流量:
ip ip-prefix [列表名] permit [IP网段] [子网掩码/长度] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] apply origin [i/e/?] [1/2] # 1:代表入口处修改,2:代表出口处修改 # 加上空表,表示过行其他所有 复制代码
-
在BGP中调用:
peer [对端更新源地址] route-policy [列表名] [export/import] # 先进入BGP进程 复制代码
-
-
-
度量:MED
-
多出口的鉴别属性
-
BGP协议自身没有度量值;只有在宣告本地路由或重发布IGP到BGP时,携带IGP度量,度量值在MED处显示
-
管理员可以利用该属性,来实现干涉选路(最常用于干涉EBGP关系选路,常常用于AS1干涉AS2对AS1的选路)
-
修改MED:
-
抓取流量:
ip ip-prefix [列表名] permit [IP网段] [子网掩码/长度] 复制代码
-
设置策略列表:
route-policy [列表名] permit node [序列号] apply cost [度量值] # 加上空表,表示过行其他所有 复制代码
-
在BGP中调用:
peer [对端更新源地址] route-policy [列表名] [export/import] # 先进入BGP进程
-
-
作者:阿尔托莉雅969
链接:https://juejin.cn/post/7170864533165047816
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。