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/ 
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    IO 单个文件的多线程拷贝
    day30 进程 同步 异步 阻塞 非阻塞 并发 并行 创建进程 守护进程 僵尸进程与孤儿进程 互斥锁
    day31 进程间通讯,线程
    d29天 上传电影练习 UDP使用 ScketServer模块
    d28 scoket套接字 struct模块
    d27网络编程
    d24 反射,元类
    d23 多态,oop中常用的内置函数 类中常用内置函数
    d22 封装 property装饰器 接口 抽象类 鸭子类型
    d21天 继承
  • 原文地址:https://www.cnblogs.com/hustcat/p/3920940.html
Copyright © 2011-2022 走看看