使用mpls功能,首先需要加载mpls相关的模块:
$ sudo modprobe mpls_gso
$ sudo modprobe mpls_iptunnel
$ sudo modprobe mpls_router

使能mpls的接收和设置labels表项的数量,默认情况下内核不接收mpls报文,如果不使能此项,在如下使用ip命令配置本机环回lo接口接收mpls数据包时就会失败。labels转发表项的数量初始为0,将会导致不能配置label转发表项。

sysctl -w net.mpls.conf.lo.input=1
sysctl -w net.mpls.platform_labels=1048575

测试MPLS

添加MPLS路由, 使用标签 100 封装 10.10.10.10/32, 使用标签18封装 172.16.48.174/32.

ip route add 10.10.10.10/32 encap mpls 100 via inet 192.168.1.2
ip r add 172.16.48.174/32  encap mpls  18 via 50.0.1.5

输入标签 100 进行标签交换转发, 封装标签200并转发到 192.168.2.2.

ip -f mpls route add 100 as 200 via inet 192.168.2.2

输入标签300 转发到本地

ip -f mpls route add 300 dev lo

配置1:到网络10.1.1.0/30的数据包增加200和300两个label

$ sudo ip route add 10.1.1.0/30 encap mpls 200/300 via 192.168.1.1 dev ens33    

$ ip route 
10.1.1.0/30  encap mpls  200/300 via 192.168.1.1 dev ens33 
$

使用ping测试,tcpdump抓包内容可见,增加了200和300两个label,标签300设置了标签栈底标志[S]。
$ ping 10.1.1.1
PING 10.1.1.1 (10.1.1.1) 56(84) bytes of data.
$
$ sudo tcpdump mpls -vve
tcpdump: listening on ens33, link-type EN10MB (Ethernet), capture size 262144 bytes
23:36:30.813147 00:0c:29:74:7f:04 (oui Unknown) > 00:90:27:fe:c9:34 (oui Unknown), ethertype MPLS unicast (0x8847), length 106: 
MPLS (label 200, exp 0, ttl 64)
     (label 300, exp 0, [S], ttl 64)
     (tos 0x0, ttl 64, id 36751, offset 0, flags [DF], proto ICMP (1), length 84)
    localhost > localhost: ICMP echo request, id 6907, seq 1, length 64

配置2:标签为500的mpls数据包送到本机的环回接口lo:

$ sudo ip -f mpls route add 500 dev lo
$
$ip -f mpls route show
500 dev lo 
$

配置3:标签为100的数据包替换为标签600,发往192.168.1.2。

$ sudo ip -f mpls route add 100 as to 600 via inet 192.168.1.2
$
$ip -f mpls route show
100 as to 600 via inet 192.168.1.2 dev ens33 
500 dev lo 
$

配置4:指定多个下一跳地址,为每个下一跳指定不同的(90/91)标签:

$ sudo ip -f mpls route add 80 nexthop as to 90 via inet 192.168.1.2 nexthop as to 91 via inet 192.168.1.3  

$ ip -d -f mpls route show
unicast 80 proto boot scope global 
        nexthop as to 90 via inet 192.168.1.2  dev ens33
        nexthop as to 91 via inet 192.168.1.3  dev ens33
$

MPLS的路由结构

内核函数mpls_route_add处理MPLS路由的添加工作。所有的MPLS路由全部组织在网络命名空间的成员platform_label指针数组(指针的指针)中,通过标签值可找到对应的MPLS路由。全部路由不超过platform_labels指定的最大数量。

struct netns_mpls {size_t platform_labels;struct mpls_route __rcu * __rcu *platform_label;
}

一个mpls_route路由表项所占空间与其所有的下一跳mpls_nh的空间,以及每个下一跳的所有label空间之总和不超过4K字节大小。mpls_route路由表项结构图如下:

另外,内核注册了netdev通知链函数mpls_dev_notify处理mpls路由的失效和活动状态。

static struct notifier_block mpls_dev_notifier = {.notifier_call = mpls_dev_notify,
};

当接收到设备关闭NETDEV_DOWN事件时,调用mpls_ifdown遍历所有的mpls路由表项,将出口设备为此设备的表项标记为不可用(RTNH_F_DEAD)。如果接收到设备NETDEV_UP的事件,同样的遍历所有的表项,经出口设备为此设备的表项标记为可用,即去掉RTNH_F_DEAD标志。

