成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

天天講路由,那 Linux 路由到底咋實現的!?

系統 Linux 商務辦公
容器是一種新的虛擬化技術,每一個容器都是一個邏輯上獨立的網絡環境。Linux 上提供了軟件虛擬出來的二層交換機 Bridge 可以解決同一個宿主機上多個容器之間互連的問題,但這是不夠的。二層交換無法解決容器和宿主機外部網絡的互通。

 

本文轉載自微信公眾號「開發內功修煉」,作者張彥飛allen。轉載本文請聯系開發內功修煉公眾號。

大家好,我是飛哥。

容器是一種新的虛擬化技術,每一個容器都是一個邏輯上獨立的網絡環境。Linux 上提供了軟件虛擬出來的二層交換機 Bridge 可以解決同一個宿主機上多個容器之間互連的問題,但這是不夠的。二層交換無法解決容器和宿主機外部網絡的互通。

容器肯定是需要和宿主機以外的外部網絡互通才具備實用價值的。比如在 Kubernets 中,就要求所有的 pod 之間都可以互通。相當于在原先物理機所組成的網絡之上,要再建一個互通的虛擬網絡出來。這就是 Overlay 網絡的概念,用一個簡單的示例圖表示如下。

回想在傳統物理物理網絡中,不同子網之間的服務器是如何互聯起來的呢,沒錯,就是在三層工作的路由器,也叫網關。路由器使得數據包可以從一個子網中傳輸到另一個子網中,進而實現更大范圍的網絡互通。如下圖所示,一臺路由器將 192.168.0.x 和 192.168.1.x 兩個子網連接了起來。

在容器虛擬化網絡中,自然也需要這么一個角色,將容器和宿主機以外的網絡連接起來。其實 Linux 天生就具備路由的功能,只是在云原生時代,它的路由功能再一次找到了用武之地。在容器和外部網絡通信的過程中,Linux 就又承擔起路由器的角色,實現容器數據包的正確轉發和投遞。

在各種基于容器的云原生技術盛行的今天,再次回頭深刻理解路由工作原理顯得非常有必要,而且也非常的有價值。今天,我們就再來強化一下 Linux 上的路由知識!

一、什么時候需要路由

先來聊聊 Linux 在什么情況下需要路由過程。其實在發送數據時和接收數據時都會涉及到路由選擇,為什么?我們挨個來看。

1.1 發送數據時選路

Linux 之所以在發送數據包的時候需要進行路由選擇,這是因為服務器上是可能會有多張網卡設備存在的。數據包在發送的時候,一路通過用戶態、TCP 層到了 IP 層的時候,就要進行路由選擇,以決定使用哪張網卡設備把數據包送出去。詳細過程參見25 張圖,一萬字,拆解 Linux 網絡包發送過程

來大致過一下路由相關源碼源碼。網絡層發送的入口函數是 ip_queue_xmit。

  1. //file: net/ipv4/ip_output.c 
  2. int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) 
  3.  // 路由選擇過程 
  4.  // 選擇完后記錄路由信息到 skb 上 
  5.  rt = (struct rtable *)__sk_dst_check(sk, 0); 
  6.  if (rt == NULL) { 
  7.   // 沒有緩存則查找路由項 
  8.   rt = ip_route_output_ports(...); 
  9.   sk_setup_caps(sk, &rt->dst); 
  10.  } 
  11.  skb_dst_set_noref(skb, &rt->dst); 
  12.  ... 
  13.  //發送 
  14.  ip_local_out(skb); 

在 ip_queue_xmit 里我們開頭就看到了路由項查找, ip_route_output_ports 這個函數中完成路由選擇。路由選擇就是到路由表中進行匹配,然后決定使用哪個網卡發送出去。

Linux 中最多可以有 255 張路由表,其中默認情況下有 local 和 main 兩張。使用 ip 命令可以查看路由表的具體配置。拿 local 路由表來舉例。

  1. #ip route list table local 
  2. local 10.143.x.y dev eth0 proto kernel scope host src 10.143.x.y 
  3. local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 

1.2 接收數據時選路

沒錯,接收數據包的時候也需要進行路由選擇。這是因為 Linux 可能會像路由器一樣工作,將收到的數據包通過合適的網卡將其轉發出去。

