zoukankan      html  css  js  c++  java
  • 环回接口(loopback interface)的新认识

    背景

    前些日子在IDC实验docker的时候,为了避免与公司网络冲突,将bridge设置为127.x网段的IP,原以为这样就OK,后来发现在访问container内部的服务的时候无法访问。开始以为iptables的问题,搞了半天,后来,才发现系统对127.x.x.x的包根本不会经过bridge。这两天补习了一下linux的路由实现,才彻底明白其中缘由。

    其实,关于环回接口,TCP/IP详解中已经描述得很清楚,只是自己没有去仔细阅读而已。

    TCP/IP关于环回接口的描述

    Linu支持环回接口( Loopback Interface),以允许运行在同一台主机上的客户程序和服务器程序通TCP/IP进行通信。 A 类网络127就是为环回接口预留的 。根据惯例,大多数系统把IP地址127.0.0.1分配给这个接口,并命名为localhost。一个传给环回接口的IP数据报不能在任何网络上出现。实际上,访问127.x.x.x的所有IP都是访问环回接口(lo)。

    按理来说,一旦传输层检测到目的端地址是环回地址时,应该可以省略部分传输层和所有网络层的逻辑操作。但是大多数的产品还是照样完成传输层和网络层的所有过程,只是当
I P 数据报离开网络层时把它返回给自己。Linux的内核实现就是这样。

     

    几个关键点:

    (1)传给环回地址(一般是127.0.0.1 )的任何数据均作为IP输入。

    (2)传给广播地址或多播地址的数据报复制一份传给环回接口,然后送到以太网上。这是因为广播传送和多播传送的定包含主机本身。

    (3)任何传给该主机I P地址的数据均送到环回接口 。

    从上面的描述可以明白,访问127.0.0.1和本机IP(比如192.168.1.10)都是通过lo来完成的。

    考虑如下路由表:

    尽管我们为172.16.213.0/24和129.0.0.0/8指定了出口设备(eth0/docker0),但实际上,数据仍然是通过lo来完成的。

    Linux的实现

    内核默认有两个路由表(不考虑策略路由):

    struct fib_table *ip_fib_local_table;

    struct fib_table *ip_fib_main_table;

    前者用于本地路由,后都可以由管理员配置。

    NewImage

    从上面的可以看到,172.16.213.129,127.0.0.0/8都被认为是本机IP。

    linux在进行路由查找时,先查找local,再查找main:

    static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)

    {

           if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) &&

               ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res))

                  return -ENETUNREACH;

           return 0;

    }

    实际上,如果内核认为目标地址是本机IP,就会将包的出口设备设置为loopback_dev(不管路由表将出口设备设置成什么)。

    static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)

    {

    ...

           if (res.type == RTN_LOCAL) {

                  if (!fl.fl4_src)

                         fl.fl4_src = fl.fl4_dst;

                  if (dev_out)

                         dev_put(dev_out);

                  dev_out = &loopback_dev;

                  dev_hold(dev_out);

                  fl.oif = dev_out->ifindex;

                  if (res.fi)

                         fib_info_put(res.fi);

                  res.fi = NULL;

                  flags |= RTCF_LOCAL;

                  goto make_route;

           }

    整个数据流过程:

     NewImage

     主要参考

    [1]TCP/IP详解

    [2]深入理解linux网络技术内幕


    作者:YY哥 
    出处:http://www.cnblogs.com/hustcat/ 
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    开启linux服务器防火墙
    Linux系统编程11_管道和命名管道
    Lua语法
    Git学习
    Buildroot介绍
    Makefile基本介绍
    页、页表和块
    文件系统,根文件系统,MTD
    什么是ioctl
    bootargs的mtdparts解析
  • 原文地址:https://www.cnblogs.com/hustcat/p/3920940.html
Copyright © 2011-2022 走看看