static int mpls_dev_notify(struct notifier_block *this, unsigned long event, void *ptr)
{struct net_device *dev = netdev_notifier_info_to_dev(ptr);switch (event) {case NETDEV_DOWN:mpls_ifdown(dev, event);break;case NETDEV_UP:mpls_ifup(dev, RTNH_F_DEAD | RTNH_F_LINKDOWN);break;}
}

MPLS数据帧处理

Linux内核协议栈注册了一个ETH_P_MPLS_UC(0x8847)类型的数据包处理函数(mpls_packet_type)处理MPLS报文。

static struct packet_type mpls_packet_type __read_mostly = {.type = cpu_to_be16(ETH_P_MPLS_UC),.func = mpls_forward,
};

首先通过MPLS标签解析mpls_entry_decode函数,得到数据包中MPLS标签的4个字段:标签值、TTL、流量类别和标签栈底标志位。标签值字段占用20个bit位,其最大值为2**20 -1,由于mpls协议存在预留值,合法的标签值从16开始(MPLS_LABEL_FIRST_UNRESERVED)。

static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr *hdr)
{    struct mpls_entry_decoded result;unsigned entry = be32_to_cpu(hdr->label_stack_entry);result.label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;result.ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;result.tc =  (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;result.bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;return result;
}

其次通过得到的MPLS标签值,查询mpls路由表。有之前介绍的mpls路由表结构可知,以标签值做索引即可找到对应的路由项:

static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
{struct mpls_route __rcu **platform_label = rcu_dereference(net->mpls.platform_label);rt = rcu_dereference(platform_label[index]);return rt;
}

对于仅有一个下一跳的路由表项,直接使用。对于多个下一跳地址,需要在找到的路由项中,选择一个下一跳地址,函数(mpls_select_multipath)完成此功能。检查如果活动的下一跳的个数为0,返回空。否则根据数据包中的以下字段计算hash值:最多4个标签值、IP头的源IP地址、目的IP地址和协议号。得到的hash值与当前活动的下一跳数量(alive)取余得到下一跳地址的索引值。mpls_get_nexthop函数取出mpls路由的下一跳。

如果活动的下一跳数量与下一跳总数相等,说明根据下一跳索引nh_index可以直接取到下一跳结构。否则,需要遍历所有活动的下一跳列表,找到此下一跳。

    alive = READ_ONCE(rt->rt_nhn_alive);if (alive == 0) return NULL;hash = mpls_multipath_hash(rt, skb);nh_index = hash % alive;if (alive == rt->rt_nhn) goto out;for_nexthops(rt) {unsigned int nh_flags = READ_ONCE(nh->nh_flags);if (nh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN))  continue;if (n == nh_index) return nh;n++;} endfor_nexthops(rt);
out:return mpls_get_nexthop(rt, nh_index);

如果配置了标签替换,仅替换数据包中的顶层标签。以下代码将mpls路由表项中下一跳对应的标签栈写入到数据包头中。

    hdr = mpls_hdr(skb);bos = dec.bos;for (i = nh->nh_labels - 1; i >= 0; i--) {hdr[i] = mpls_entry_encode(nh->nh_label[i], dec.ttl, 0, bos);bos = false;}

环境
iproute2版本:4.17.0
内核版本:  Linux-4.15