Linux 在 IP 層的接收入口 ip_rcv 執行后調用到 ip_rcv_finish。在這里展開路由選擇。如果發現確實就是本設備的網絡包,那么就通過 ip_local_deliver 送到更上層的 TCP 層進行處理。

如果路由后發現非本設備的網絡包,那就進入到 ip_forward 進行轉發,最后通過 ip_output 發送出去。

具體的代碼如下。

  1. //file: net/ipv4/ip_input.c 
  2. static int ip_rcv_finish(struct sk_buff *skb){ 
  3.     ... 
  4.     if (!skb_dst(skb)) { 
  5.         int err = ip_route_input_noref(skb, iph->daddr, iph->saddr, 
  6.                            iph->tos, skb->dev); 
  7.         ... 
  8.     } 
  9.     ... 
  10.     return dst_input(skb); 

其中 ip_route_input_noref 就是在進行路由查找。

  1. //file: net/ipv4/route.c 
  2. int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, 
  3.     u8 tos, struct net_device *dev) 
  4.  ... 
  5.  res = ip_route_input_slow(skb, daddr, saddr, tos, dev); 
  6.  return res; 

這里記著 ip_route_input_slow 就行了,后面我們再看。

1.3 linux 路由小結

路由在內核協議棧中的位置可以用如下一張圖來表示。

網絡包在發送的時候,需要從本機的多個網卡設備中選擇一個合適的發送出去。網絡包在接收的時候,也需要進行路由選擇,如果是屬于本設備的包就往上層送到網絡層、傳輸層直到 socket 的接收緩存區中。如果不是本設備上的包,就選擇合適的設備將其轉發出去。

二、Linux 的路由實現

2.1 路由表

路由表(routing table)在內核源碼中的另外一個叫法是轉發信息庫(Forwarding Information Base,FIB)。所以你在源碼中看到的 fib 開頭的定義基本上就是和路由表相關的功能。

其中路由表本身是用 struct fib_table 來表示的。

  1. struct fib_table { 
  2.  struct hlist_node tb_hlist; 
  3.  u32   tb_id; 
  4.  int   tb_default; 
  5.  int   tb_num_default; 
  6.  unsigned long  tb_data[0]; 
  7. }; 

所有的路由表都通過一個 hash - fib_table_hash 來組織和管理。它是放在網絡命名空間 net 下的。這也就說明每個命名空間都有自己獨立的路由表。

  1. //file:include/net/net_namespace.h 
  2. struct net { 
  3.  struct netns_ipv4 ipv4; 
  4.  ... 
  5.  
  6. //file: include/net/netns/ipv4.h 
  7. struct netns_ipv4 { 
  8.  // 所有路由表  
  9.  struct hlist_head *fib_table_hash; 
  10.  
  11.  // netfilter 
  12.  ... 

在默認情況下,Linux 只有 local 和 main 兩個路由表。如果內核編譯時支持策略路由,那么管理員最多可以配置 255 個獨立的路由表。

如果你的服務器上創建了多個網絡命名空間的話,那么就會存在多套路由表。以除了默認命名網絡空間外,又創了了一個新網絡命名空間的情況為例,路由表在整個內核數據結構中的關聯關系總結如下圖所示。

2.2 路由查找

在上面的小節中我們看到,發送過程調用 ip_route_output_ports 來查找路由,接收過程調用 ip_route_input_slow 來查找。但其實這兩個函數都又最終會調用到 fib_lookup 這個核心函數,源碼如下。

  1. //file: net/ipv4/route.c 
  2. struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4) 
  3.  ... 
  4.  // 進入 fib_lookup 
  5.  if (fib_lookup(net, fl4, &res)) { 
  6.  } 
  7.  
  8. //file: net/ipv4/route.c 
  9. static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, 
  10.           u8 tos, struct net_device *dev) 
  11.  ... 
  12.  // 進入 fib_lookup 
  13.  err = fib_lookup(net, &fl4, &res); 