Linux MPLS功能详解相关推荐

  1. Linux下的tar归档及解压缩功能详解

    Linux下的tar归档及解压缩功能详解 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.Linux下解压缩工具 二.gzip工具的使用方法 三.其他解压缩工具 一.L ...

  2. 【转载】Linux命令-自动挂载文件/etc/fstab功能详解[转]

    博客园 首页 新随笔 联系 订阅 管理 随笔 - 322  文章 - 0  评论 - 19 Linux命令-自动挂载文件/etc/fstab功能详解[转]     一./etc/fstab文件的作用 ...

  3. Linux 挂载windows网络共享文件 /etc/fstab功能详解

    转载自: http://www.cnblogs.com/qiyebao/p/4484047.html Linux命令-自动挂载文件/etc/fstab功能详解[转] 一./etc/fstab文件的作用 ...

  4. linux who命令功能,Linux who命令详解

    who 命令显示关于当前在本地系统上的所有用户的信息.显示以下内容:登录名.tty.登录日期和时间.输入whoami 显示您的登录名.tty.您登录的日期和时间.如果用户是从一个远程机器登录的,那么该 ...

  5. linux日志配置含义,Linux操作系统中的日志功能详解

    日志系统将我们系统运行的每一个状况信息都使用文字记录下来,这些信息有助我们观察系统运行过程中正常状态和系统运行错误时快速定位错误位置的途径等;下面学习啦小编主要概述一下Linux操作系统中的日志功能. ...

  6. 【网络编程】Linux tcpdump命令详解---编辑中

    目录 即看即用 详细说明 简介 输出信息含义 链路层头 TCP 数据包 UDP 数据包 SMB/CIFS 解码 AFS 请求和回应 KIP AppleTalk协议 IP 数据包破碎 时间戳 反向过滤 ...

  7. Linux磁盘阵列技术详解(二)--raid 1创建

    我在Linux磁盘阵列技术详解(一)里已经详细介绍了几种RAID磁盘阵列方式,原理以及创建raid 0 的详细步骤.那么这篇文档就着重讲解如何创建raid 1的技术: 步骤如下: ① 分区 同样我们还 ...

  8. linux mingetty 命令详解

    linux mingetty 命令详解 功能说明:精简版的getty. 语 法:mingetty [--long-hostname][--noclear][tty] 补充说明:mingetty适用于本 ...

  9. linux zip 命令详解

    功能说明:压缩文件.  语 法:zip [-AcdDfFghjJKlLmoqrSTuvVwXyz$][-b <工作目录>][-ll][-n <字尾字符串>][-t <日期 ...

  10. linux zipinfo 命令详解

    linux zipinfo 命令详解 功能说明:列出压缩文件信息. 语 法:zipinfo [-12hlmMstTvz][压缩文件][文件...][-x <范本样式>] 补充说明:执行zi ...

最新文章

  1. tom大叔blog--------深入理解javascript系列-----------笔记
  2. RK1109 RK1126等芯片来袭,2020年瑞芯微旗下SoC一览
  3. 计算机组装过程英文版,计算机组装与维护试题及答案(国外英文资料).doc
  4. GaussDB(for MySQL)如何快速创建索引?华为云数据库资深架构师为您揭秘
  5. linux远程日志rsyslog服务端和客户端安装(亲测)--自定义接收日志格式
  6. ISE与Notepad++关联
  7. 广义逆高斯分布(Generalized Inverse Gaussian Distribution)及修正贝塞尔函数
  8. 【git】小乌龟和git冲突
  9. 微积分的发现是人类精神的最高胜利
  10. 【汇编语言】DOSBox教程
  11. 云服务器 微信支付开发,WeX5怎么样实现支付宝和微信支付接口
  12. pixiv的服务器信息,Pixiver™
  13. 2020成考C语言答案,2020年成人高考语文题库(含历年真题练习题模拟题)
  14. 山东建筑大学计算机学院孙倩,山东建筑大学毕业设计答辩.pdf
  15. 4A(统一安全管控平台)解析
  16. 三菱FX3U PLC模拟量输入FB(FX2N-2AD)
  17. 算法设计与分析-----动态规划
  18. GEE学习笔记:在Google Earth Engine(GEE)计算两个时间的时间间隔
  19. Ubuntu18.04使用锐捷登录校园网
  20. 赵纪锋首谈2018淘宝双十一全新玩儿法!恭喜你在双十一前看见了!

热门文章

  1. 多人操作sqlite3数据库冲突问题解决方法
  2. 工作5年的一份总结(1)-07/09-07/11
  3. 算法笔记2-优先队列(堆)(上)
  4. 采用nettcp绑定的wcf宿主到iis7
  5. STORM的DRPC通讯
  6. Xcode的插件的路径
  7. 应用HTK搭建语音拨号系统2:创建单音素HMM模型
  8. 很酷的CSS3仿Facebook登录表单
  9. asp.net 无法访问已关闭的资源集
  10. keepalived基本应用解析