我們來看下 fib_loopup 都干了啥。為了容易理解,我們只看一下不支持多路由表版本的 fib_lookup。

  1. //file: include/net/ip_fib.h 
  2. static inline int fib_lookup(struct net *net, const struct flowi4 *flp, 
  3.         struct fib_result *res) 
  4.  struct fib_table *table
  5.  
  6.  table = fib_get_table(net, RT_TABLE_LOCAL); 
  7.  if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF)) 
  8.   return 0; 
  9.  
  10.  table = fib_get_table(net, RT_TABLE_MAIN); 
  11.  if (!fib_table_lookup(table, flp, res, FIB_LOOKUP_NOREF)) 
  12.   return 0; 
  13.  return -ENETUNREACH; 

這個函數就是依次到 local 和 main 表中進行匹配,匹配到后就返回,不會繼續往下匹配。從上面可以看到 local 表的優先級要高于 main 表,如果 local 表中找到了規則,則路由過程就結束了。

這也就是很多同學說為什么 ping 本機的時候在 eth0 上抓不到包的根本原因。所有命中 local 表的包都會被送往 loopback 設置,不會過 eth0。

三、路由的使用方法

3.1 開啟轉發路由

在默認情況下,Linux 上的轉發功能是關閉的,這時候 Linux 發現收到的網絡包不屬于自己就會將其丟棄。

但在某些場景下,例如對于容器網絡來說,Linux 需要轉發本機上其它網絡命名空間中過來的數據包,需要手工開啟轉發。如下這兩種方法都可以。

  1. # sysctl -w net.ipv4.ip_forward=1 
  2. # sysctl net.ipv4.conf.all.forwarding=1 

開啟后,Linux 就能像路由器一樣對不屬于本機(嚴格地說是本網絡命名空間)的 IP 數據包進行路由轉發了。

3.2 查看路由表

在默認情況下,Linux 只有 local 和 main 兩個路由表。如果內核編譯時支持策略路由,那么管理員最多可以配置 255 個獨立的路由表。在 centos 上可以通過以下方式查看是否開啟了 CONFIG_IP_MULTIPLE_TABLES 多路由表支持。

  1. # cat /boot/config-3.10.0-693.el7.x86_64  
  2. CONFIG_IP_MULTIPLE_TABLES=y 
  3. ... 

所有的路由表按照從 0 - 255 進行編號,每個編號都有一個別名。編號和別名的對應關系在 /etc/iproute2/rt_tables 這個文件里可以查到。

  1. # cat /etc/iproute2/rt_tables 
  2. 255     local 
  3. 254     main 
  4. 253     default 
  5. 0       unspec 
  6. 200     eth0_table 

查看某個路由表的配置,通過使用 ip route list table {表名} 來查看。

  1. #ip route list table local 
  2. local 10.143.x.y dev eth0 proto kernel scope host src 10.143.x.y 
  3. local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1 

如果是查看 main 路由表,也可以直接使用 route 命令

  1. # route -n 
  2. Kernel IP routing table 
  3. Destination     Gateway         Genmask         Flags Metric Ref    Use Iface 
  4. 10.0.0.0        10.*.*.254      255.0.0.0       UG    0      0        0 eth0 
  5. 10.*.*.0        0.0.0.0         255.255.248.0   U     0      0        0 eth0 

上面字段中的含義如下

  • Destination:目的地址,可以是一個具體的 IP,也可以是一個網段,和 Genmask 一起表示。
  • Gateway:網關地址,如果是 0.0.0.0 表示不需要經過網關。
  • Flags: U 表示有效,G 表示連接路由,H 這條規則是主機路由,而不是網絡路由。
  • Iface:網卡設備,使用哪個網卡將包送過去。

上述結果中輸出的第一條路由規則表示這臺機器下,確切地說這個網絡環境下,所有目標為 10.0.0.0/8(Genmask 255.0.0.0 表示前 8 位為子網掩碼) 網段的網絡包都要通過 eth0 設備送到 10...254 這個網關,由它再幫助轉發。

第二條路由規則表示,如果目的地址是 10...0/21(Genmask 255.255.248.0 表示前 21 位為子網掩碼)則直接通過 eth0 發出即可,不需要經過網關就可通信。

3.3 修改路由表

默認的 local 路由表是內核根據當前機器的網卡設備配置自動生成的,不需要手工維護。對于main 的路由表配置我們一般只需要使用 route add 命令就可以了,刪除使用 route del。

修改主機路由

  1. # route add -host 192.168.0.100 dev eth0 //直連不用網關 
  2. # route add -host 192.168.1.100 dev eth0 gw 192.168.0.254 //下一跳網關 

修改網絡路由

  1. # route add -net 192.168.1.0/24 dev eth0 //直連不用網關 
  2. # route add -net 192.168.1.0/24 dev eth0 gw 10.162.132.110 //下一跳網關 

也可以指定一條默認規則,不命中其它規則的時候會執行到這條。

  1. # route add default gw 192.168.0.1 eth0 

對于其它編號的路由表想要修改的話,就需要使用 ip route 命令了。這里不過多展開,只用 main 表舉一個例子,有更多使用需求的同學請自行搜索。

  1. # ip route add 192.168.5.0/24 via 10.*.*.110 dev eth0 table main 

3.4 路由規則測試

在配置了一系列路由規則后,為了快速校驗是否符合預期,可以通過 ip route get 命令來確認。

  1. # ip route get 192.168.2.25 
  2. 192.168.2.25 via 10.*.*.110 dev eth0 src 10.*.*.161 
  3.     cache 

本文總結

在現如今各種網絡虛擬化技術里,到處都能看著對路由功能的靈活應用。所以我們今天專門深入研究了一下 Linux 路由工作原理。

在 Linux 內核中,對于發送過程和接收過程都會涉及路由選擇,其中接收過程的路由選擇是為了判斷是該本地接收還是將它轉發出去。

 

默認有 local 和 main 兩個路由表,不過如果安裝的 linux 開啟了 CONFIG_IP_MULTIPLE_TABLES 選項的話,最多能支持 255 張路由表。

路由選擇過程其實不復雜,就是根據各個路由表的配置找到合適的網卡設備,以及下一跳的地址,然后把包轉發出去就算是完事。

通過合適地配置路由規則,容器中的網絡環境和外部的通信不再是難事。通過大量地干預路由規則就可以實現虛擬網絡互通。

 

好了,今天的分享就到這里了,期待你的點贊、再看和轉發~~

 

責任編輯:武曉燕 來源: 開發內功修煉
相關推薦

2010-08-05 13:11:52

2018-06-04 16:20:56

Linux動態路由Quagga

2011-09-05 14:07:07

linux系統QOS限速路由

2011-04-01 12:37:19

路由

2011-04-01 13:28:37

2010-06-10 16:20:37

BGP路由協議

2009-12-02 12:52:00

華為路由器命令

2013-12-16 14:41:45

2011-04-01 13:01:57

路由表路由器

2011-04-01 13:32:27

路由路由器

2011-04-01 13:55:58

路由路由器路由表

2009-11-18 09:22:43

linux路由功能

2011-04-01 14:15:41

路由路由器路由接口

2014-06-16 16:37:36

linux路由表

2019-09-10 13:58:57

動態路由路由器網絡

2009-11-11 16:56:46

VRRP路由技術

2011-08-29 14:45:15

路由器ADSL貓雙路由連接

2010-08-13 09:08:11

CISCO配置

2018-05-03 15:03:09

內存虛擬化空間

2009-11-12 15:06:46

路由器故障
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 色婷婷国产精品综合在线观看 | 久久久精品综合 | 日本在线中文 | 成人精品一区二区三区 | 中文字幕一区二区三区在线观看 | 嫩草国产 | 在线免费观看黄a | 亚洲精品第一国产综合野 | 久久久蜜臀国产一区二区 | 国内精品视频一区二区三区 | 青青久久| 国产精品永久久久久久久www | 成人精品久久日伦片大全免费 | www精品美女久久久tv | 亚洲精品91 | 一级片视频免费 | 九九色综合 | 天天想天天干 | 亚洲一区二区三 | 日皮视频免费 | 国产精品永久免费观看 | 亚洲一区二区三区免费在线观看 | 精品国产乱码久久久久久老虎 | 日本电影一区二区 | 日韩成人在线电影 | 一区二区三区国产在线观看 | 高清免费av | 国产精品美女 | 欧美日韩中 | 日韩精品免费在线观看 | 99精品99 | 看a网站| 欧美亚洲国产一区二区三区 | 亚洲视频免费 | 国产黄色小视频 | 好姑娘高清在线观看电影 | 狠狠躁18三区二区一区 | 国产一区二区三区四区五区3d | 亚洲视频免费观看 | 免费在线观看av片 | 99精品网站 |