日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Docker源码分析(八):Docker Container网络(下)

發布時間:2025/4/5 编程问答 71 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Docker源码分析(八):Docker Container网络(下) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://www.infoq.com/cn/articles/docker-source-code-analysis-part8

1.Docker Client配置容器網絡模式

Docker目前支持4種網絡模式,分別是bridge、host、container、none,Docker開發者可以根據自己的需求來確定最適合自己應用場景的網絡模式。

從Docker Container網絡創建流程圖中可以看到,創建流程第一個涉及的Docker模塊即為Docker Client。當然,這也十分好理解,畢竟Docker Container網絡環境的創建需要由用戶發起,用戶根據自身對容器的需求,選擇網絡模式,并將其通過Docker Client傳遞給Docker Daemon。本節,即從Docker Client源碼的角度,分析如何配置Docker Container的網絡模式,以及Docker Client內部如何處理這些網絡模式參數。

需要注意的是:配置Docker Container網絡環境與創建Docker Container網絡環境有一些區別。區別是:配置網絡環境指用戶通過向Docker Client傳遞網絡參數,實現Docker Container網絡環境參數的配置,這部分配置由Docker Client傳遞至Docker Daemon,并由Docker Daemon保存;創建網絡環境指,用戶通過Docker Client向Docker Daemon發送容器啟動命令之后,Docker Daemon根據之前保存的網絡參數,實現Docker Container的啟動,并在啟動過程中完成Docker Container網絡環境的創建。

以上的基本知識,理解下文的Docker Container網絡環境創建流程。

1.1 Docker Client使用

Docker架構中,用戶可以通過Docker Client來配置Docker Container的網絡模式。配置過程主要通過docker run命令來完成,實現配置的方式是在docker run命令中添加網絡參數。使用方式如下(其中NETWORKMODE為四種網絡模式之一,ubuntu為鏡像名稱,/bin/bash為執行指令):

docker run -d --net NETWORKMODE ubuntu /bin/bash

運行以上命令時,首先創建一個Docker Client,然后Docker Client會解析整條命令的請求內容,接著解析出為run請求,意為運行一個Docker Container,最終通過Docker Client端的API接口,調用CmdRun函數完成run請求執行。(詳情可以查閱《Docker源碼分析》系列的第二篇——Docker Client篇)。

Docker Client解析出run命令之后,立即調用相應的處理函數CmdRun進行處理關于run請求的具體內容。CmdRun的作用主要可以歸納為三點:

  • 解析Docker Client傳入的參數,解析出config、hostconfig和cmd對象等;
  • 發送請求至Docker Daemon,創建一個container對象,完成Docker Container啟動前的準備工作;
  • 發送請求至Docker Daemon,啟動相應的Docker Container(包含創建Docker Container網絡環境創建)。

1.2 runconfig包解析

CmdRun函數的實現位于./docker/api/client/commands.go。CmdRun執行的第一個步驟為:通過runconfig包中ParseSubcommand函數解析Docker Client傳入的參數,并從中解析出相應的config,hostConfig以及cmd對象,實現代碼如下:

config, hostConfig, cmd, err := runconfig.ParseSubcommand (cli.Subcmd("run", "[OPTIONS] IMAGE [COMMAND] [ARG...]", "Run a command in a new container"), args, nil)

其中,config的類型為Config結構體,hostConfig的類型為HostConfig結構體,兩種類型的定義均位于runconfig包。Config與HostConfig類型同用以描述Docker Container的配置信息,然而兩者之間又有著本質的區別,最大的區別在于兩者各自的作用范疇:

  • Config結構體:描述Docker Container獨立的配置信息。獨立的含義是:Config這部分信息描述的是容器本身,而不會與容器所在host宿主機相關;
  • HostConfig結構體:描述Docker Container與宿主機相關的配置信息。

1.2.1 Config結構體

Config結構體描述Docker Container本身的屬性信息,這些信息與容器所在的host宿主機無關。結構體的定義如下:

type Config struct {Hostname stringDomainname stringUser stringMemory int64 // Memory limit (in bytes)MemorySwap int64 // Total memory usage (memory + swap); set `-1' to disable swapCpuShares int64 // CPU shares (relative weight vs. other containers)Cpuset string // Cpuset 0-2, 0,1AttachStdin boolAttachStdout boolAttachStderr boolPortSpecs []string // Deprecated - Can be in the format of 8080/tcpExposedPorts map[nat.Port]struct{}Tty bool // Attach standard streams to a tty, including stdin if it is not closed.OpenStdin bool // Open stdinStdinOnce bool // If true, close stdin after the 1 attached client disconnects.Env []stringCmd []stringImage string // Name of the image as it was passed by the operator (eg. could be symbolic)Volumes map[string]struct{}WorkingDir stringEntrypoint []stringNetworkDisabled boolOnBuild []string }

Config結構體中各屬性的詳細解釋如下表:

Config結構體屬性名

類型

代表含義

Hostname

string

容器主機名

Domainname

string

域名名稱

User

string

用戶名

Memory

int64

容器內存使用上限(單位:字節)

MemorySwap

int64

容器所有的內存使用上限(物理內存+交互區),關閉交互區支持置為-1

CpuShares

int64

容器CPU使用share值,其他容器的相對值

Cpuset

string

CPU核的使用集合

AttachStdin

bool

是否附加標準輸入

AttachStdout

bool

是否附加標準輸出

AttachStderr

bool

是否附加標準錯誤輸出

PortsSpecs

[]string

目前已被遺棄

ExposedPorts

map[nat.Port]struct{}

容器內部暴露的端口號

Tty

bool

是否分配一個偽終端tty

OpenStdin

bool

在沒有附加標準輸入時,是否依然打開標準輸入

StdinOnce

bool

若為真,表示第一個客戶關閉標準輸入后關閉標準輸入功能

Env

[]string

容器進程運行的環境變量

Cmd

[]string

容器內通過ENTRYPOINT運行的指令

Image

string

容器rootfs所依賴的鏡像名稱

Volumes

map[string]struct{}

容器需要從host宿主機上掛載的目錄

WorkingDir

string

容器內部的指定工作目錄

Entrypoint

[]string

覆蓋鏡像屬性中默認的ENTRYPOINT

NetworkDisabled

bool

是否關閉容器網絡功能

OnBuild

[]string

?

1.2.2 HostConfig結構體

HostConfig結構體描述Docker Container與宿主機相關的屬性信息,結構體的定義如下:

type HostConfig struct {Binds []stringContainerIDFile stringLxcConf []utils.KeyValuePairPrivileged boolPortBindings nat.PortMapLinks []stringPublishAllPorts boolDns []stringDnsSearch []stringVolumesFrom []stringDevices []DeviceMappingNetworkMode NetworkModeCapAdd []stringCapDrop []stringRestartPolicy RestartPolicy }

Config結構體中各屬性的詳細解釋如下表:

HostConfig結構體屬性名

類型

代表含義

Binds

[]string

從宿主機上綁定到容器的volumes

ContainerIDFile

string

文件名,文件用以寫入容器的ID

LxcConf

[]utils.KeyValuePair

添加自定義的lxc選項

Privileged

bool

是否賦予該容器擴展權限

PortBindings

nat.PortMap

容器綁定到host宿主機的端口

Links

[]string

添加其他容器的鏈接到該容器

PublishAllPorts

bool

是否向宿主機暴露所有端口信息

Dns

[]string

自定義的DNS服務器地址

DnsSearch

[]string

自定義的DNS查找服務器地址

VolumesFrom

[]string

從指定的容器中掛載到該容器的volumes

Devices

[]DeviceMapping

為容器添加一個或多個宿主機設備

NetworkMode

NetworkMode

為容器設置的網絡模式

CapAdd

[]string

為容器用戶添加一個或多個Linux Capabilities

CapDrop

[]string

為容器用戶禁用一個或多個Linux Capabilities

RestartPolicy

RestartPolicy

當一個容器異常退出時采取的重啟策略

1.2.3 runconfig解析網絡模式

講述完Config與HostConfig結構體之后,回到runconfig包中分析如何解析與Docker Container網絡模式相關的配置信息,并將這部分信息傳遞給config實例與hostConfig實例。

runconfig包中的ParseSubcommand函數調用parseRun函數完成命令請求的分析,實現代碼位于./docker/runconfig/parse.go#L37-L39,如下:

func ParseSubcommand(cmd *flag.FlagSet, args []string,sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {return parseRun(cmd, args, sysInfo) }

進入parseRun函數即可發現:該函數完成了四方面的工作:

  • 定義與容器配置信息相關的flag參數;
  • 解析docker run命令后緊跟的請求內容,將請求內容全部保存至flag參數中,余下的內容一個為鏡像image名,另一個為需要在容器內執行的cmd命令;
  • 通過flag參數驗證參數的有效性,并處理得到Config結構體與HostConfig結構體需要的屬性值;
  • 創建并初始化Config類型實例config、HostConfig類型實例hostConfig,最總返回config、hostConfig與cmd。

本文主要分析Docker Container的網絡模式,而parseRun函數中有關容器網絡模式的flag參數有flNetwork與flNetMode,兩者的定義分別位于./docker/runconfig/parse.go#L62與./docker/runconfig/parse.go#L75,如下:

flNetwork = cmd.Bool([]string{"#n", "#-networking"}, true, "Enable networking for this container")

flNetMode = cmd.String([]string{"-net"}, "bridge", "Set the Network mode for the container\n'bridge': creates a new network stack for the container on the docker bridge\n'none': no networking for this container\n'container:<name|id>': reuses another container network stack\n'host': use the host network stack inside the container. Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure.")

可見flag參數flNetwork表示是否開啟容器的網絡模式,若為true則開啟,說明需要給容器創建網絡環境;否則不開啟,說明不給容器賦予網絡功能。該flag參數的默認值為true,另外使用該flag的方式為:在docker run之后設定--networking或者-n,如:

docker run --networking true ubuntu /bin/bash

另一個flag參數flNetMode則表示為容器設定的網絡模式,共有四種選項,分別是:bridge、none、container:<name|id>和host。四種模式的作用上文已經詳細解釋,此處不再贅述。使用該flag的方式為:在docker run之后設定--net,如:

Docker run --net host ubuntu /bin/bash

用戶使用docker run啟動容器時設定了以上兩個flag參數(--networking和--net),則runconfig包會解析出這兩個flag的值。最終,通過flag參數flNetwork,得到Config類型實例config的屬性NetworkDisabled;通過flag參數flNetMode,得到HostConfig類型實例hostConfig的屬性NetworkMode。

函數parseRun返回config、hostConfig與cmd,代表著runconfig包解析配置參數工作的完成,CmdRun得到返回內容之后,繼續向下執行。

1.3 CmdRun執行

在runconfig包中已經將有關容器網絡模式的配置置于config對象與hostConfig對象,故在CmdRun函數的執行中,更多的是基于config對象與hostConfig參數處理配置信息,而沒有其他的容器網絡處理部分。

CmdRun后續主要工作是:利用Docker Daemon暴露的RESTful API接口,將docker run的請求發送至Docker Daemon。以下是CmdRun執行過程中Docker Client與Docker Daemon的簡易交互圖。

圖1.1 CmdRun中Docker Client與Docker Daemon交互圖

具體分析CmdRun的執行流程可以發現:在解析config、hostConfig與cmd之后,Docker Client首先發起請求create container。若Docker Daemon節點上已經存在該容器所需的鏡像,則立即執行create container操作并返回請求響應;Docker Client收到響應后,再發起請求start container。若容器鏡像還不存在,Docker Daemon返回一個404的錯誤,表示鏡像不存在;Docker Client收到錯誤響應之后,再發起一個請求pull image,使Docker Daemon首先下載鏡像,下載完畢之后Docker Client再次發起請求create container,Docker Daemon創建完畢之后,Docker Client最終發起請求start container。

總結而言,Docker Client負責創建容器請求的發起。關于Docker Container網絡環境的配置參數存儲于config與hostConfig對象之中,在請求create container和start container發起時,隨請求一起發送至Docker Daemon。

2.Docker Daemon創建容器網絡流程

Docker Daemon接收到Docker Client的請求大致可以分為兩次,第一次為create container,第二次為start container。這兩次請求的執行過程中,都與Docker Container的網絡相關。以下按照這兩個請求的執行,具體分析Docker Container網絡模式的創建。Docker Daemon如何通過Docker Server解析RESTful請求,并完成分發調度處理,在《Docker源碼分析》系列的第五篇——Docker Server篇中已經詳細分析過,本文不再贅述。

2.1創建容器并配置網絡參數

Docker Daemon首先接收并處理create container請求。需要注意的是:create container并非創建了一個運行的容器,而是完成了以下三個主要的工作:

  • 通過runconfig包解析出create container請求中與Docker Container息息相關的config對象;
  • 在Docker Daemon內部創建了與Docker Container對應的container對象;
  • 完成Docker Container啟動前的準備化工作,如準備所需鏡像、創建rootfs等。

創建容器過程中,Docker Daemon首先通過runconfig包中ContainerConfigFromJob函數,解析出請求中的config對象,解析過程代碼如下:

config := runconfig.ContainerConfigFromJob(job)

至此,Docker Client處理得到的config對象,已經傳遞至Docker Daemon的config對象,config對象中已經含有屬性NetworkDisabled具體值。

處理得到config對象之后,Docker Daemon緊接著創建container對象,并為Docker Container作相應的準備工作。具體的實現代碼位于./docker/daemon/create.go#L73-L78,如下:

if container, err = daemon.newContainer(name, config, img); err != nil {return nil, nil, err } if err := daemon.createRootfs(container, img); err != nil {return nil, nil, err }

與Docker Container網絡模式配置相關的內容主要位于創建container對象中。newContainer函數的定義位于./docker/daemon/daemon.go#L516-L550,具體的container對象如下:

container := &Container{ID: id,Created: time.Now().UTC(),Path: entrypoint,Args: args, //FIXME: de-duplicate from configConfig: config,hostConfig: &runconfig.HostConfig{},Image: img.ID, // Always use the resolved image idNetworkSettings: &NetworkSettings{},Name: name,Driver: daemon.driver.String(),ExecDriver: daemon.execDriver.Name(),State: NewState(), }

在container對象中,config對象直接賦值給container對象的Config屬性,另外hostConfig屬性與NetworkSeeetings屬性均為空。其中hostConfig對象將在start container請求執行過程中被賦值,NetworkSettings類型的作用是描述容器的網絡具體信息,定義位于./docker/daemon/network_settings.go#L11-L18,代碼如下:

type NetworkSettings struct {IPAddress stringIPPrefixLen intGateway stringBridge stringPortMapping map[string]PortMapping // DeprecatedPorts nat.PortMap }

Networksettings類型的各屬性的詳細解釋如下表:

?

NetworkSettings屬性名稱

類型

含義

IPAddress

string

IP網絡地址

IPPrefixLen

int

網絡標識位長度

Gateway

string

網關地址

Bridge

string

網橋地址

PortMapping

map[string]PortMapping

端口映射

Ports

nat.PortMap

端口號

總結而言,Docker Daemon關于create container請求的執行,先實現了容器配置信息從Docker Client至Docker Daemon的轉移,再完成了啟動容器前所需的準備工作。

2.2啟動容器之網絡配置

創建容器階段,Docker Daemon創建了容器對象container,container對象內部的Config屬性含有NetworkDisabled。創建容器完成之后,Docker Daemon還需要接收Docker Client的請求,并執行start container的操作,即啟動容器。

啟動容器過程中,Docker Daemon首先通過runconfig包中ContainerHostConfigFromJob函數,解析出請求中的hostConfig對象,解析過程代碼如下:

hostConfig := runconfig.ContainerHostConfigFromJob(job)

至此,Docker Client處理得到的hostConfig對象,已經傳遞至Docker Daemon的hostConfig對象,hostConfig對象中已經含有屬性NetworkMode具體值。

容器啟動的所有工作,均由以下的Start函數來完成,代碼位于./docker/daemon/start.go#L36-L38,如下:

if err := container.Start(); err != nil {return job.Errorf("Cannot start container %s: %s", name, err)}

Start函數實現了容器的啟動。更為具體的描述是:Start函數實現了進程的啟動,另外在啟動進程的同時為進程設定了命名空間(namespace),啟動完畢之后為進程完成了資源使用的控制,從而保證進程以及之后進程的子進程都會在同一個命名空間內,且受到相同的資源控制。如此一來,Start函數創建的進程,以及該進程的子進程,形成一個進程組,該進程組處于資源隔離和資源控制的環境,我們習慣將這樣的進程組環境稱為容器,也就是這里的Docker Container。

回到Start函數的執行,位于./docker/daemon/container.go#L275-L320。Start函數執行過程中,與Docker Container網絡模式相關的部分主要有三部分:

  • initializeNetwork(),初始化container對象中與網絡相關的屬性;
  • populateCommand,填充Docker Container內部需要執行的命令,Command中含有進程啟動命令,還含有容器環境的配置信息,也包括網絡配置;
  • container.waitForStart(),實現Docker Container內部進程的啟動,進程啟動之后,為進程創建網絡環境等。

2.2.1初始化容器網絡配置

容器對象container中有屬性hostConfig,屬性hostConfig中有屬性NetworkMode,初始化容器網絡配置initializeNetworking()的主要工作就是,通過NetworkMode屬性為Docker Container的網絡作相應的初始化配置工作。

Docker Container的網絡模式有四種,分別為:host、other container、none以及bridge。initializeNetworking函數的執行完全覆蓋了這四種模式。

initializeNetworking()函數的實現位于./docker/daemon/container.go#L881-L933。

2.2.1.1 初始化host網絡模式配置

Docker Container網絡的host模式意味著容器使用宿主機的網絡環境。雖然Docker Container使用宿主機的網絡環境,但這并不代表Docker Container可以擁有宿主機文件系統的視角,而host宿主機上有很多信息標識的是網絡信息,故Docker Daemon需要將這部分標識網絡的信息,從host宿主機添加到Docker Container內部的指定位置。這樣的網絡信息,主要有以下兩種:

  • host宿主機的主機名(hostname);
  • host宿主機上/etc/hosts文件,用于配置IP地址以及主機名。

其中,宿主機的主機名hostname用于創建container.Config中的Hostname與Domainname屬性。

另外,Docker Daemon在Docker Container的rootfs內部創建hostname文件,并在文件中寫入Hostname與Domainname;同時創建hosts文件,并寫入host宿主機上/etc/hosts內的所有內容。

2.2.1.2 初始化other container網絡模式配置

Docker Container的other container網絡模式意味著:容器使用其他已經創建容器的網絡環境。

Docker Daemon首先判斷host網絡模式之后,若不為host網絡模式,則繼續判斷Docker Container網絡模式是否為other container。如果Docker Container的網絡模式為other container(假設使用的-net參數為--net=container:17adef,其中17adef為容器ID)。Docker Daemon所做的執行操作包括兩部分。

第一步,從container對象的hostConfig屬性中找出NetworkMode,并找到相應的容器,即17adef的容器對象container,實現代碼如下:

nc, err := container.getNetworkedContainer()

第二步,將17adef容器對象的HostsPath、ResolveConfPath、Hostname和Domainname賦值給當前容器對象container,實現代碼如下:

container.HostsPath = nc.HostsPath container.ResolvConfPath = nc.ResolvConfPath container.Config.Hostname = nc.Config.Hostname container.Config.Domainname = nc.Config.Domainname
2.2.1.3 初始化none網絡模式配置

Docker Container的none網絡模式意味著不給該容器創建任何網絡環境,容器只能使用127.0.0.1的本機網絡。

Docker Daemon通過config屬性的DisableNetwork來判斷是否為none網絡模式。實現代碼如下:

if container.daemon.config.DisableNetwork {container.Config.NetworkDisabled = truereturn container.buildHostnameAndHostsFiles("127.0.1.1")}
2.2.1.4 初始化bridge網絡模式配置

Docker Container的bridge網絡模式意味著為容器創建橋接網絡模式。橋接模式使得Docker Container創建獨立的網絡環境,并通過“橋接”的方式實現Docker Container與外界的網絡通信。

初始化bridge網絡模式的配置,實現代碼如下:

if err := container.allocateNetwork(); err != nil {return err } return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress)

以上代碼完成的內容主要也是兩部分:第一,通過allocateNetwork函數為容器分配網絡接口設備需要的資源信息(包括IP、bridge、Gateway等),并賦值給container對象的NetworkSettings;第二,為容器創建hostname以及創建Hosts等文件。

2.2.2創建容器Command信息

Docker在實現容器時,使用了Command類型。Command在Docker Container概念中是一個非常重要的概念。幾乎可以認為Command是Docker Container生命周期的源頭。Command的概念會貫穿以后的《Docker源碼分析》系列,比如Docker Daemon與dockerinit的關系,dockerinit和entrypoint.sh的關系,entrypoint.sh與CMD的關系,以及namespace在這些內容中扮演的角色。

簡單來說,Command類型包含了兩部分的內容:第一,運行容器內進程的外部命令exec.Cmd;第二,運行容器時啟動進程需要的所有環境基礎信息:包括容器進程組的使用資源、網絡環境、使用設備、工作路徑等。通過這兩部分的內容,我們可以清楚,如何啟動容器內的進程,同時也清楚為容器創建什么樣的環境。

首先,我們先來看Command類型的定義,位于./docker/daemon/execdriver/driver.go#L84,通過分析Command類型以及其他相關的數據結構類型,可以得到以下簡要類型關系圖:

圖 2.1 Command類型關系圖

從Command類型關系圖中可以看到,Command類型中重新包裝了exec.Cmd類型,即代表需要創建的進程具體的外部命令;同時,關于網絡方面的屬性有Network,Network的類型為指向Network類型的指針;關于Docker Container資源使用方面的屬性為Resources,從Resource的類型來看,Docker目前能做的資源限制有4個維度,分別為內存,內存+Swap,CPU使用,CPU核使用;關于掛載的內容,有屬性Mounts;等等。

簡單介紹Command類型之后,回到Docker Daemon啟動容器網絡的源碼分析。在Start函數的執行流程中,緊接initializeNetworking()之后,與Docker Container網絡相關的是populateCommand環節。populateCommand的函數實現位于./docker/daemon/container.go#L191-L274。上文已經提及,populateCommand的作用是創建包execdriver的對象Command,該Command中既有啟動容器進程的外部命令,同時也有眾多為容器環境的配置信息,包括網絡。

本小節,更多的分析populateCommand如何填充Command對象中的網絡信息,其他信息的分析會在《源碼分析系列》的后續進行展開。

Docker總共有四種網絡模式,故populateCommand自然需要判斷容器屬于哪種網絡模式,隨后將具體的網絡模式信息,寫入Command對象的Network屬性中。查驗Docker Container網絡模式的代碼位于./docker/daemon/container.go#L204-L227,如下:

parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)switch parts[0] {case "none":case "host":en.HostNetworking = truecase "bridge", "": // empty string to support existing containersif !c.Config.NetworkDisabled {network := c.NetworkSettingsen.Interface = &execdriver.NetworkInterface{Gateway: network.Gateway,Bridge: network.Bridge,IPAddress: network.IPAddress,IPPrefixLen: network.IPPrefixLen,}}case "container":nc, err := c.getNetworkedContainer()if err != nil {return err}en.ContainerID = nc.IDdefault:return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)}

populateCommand首先通過hostConfig對象中的NetworkMode判斷容器屬于哪種網絡模式。該部分內容涉及到execdriver包中的Network類型,可參見Command類型關系圖中的Network類型。若為none模式,則對于Network對象(即en,*execdriver.Network)不做任何操作。若為host模式,則將Network對象的HostNetworking置為true;若為bridge橋接模式,則首先創建一個NetworkInterface對象,完善該對象的Gateway、Bridge、IPAddress和IPPrefixLen信息,最后將NetworkInterface對象作為Network對象的Interface屬性的值;若為other container模式,則首先通過getNetworkedContainer()函數獲知被分享網絡命名空間的容器,最后將容器ID,賦值給Network對象的ContainerID。由于bridge模式、host模式、none模式以及other container模式彼此互斥,故Network對象中Interface屬性、ContainerID屬性以及HostNetworking三者之中只有一個被賦值。當Docker Container的網絡查驗之后,populateCommand將en實例Network屬性的值,傳遞給Command對象。

至此,populateCommand關于網絡方面的信息已經完成配置,網絡配置信息已經成功賦值于Command的Network屬性。。

2.2.3啟動容器內部進程

當為容器做好所有的準備與配置之后,Docker Daemon需要真正意義上的啟動容器。根據Docker Daemon啟動容器流程涉及的Docker模塊中可以看到,這樣的請求,會被發送至execdriver,再經過libcontainer,最后實現真正啟動進程,創建完容器。

回到Docker Daemon的啟動容器,daemon包中start函數的最后一步即為執行container.waitForStart()。waitForStart函數的定義位于./docker/daemon/container.go#L1070-L1082,代碼如下:

func (container *Container) waitForStart() error {container.monitor = newContainerMonitor(container, container.hostConfig.RestartPolicy)select {case <-container.monitor.startSignal:case err := <-utils.Go(container.monitor.Start):return err}return nil }

以上代碼運行過程中首先通過newContainerMonitor返回一個初始化的containerMonitor對象,該對象中帶有容器進程的重啟策略(RestartPolicy)。這里簡單介紹containerMonitor對象??傮w而言,containerMonitor對象用以監視容器中第一個進程的執行。如果containerMonitor中指定了一種進程重啟策略,那么一旦容器內部進程沒有啟動成功,Docker Daemon會使用重啟策略來重啟容器。如果在重啟策略下,容器依然沒有成功啟動,那么containerMonitor對象會負責重置以及清除所有已經為容器準備好的資源,例如已經為容器分配好的網絡資源(即IP地址),還有為容器準備的rootfs等。

waitForStart()函數通過container.monitor.Start來實現容器的啟動,進入./docker/daemon/monitor.go#L100,可以發現啟動容器進程位于./docker/daemon/monitor.go#L136,代碼如下:

exitStatus, err = m.container.daemon.Run(m.container, pipes, m.callback)

以上代碼實際調用了daemon包中的Run函數,位于./docker/daemon/daemon.go#L969-L971,代碼如下:

func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {return daemon.execDriver.Run(c.command, pipes, startCallback) }

最終,Run函數中調用了execdriver中的Run函數來執行Docker Container的啟動命令。

至此,網絡部分在Docker Daemon內部的執行已經結束,緊接著程序運行邏輯陷入execdriver,進一步完成容器啟動的相關步驟。

3.execdriver網絡執行流程

Docker架構中execdriver的作用是啟動容器內部進程,最終啟動容器。目前,在Docker中execdriver作為執行驅動,可以有兩種選項:lxc與native。其中,lxc驅動會調用lxc工具實現容器的啟動,而native驅動會使用Docker官方發布的libcontainer來啟動容器。

Docker Daemon啟動過程中,execdriver的類型默認為native,故本文主要分析native驅動在執行啟動容器時,如何處理網絡部分。

在Docker Daemon啟動容器的最后一步,即調用了execdriver的Run函數來執行。通過分析Run函數的具體實現,關于Docker Container的網絡執行流程主要包括兩個環節:

(1) 創建libcontainer的Config對象

(2) 通過libcontainer中的namespaces包執行啟動容器

將execdriver.Run函數的運行流程具體展開,與Docker Container網絡相關的流程,可以得到以下示意圖:

圖3.1 execdriver.Run執行流程圖

3.1創建libcontainer的Config對象

Run函數位于./docker/daemon/execdriver/native/driver.go#L62-L168,進入Run函數的實現,立即可以發現該函數通過createContainer創建了一個container對象,代碼如下:

container, err := d.createContainer(c)

其中c為Docker Daemon創建的execdriver.Command類型實例。以上代碼的createContainer函數的作用是:使用execdriver.Command來填充libcontainer.Config。

libcontainer.Config的作用是,定義在一個容器化的環境中執行一個進程所需要的所有配置項。createContainer函數的存在,使用Docker Daemon層創建的execdriver.Command,創建更下層libcontainer所需要的Config對象。這個角度來看,execdriver更像是封裝了libcontainer對外的接口,實現了將Docker Daemon認識的容器啟動信息轉換為底層libcontainer能真正使用的容器啟動配置選項。libcontainer.Config類型與其內部對象的關聯圖如下:

圖3.2 libcontainer.Config類型關系圖

進入createContainer的源碼實現部分,位于./docker/daemon/execdriver/native/create.go#L23-L77,代碼如下:

func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {container := template.New()……if err := d.createNetwork(container, c); err != nil {return nil, err}……return container, nil }

3.1.1 libcontainer.Config模板實例

從createContainer函數的實現以及execdriver.Run執行流程圖中都可以看到,createContainer所做的第一個操作就是即為執行template.New(),意為創建一個libcontainer.Config的實例container。其中,template.New()的定義位于./docker/daemon/execdriver/native/template/default_template.go,主要的作用為返回libcontainer關于Docker Container的默認配置選項。

Template.New()的代碼實現如下:

func New() *libcontainer.Config {container := &libcontainer.Config{Capabilities: []string{"CHOWN","DAC_OVERRIDE","FSETID","FOWNER","MKNOD","NET_RAW","SETGID","SETUID","SETFCAP","SETPCAP","NET_BIND_SERVICE","SYS_CHROOT","KILL","AUDIT_WRITE",},Namespaces: map[string]bool{"NEWNS": true,"NEWUTS": true,"NEWIPC": true,"NEWPID": true,"NEWNET": true,},Cgroups: &cgroups.Cgroup{Parent: "docker",AllowAllDevices: false,},MountConfig: &libcontainer.MountConfig{},}if apparmor.IsEnabled() {container.AppArmorProfile = "docker-default"}return container }

關于該libcontainer.Config默認的模板對象,從源碼實現中可以看到,首先設定了Capabilities的默認項,如CHOWN、DAC_OVERRIDE、FSETID等;其次又將Docker Container所需要的設定的namespaces添加默認值,即需要創建5個NAMESPACE,如NEWNS、NEWUTS、NEWIPC、NEWPID和NEWNET,其中不包括user namespace,另外與網絡相關的namespace為NEWNET;最后設定了一些關于cgroup以及apparmor的默認配置。

Template.New()函數最后返回類型為libcontainer.Config的實例container,該實例中只含有默認配置項,其他的配置項的添加需要createContainer的后續操作來完成。

3.1.2 createNetwork實現

在createContainer的實現流程中,為了完成container對象(類型為libcontainer.Config)的完善,最后有很多步驟,如與網絡相關的createNetwork函數調用,與Linux內核Capabilities相關的setCapabilities函數調用,與cgroups相關的setupCgroups函數調用,以及與掛載目錄相關的setupMounts函數調用等。本小節主要分析createNetwork如何為container對象完善網絡配置項。

createNetwork函數的定義位于./docker/daemon/execdriver/native/create.go#L79-L124,該函數主要利用execdriver.Command中Network屬性中的內容,來判斷如何創建libcontainer.Config中Network屬性(關于兩中Network屬性,可以參見圖3.1和圖3.2)。由于Docker Container的4種網絡模式彼此互斥,故以上Network類型中Interface、ContainerID與HostNetworking最多只有一項會被賦值。

由于execdriver.Command中Network的類型定義如下:

type Network struct {Interface *NetworkInterfaceMtu int ContainerID string HostNetworking bool }

分析createNetwork函數,其具體實現可以歸納為4部分內容:

(1) 判斷網絡是否為host模式;

(2) 判斷是否為bridge橋接模式;

(3) 判斷是否為other container模式;

(4) 為Docker Container添加loopback網絡設備。

首先來看execdriver判斷是否為host模式的代碼:

if c.Network.HostNetworking {container.Namespaces["NEWNET"] = falsereturn nil }

當execdriver.Command類型實例中Network屬性的HostNetworking為true,則說明需要為Docker Container創建host網絡模式,使得容器與宿主機共享同樣的網絡命名空間。關于host模式的具體介紹中,已經闡明,只須在創建進程進行CLONE系統調用時,不傳入CLONE_NEWNET參數標志即可實現。這里的代碼正好準確的驗證了這一點,將container對象中NEWNET的Namespace設為false,最終在libcontainer中可以達到效果。

再看execdriver判斷是否為bridge橋接模式的代碼:

if c.Network.Interface != nil {vethNetwork := libcontainer.Network{Mtu: c.Network.Mtu,Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),Gateway: c.Network.Interface.Gateway,Type: "veth",Bridge: c.Network.Interface.Bridge,VethPrefix: "veth",}container.Networks = append(container.Networks, &vethNetwork)}

當execdriver.Command類型實例中Network屬性的Interface不為nil值,則說明需要為Docker Container創建bridge橋接模式,使得容器使用隔離的網絡環境。于是這里為類型為libcontainer.Config的container對象添加Networks屬性vethNetwork,網絡類型為“veth”,以便libcontainer在執行時,可以為Docker Container創建veth pair。

接著來看execdriver判斷是否為other container模式的代碼:

if c.Network.ContainerID != "" {d.Lock()active := d.activeContainers[c.Network.ContainerID]d.Unlock()if active == nil || active.cmd.Process == nil {return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)}cmd := active.cmdnspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")container.Networks = append(container.Networks, &libcontainer.Network{Type: "netns",NsPath: nspath,})}

當execdriver.Command類型實例中Network屬性的ContainerID不為空字符串時,則說明需要為Docker Container創建other container模式,使得創建容器使用其他容器的網絡環境。實現過程中,execdriver需要首先在activeContainers中查找需要被共享網絡環境的容器active;并通過active容器的啟動執行命令cmd找到容器第一進程在宿主機上的PID;隨后在proc文件系統中找到該進程PID的關于網絡namespace的路徑nspath;最后為類型為libcontainer.Config的container對象添加Networks屬性,Network的類型為“netns”。

此外,createNetwork函數還實現為Docker Container創建一個loopback回環設備,以便容器可以實現內部通信。實現過程中,同樣為類型libcontainer.Config的container對象添加Networks屬性,Network的類型為“loopback”,代碼如下:

container.Networks = []*libcontainer.Network{{Mtu: c.Network.Mtu,Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),Gateway: "localhost",Type: "loopback",},}

至此,createNetwork函數已經把與網絡相關的配置,全部創建在類型為libcontainer.Config的container對象中了,就等著啟動容器進程時使用。

3.2 調用libcontainer的namespaces啟動容器

回到execdriver.Run函數,創建完libcontainer.Config實例container,經過一系列其他方面的處理之后,最終execdriver執行namespaces.Exec函數實現啟動容器,container對象依然是namespace.Exec函數中一個非常重要的參數。這一環節代表著execdriver把啟動Docker Container的工作交給libcontainer,以后的執行陷入libcontainer。

調用namespaces.Exec的代碼位于./docker/daemon/execdriver/native/driver.go#L102-L127,為了便于理解,簡化的代碼如下:

namespaces.Exec(container, c.Stdin, c.Stdout, c.Stderr, c.Console,c.Rootfs, dataPath, args, parameter_1, parameter_2)

其中parameter_1為定義的函數,如下:

func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {c.Path = d.initPathc.Args = append([]string{DriverName,"-console", console,"-pipe", "3","-root", filepath.Join(d.root, c.ID),"--",}, args...)// set this to nil so that when we set the clone flags anything else is resetc.SysProcAttr = &syscall.SysProcAttr{Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),}c.ExtraFiles = []*os.File{child}c.Env = container.Envc.Dir = c.Rootfsreturn &c.Cmd}

同樣的,parameter_2也為定義的函數,如下:

func() {if startCallback != nil {c.ContainerPid = c.Process.PidstartCallback(c)}}

Parameter_1以及parameter_2這兩個函數均會在libcontainer的namespaces中發揮很大的重要。

至此,execdriver模塊的執行部分已經完結,Docker Daemon的程序運行邏輯陷入libcontainer。

4.libcontainer實現內核態網絡配置

libcontainer是一個Linux操作系統上容器的實現包。libcontainer指定了創建一個容器時所需要的配置選項,同時它利用Linux namespace和cgroup等技術為使用者提供了一套Golang原生態的容器實現方案,并且沒有使用任何外部依賴。用戶借助libcontainer,可以感受到眾多操縱namespaces,網絡等資源的便利。

當execdriver調用libcontainer中namespaces包的Exec函數時,libcontainer開始發揮其實現容器功能的作用。Exec函數位于./libcontainer/namespaces/exec.go#L24-L113。本文更多的關心Docker Container的網絡創建,因此從這個角度來看Exec的實現可以分為三個步驟:

(1) 通過createCommand創建一個Golang語言內的exec.Cmd對象;

(2) 啟動命令exec.Cmd,執行容器內第一個進程;

(3) 通過InitializeNetworking函數為容器進程初始化網絡環境。

以下詳細分析這三個部分,源碼的具體實現。

4.1創建exec.Cmd

提到exec.Cmd,就不得不提Go語言標準庫中的包os以及包os/exec。前者提供了與平臺無關的操作系統功能集,后者則提供了功能集里與命令執行相關的部分。

首先來看一下在Go語言中exec.Cmd的定義,如下:

type Cmd struct {Path string //所需執行命令在系統中的路徑Args []string //傳入命令的參數Env []string //進程運行時的環境變量Dir string //命令運行的工作目錄Stdin io.ReaderStdout io.WriterStderr io.WriterExtraFiles []*os.File //進程所需打開的文件描述符資源SysProcAttr *syscall.SysProcAttr //可選的操作系統屬性Process *os.Process //代表Cmd啟動后,操作系統底層的具體進程ProcessState *os.ProcessState //進程退出后保留的信息 }

清楚Cmd的定義之后,再來分析namespaces包的Exec函數中,是如何來創建exec.Cmd的。在Exec函數的實現過程中,使用了以下代碼實現Exec.Cmd的創建:

command := createCommand(container, console, rootfs, dataPath, os.Args[0], syncPipe.Child(), args)

其中createCommand為namespace.Exec函數中傳入的倒數第二個參數,類型為CreateCommand。而createCommand只是namespaces.Exec函數的形參,真正的實參則為execdriver調用namespaces.Exec時的參數parameter_1,即如下代碼:

func(container *libcontainer.Config, console, rootfs, dataPath,init string, child *os.File, args []string) *exec.Cmd {c.Path = d.initPathc.Args = append([]string{DriverName,"-console", console,"-pipe", "3","-root", filepath.Join(d.root, c.ID),"--",}, args...)// set this to nil so that when we set the clone flags anything else is resetc.SysProcAttr = &syscall.SysProcAttr{Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),}c.ExtraFiles = []*os.File{child}c.Env = container.Envc.Dir = c.Rootfsreturn &c.Cmd}

熟悉exec.Cmd的定義之后,分析以上代碼的實現就顯得較為簡單。為Cmd賦值的對象有Path,Args,SysProcAttr,ExtraFiles,Env和Dir。其中需要特別注意的是Path的值d.initPath,該路徑下存放的是dockerinit的二進制文件,Docker 1.2.0版本下,路徑一般為“/var/lib/docker/init/dockerinit-1.2.0”。另外SysProcAttr使用以下的代碼來賦值:

&syscall.SysProcAttr{Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),}

syscall.SysProAttr對象中的Cloneflags屬性中,即保留了libcontainer.Config類型的實例container中的Namespace屬性。換言之,通過exec.Cmd創建進程時,正是通過Cloneflags實現Clone系統調用中傳入namespace參數標志。

回到函數執行中,在函數的最后返回了c.Cmd,命令創建完畢。

4.2啟動exec.Cmd創建進程

創建完exec.Cmd,當然需要將該執行命令運行起來,namespaces.Exec函數中直接使用以下代碼實現進程的啟動:

if err := command.Start(); err != nil {return -1, err}

這一部分的內容簡單直接, Start()函數用以完成指定命令exec.Cmd的啟動執行,同時并不等待其啟動完畢便返回。Start()函數的定義位于os/exec包。

進入os/exec包,查看Start()函數的實現,可以看到執行過程中,會對command.Process進行賦值,此時command.Process中會含有剛才啟動進程的PID進程號,該PID號屬于在宿主機pid namespace下,而并非是新創建namespace下的PID號。

4.3為容器進程初始化網絡環境

上一環節實現了容器進程的啟動,然而卻還沒有為之配置相應的網絡環境。namespaces.Exec在之后的InitializeNetworing中實現了為容器進程初始化網絡環境。初始化網絡環境需要兩個非常重要的參數:container對象以及容器進程的Pid號。類型為libcontainer.Config的實例container中包含用戶對Docker Container的網絡配置需求,另外容器進程的Pid可以使得創建的網絡環境與進程新創建的namespace進行關聯。

namespaces.Exec中為容器進程初始化網絡環境的代碼實現位于./libcontainer/namespaces/exec.go#L75-L79,如下:

if err := InitializeNetworking(container, command.Process.Pid, syncPipe, &networkState); err != nil {command.Process.Kill()command.Wait()return -1, err}

InitializeNetworing的作用很明顯,即為創建的容器進程初始化網絡環境。更為底層的實現包含兩個步驟:

(1) 先在容器進程的namespace外部,創建容器所需的網絡棧;

(2) 將創建的網絡棧遷移進入容器的net namespace。

IntializeNetworking的源代碼實現位于./libcontainer/namespaces/exec.go#L176-L187,如下:

func InitializeNetworking(container *libcontainer.Config, nspid int, pipe *syncpipe.SyncPipe, networkState *network.NetworkState) error {for _, config := range container.Networks {strategy, err := network.GetStrategy(config.Type)if err != nil {return err}if err := strategy.Create((*network.Network)(config), nspid, networkState); err != nil {return err}}return pipe.SendToChild(networkState) }

以上源碼實現過程中,首先通過一個循環,遍歷libcontainer.Config類型實例container中的網絡屬性Networks;隨后使用GetStrategy函數處理Networks中每一個對象的Type屬性,得出Network的類型,這里的類型有3種,分別為“loopback”、“veth”、“netns”。除host網絡模式之外,loopback對于其他每一種網絡模式的Docker Container都需要使用;veth針對bridge橋接模式,而netns針對other container模式。

得到Network類型的類型之后,libcontainer創建相應的網絡棧,具體實現使用每種網絡棧類型下的Create函數。以下分析三種不同網絡棧各自的創建流程。

4.3.1 loopback網絡棧的創建

Loopback是一種本地環回設備,libcontainer創建loopback網絡設備的實現代碼位于./libcontainer/network/loopback.go#L13-L15,如下:

func (l *Loopback) Create(n *Network, nspid int, networkState *NetworkState) error {return nil }

令人費解的是,libcontainer在loopback設備的創建函數Create中,并沒有作實質性的內容,而是直接返回nil。

其實關于loopback設備的創建,要回到Linux內核為進程新建namespace的階段。當libcontainer執行command.Start()時,由于創建了一個新的網絡namespace,故Linux內核會自動為新的net namespace創建loopback設備。當Linux內核創建完loopback設備之后,libcontainer所做的工作即只要保留loopback設備的默認配置,并在Initialize函數中實現啟動該設備。

4.3.2 veth網絡棧的創建

Veth是Docker Container實際使用的網絡策略之一,其使用網橋docker0并創建veth pair虛擬網絡設備對,最終使一個veth配置在宿主機上,而另一個veth安置在容器網絡namespace內部。

libcontainer中實現veth策略的代碼非常通俗易懂,代碼位于./libcontainer/network/veth.go#L19-L50,如下:

name1, name2, err := createVethPair(prefix)if err != nil {return err}if err := SetInterfaceMaster(name1, bridge); err != nil {return err}if err := SetMtu(name1, n.Mtu); err != nil {return err}if err := InterfaceUp(name1); err != nil {return err}if err := SetInterfaceInNamespacePid(name2, nspid); err != nil {return err}

主要的流程包含的四個步驟:

(1) 在宿主機上創建veth pair;

(2) 將一個veth附加至docker0網橋上;

(3) 啟動第一個veth;

(4) 將第二個veth附加至libcontainer創建進程的namespace下。

使用Create函數實現veth pair的創建之后,在Initialize函數中實現將網絡namespace中的veth改名為“eth0”,并設置網絡設備的MTU等。

4.3.3 netns網絡棧的創建

netns專門為Docker Container的other container網絡模式服務。netns完成的工作是將其他容器的namespace路徑傳遞給需要創建other container網絡模式的容器使用。

libcontainer中實現netns策略的代碼位于./libcontainer/network/netns.go#L17-L20,如下:

func (v *NetNS) Create(n *Network, nspid int, networkState *NetworkState) error {networkState.NsPath = n.NsPathreturn nil }

使用Create函數先將NsPath賦給新建容器之后,在Initialize函數中實現將網絡namespace的文件描述符交由新創建容器使用,最終實現兩個Docker Container共享同一個網絡棧。

通過Create以及Initialize的實現之后,Docker Container相應的網絡棧環境即已經完成創建,容器內部的應用進程可以使用不同的網絡棧環境與外界或者內部進行通信。關于Initialize函數何時被調用,需要清楚Docker Daemon與dockerinit的關系,以及如何實現Docker Daemon進程與dockerinit進程跨namespace進行通信,這部分內容會在《Docker源碼分析》系列后續專文分析。

5.總結

如何使用Docker Container的網絡,一直是工業界倍加關心的問題。本文將從Linux內核原理的角度闡述了什么是Docker Container,并對Docker Container 4種不同的網絡模式進行了初步的介紹,最終貫穿Docker 架構中的多個模塊,如Docker Client、Docker Daemon、execdriver以及libcontainer,深入分析Docker Container網絡的實現步驟。

目前,若只談論Docker,那么它還是只停留在單host宿主機的場景上。如何面對跨host的場景、如何實現分布式Docker Container的管理,目前為止還沒有一個一勞永逸的解決方案。再者,一個解決方案的存在,總是會適應于一個應用場景。Docker這種容器技術的發展,大大改善了傳統模式下使用諸如虛擬機等傳統計算單位存在的多數弊端,卻在網絡方面使得自身的使用過程中存在瑕疵。希望本文是一個引子,介紹Docker Container網絡,以及從源碼的角度分析Docker Container網絡之后,能有更多的愛好者思考Docker Container網絡的前世今生,并為Docker乃至容器技術的發展做出貢獻。

6.作者介紹

孫宏亮,DaoCloud初創團隊成員,軟件工程師,浙江大學VLIS實驗室應屆研究生。讀研期間活躍在PaaS和Docker開源社區,對Cloud Foundry有深入研究和豐富實踐,擅長底層平臺代碼分析,對分布式平臺的架構有一定經驗,撰寫了大量有深度的技術博客。2014年末以合伙人身份加入DaoCloud團隊,致力于傳播以Docker為主的容器的技術,推動互聯網應用的容器化步伐。郵箱:allen.sun@daocloud.io

7.參考文獻

http://docs.studygolang.com/pkg/os/exec/#Cmd

https://github.com/docker/libcontainer/tree/v1.2.0

https://github.com/docker/libcontainer/issues/323

轉載于:https://www.cnblogs.com/davidwang456/articles/9602958.html

總結

以上是生活随笔為你收集整理的Docker源码分析(八):Docker Container网络(下)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

亚洲视频在线播放 | 久久久影院官网 | 97电院网手机版 | 欧美视频在线观看免费网址 | 天天搞天天干 | 久久艹精品| 免费视频91 | 久久久午夜精品福利内容 | 久久久久久久久久久久国产精品 | 亚洲在线网址 | 四虎永久免费网站 | 不卡av电影在线观看 | 91免费在线看片 | 狠狠操狠狠干天天操 | 中文字幕在线视频一区二区 | 精品伊人久久久 | 亚洲精品视频免费在线观看 | 成人免费视频网 | 日本中出在线观看 | 91精品秘密在线观看 | 国产日韩在线视频 | 久久精品国产99国产 | 久久在线免费观看视频 | 国产成人精品福利 | 骄小bbw搡bbbb揉bbbb | 天天操天天操天天操天天操天天操 | a在线观看免费视频 | 色香蕉在线 | 久久久精品国产一区二区电影四季 | 国产视频在线播放 | 一级α片免费看 | 91亚洲精品乱码久久久久久蜜桃 | 婷婷久久综合九色综合 | 在线免费观看黄色 | 九九九电影免费看 | 亚洲国产999 | 色网站免费在线观看 | 最新国产精品拍自在线播放 | 综合色在线 | 国产精品福利午夜在线观看 | 美女视频是黄的免费观看 | www.人人草 | 少妇bbw搡bbbb搡bbb | 91免费在线看片 | 中文字幕 在线 一 二 | 免费网站看v片在线a | 国产亚洲精品久久久久5区 成人h电影在线观看 | 韩国在线一区二区 | 91av电影 | 国产一区二区播放 | 免费视频你懂的 | 免费观看性生交大片3 | 福利片免费看 | 久久久久看片 | 在线小视频国产 | 91| 97超碰人人在线 | 精品一区 在线 | 国产精品毛片久久久久久久 | 亚洲欧美日韩一区二区三区在线观看 | 五月天天天操 | 97网站| 日韩视频 一区 | 亚洲视频,欧洲视频 | 中文字幕亚洲精品在线观看 | 国产xxxx| 国产精品69av| 在线一区电影 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 国产高清久久久久 | 免费在线观看a v | 亚洲一级免费观看 | 国产麻豆果冻传媒在线观看 | 久久久久观看 | 亚洲最新av在线 | 国产精品欧美日韩在线观看 | 国产香蕉在线 | 国产精品第 | 黄色国产高清 | 狠狠干狠狠操 | 国产日韩精品一区二区 | 欧美一级日韩三级 | 国产探花在线看 | 久草久草久草久草 | 97在线视频免费观看 | 欧美国产日韩一区二区三区 | 综合在线观看 | 日韩电影一区二区在线观看 | 狠狠综合久久av | 人人插超碰 | 欧美日韩精品国产 | 亚洲黄色一级电影 | 国产精品嫩草影院99网站 | 国产日韩欧美精品在线观看 | 亚洲三级影院 | 免费福利片2019潦草影视午夜 | 久久精品免视看 | 最近高清中文字幕在线国语5 | 在线免费黄色 | 国产在线 一区二区三区 | 久久精品官网 | 91桃色在线观看视频 | 免费高清无人区完整版 | 久久久亚洲麻豆日韩精品一区三区 | 丁香婷婷综合网 | 特级西西www44高清大胆图片 | av在线播放国产 | 亚洲天堂精品视频在线观看 | 国产一在线精品一区在线观看 | 91看片麻豆 | 久久五月婷婷丁香社区 | 探花视频在线观看免费 | 中文字幕av免费在线观看 | 81精品国产乱码久久久久久 | 91免费看片黄 | 99在线视频精品 | 久久久午夜视频 | av大片免费看 | 99精品系列 | 五月婷久久| 久久色网站 | 四虎影视8848dvd | 成人一级黄色片 | 亚洲日本va在线观看 | 综合五月婷婷 | 久热色超碰 | 天堂成人在线 | 97超碰网 | aaa毛片视频 | 九九热视频在线 | 2024av| 免费看片成年人 | 9999免费视频 | 欧美色婷婷 | 日韩欧美高清视频在线观看 | 天天射天天爱天天干 | 成人在线免费看 | 国产综合小视频 | 日韩免费av在线 | 国产成人一区二区啪在线观看 | 午夜精品剧场 | 国产在线播放一区二区 | 婷婷亚洲最大 | 99精品视频在线观看视频 | 国内精品二区 | 久久99亚洲网美利坚合众国 | 亚洲精品视频一二三 | 国产韩国精品一区二区三区 | 久操视频在线免费看 | 99热在线国产精品 | 久久久91精品国产一区二区三区 | 久久综合久久久久88 | 99精品国产高清在线观看 | 亚洲黄色一级大片 | 亚洲三级在线免费观看 | 久久久久久久网 | 国产一级片免费视频 | 久久久久久久久福利 | 五月天综合婷婷 | 国产大尺度视频 | 婷婷黄色片 | 一区二区三区不卡在线 | 黄色大片免费播放 | 中文字幕乱码电影 | 久久精品电影网 | 激情久久网 | 国产一区欧美二区 | 2018亚洲男人天堂 | 91亚洲精品久久久蜜桃借种 | 久久久久亚洲国产 | 91热在线 | 亚洲成人av免费 | 亚洲精品综合一二三区在线观看 | 久久美女高清视频 | 欧美一级视频一区 | 日韩精品视频一二三 | 国产精品1区2区在线观看 | 天天视频色| 日韩免费二区 | 久久精品国产免费看久久精品 | 亚洲精品美女在线观看 | 久久久69 | 超碰av在线免费观看 | 亚洲无在线| 最新的av网站 | 超碰精品在线 | 成人午夜电影在线观看 | 日日干av | 操操日日 | av在线专区 | 亚洲精品欧美专区 | 摸bbb搡bbb搡bbbb| 狠狠色伊人亚洲综合网站色 | 99久久精品国产一区二区成人 | 在线亚洲免费视频 | 国产成人av | 日韩在线播放av | 欧美激情视频一区二区三区 | 九九热国产 | 天天色天 | 97超碰人人澡 | 丁五月婷婷| 久久久久久久久久福利 | 国产精品久久久久久五月尺 | 欧美色操 | 婷婷在线免费观看 | 日韩视频a | 国产一区精品在线观看 | 国产精品6| 丁香六月欧美 | 久久人人爽人人 | 日韩免费电影 | 久久天天躁 | 久久久久这里只有精品 | 99热99| 欧美日韩中文国产一区发布 | 91视频在线观看下载 | 国产二区av | 深爱激情五月婷婷 | 欧美日韩在线观看视频 | 亚洲区精品视频 | 在线黄色免费av | 三上悠亚一区二区在线观看 | 精品免费一区 | 天天做天天爱天天爽综合网 | 一级一片免费视频 | 国产成人专区 | 欧美最猛性xxxxx免费 | 日本高清久久久 | 视频99爱 | 欧美福利久久 | 日韩天堂在线观看 | 国产专区在线看 | 欧美午夜精品久久久久久孕妇 | 91人人人 | 国产精品爽爽爽 | 国产一区二区三区久久久 | 91av国产视频 | 黄色三级在线看 | 久av电影| 国产一区网址 | 91免费视频网站在线观看 | 欧洲色综合 | 亚洲视频 中文字幕 | 综合天天久久 | 97视频久久久| 色亚洲网| 国产高清在线观看av | 五月天伊人 | 久久永久免费 | 500部大龄熟乱视频 欧美日本三级 | 狠狠88综合久久久久综合网 | 在线免费高清一区二区三区 | 国产一区福利在线 | 国产成人av一区二区三区在线观看 | 天天操夜夜爱 | 黄色一级大片在线免费看国产一 | 天天干.com| 免费高清看电视网站 | 久久免费精品国产 | 久久一视频 | 丰满少妇一级片 | 成人av高清在线观看 | 天天爽天天搞 | 久久久久久久久影院 | 国产区高清在线 | 在线免费精品视频 | 99久久er热在这里只有精品15 | 欧美a级免费视频 | 久久艹艹| 免费高清国产 | 国产一级黄大片 | 国产精品1区2区 | 日韩三级视频 | 狠狠色丁香婷综合久久 | 黄色午夜网站 | 久久国产精品视频观看 | 中文字幕91 | 色吊丝在线永久观看最新版本 | 91成人国产 | 少妇bbb | 久草在线精品观看 | 97碰碰视频 | 亚洲精品在线免费看 | 日本大片免费观看在线 | 免费日韩在线 | 久久久久97国产 | 亚洲欧美日韩一区二区三区在线观看 | 中文字幕欧美日韩va免费视频 | 新版资源中文在线观看 | 91污污视频在线观看 | 99热只有精品在线观看 | 手机在线永久免费观看av片 | 91av视频观看 | 91欧美视频网站 | 91精品啪在线观看国产81旧版 | 碰超在线97人人 | 久久久久国产免费免费 | 成人国产精品久久久久久亚洲 | 久久综合射 | 在线免费av网站 | 午夜国产影院 | 成人网色 | 在线免费高清 | 久久国产精品99久久久久 | 视频一区二区在线 | 亚洲性xxxx | 亚洲国产日韩欧美在线 | 在线观看深夜视频 | 久久手机免费视频 | 91视频在线播放视频 | 日本精品视频在线观看 | 天天干天天干天天操 | 六月丁香激情综合 | 婷婷色中文网 | 伊人久久在线观看 | 精品久久国产一区 | 五月婷婷开心 | 免费在线观看日韩欧美 | 亚洲精品国产品国语在线 | 四虎影视成人精品国库在线观看 | 成人av一二三区 | 又黄又爽又色无遮挡免费 | 不卡的av在线播放 | 国产黄色片在线免费观看 | 国产日产精品一区二区三区四区 | 精品女同一区二区三区在线观看 | 亚洲视频 视频在线 | 人人爽人人香蕉 | 91麻豆精品国产自产在线游戏 | 国产日韩精品一区二区在线观看播放 | 国产无套精品久久久久久 | 久久久久网址 | 久草视频手机在线 | 天天操天天草 | 色婷婷欧美 | 玖操| 午夜国产影院 | 日日干影院 | 一区 在线观看 | 人人爽人人舔 | 日韩高清免费在线观看 | 五月婷影院 | 亚洲精品免费看 | 国产精品自在线 | 午夜精品久久久 | 国内视频1区| 欧美日韩免费观看一区=区三区 | 亚洲国产精品va在线看黑人动漫 | 亚洲精品国产精品国自 | 午夜av影院 | 免费看色视频 | 中文字幕在线观看你懂的 | 午夜精品久久久久久久99无限制 | 亚洲精品成人网 | 99精品美女| 最新中文在线视频 | 国产精品白丝av | 国产美女精品视频 | 在线观看免费版高清版 | 久久综合中文色婷婷 | 成年人在线观看视频免费 | 91入口在线观看 | 国产亚洲精品v | 国产粉嫩在线 | 免费看搞黄视频网站 | 特级西西人体444是什么意思 | 午夜精品久久久久久久久久久久 | 亚州人成在线播放 | 韩国中文三级 | 中文亚洲欧美日韩 | 国产精品中文久久久久久久 | 99中文在线| 黄色免费网战 | 友田真希x88av | 成人在线视频免费看 | 日韩免费三级 | 免费观看第二部31集 | 国产精品99久久久久久有的能看 | 亚洲欧洲av | 国产午夜精品一区二区三区嫩草 | 2021av在线| 色九九影院 | 91精品在线观看入口 | 亚州欧美精品 | 亚洲在线日韩 | 国产美女视频免费观看的网站 | 久久dvd| 九九热久久免费视频 | 日韩伦理片hd | 久99精品 | 色91av | 免费在线观看成人小视频 | 亚洲久久视频 | 97超视频| 亚洲国产精品视频在线观看 | 在线免费黄网站 | 久久婷婷丁香 | 日韩免费播放 | 99se视频在线观看 | 日韩综合视频在线观看 | 麻豆成人小视频 | 在线观看激情av | 久久久久99精品成人片三人毛片 | 日韩欧美有码在线 | 国产黄影院色大全免费 | 中文字幕在线播放日韩 | 在线观看视频在线观看 | 中文字幕乱偷在线 | 日韩av资源站 | av网站地址 | 国产伦理久久精品久久久久_ | 三级黄色网址 | 天天拍天天操 | 亚洲午夜av久久乱码 | 国产福利资源 | 成人a在线 | 亚洲激情p | 麻豆影视网 | 欧美少妇18p | 国产99一区 | 亚洲四虎影院 | 国产精品免费观看在线 | 日韩二区在线 | 麻豆影视在线播放 | 亚洲va欧洲va国产va不卡 | 日韩a级黄色片 | 97精品伊人 | 国内精品久久久 | 国产视频一 | 天天操天天色综合 | 在线免费视频 你懂得 | 国产在线国偷精品产拍 | 色综合亚洲精品激情狠狠 | 少妇视频一区 | 国产黄网在线 | www.激情五月.com | 91av在线精品 | 成人小视频在线观看免费 | 五月天久久狠狠 | 国产99自拍 | 天天干天天做天天操 | 中文字幕 二区 | 黄色在线观看网站 | 99久久日韩精品视频免费在线观看 | 国产精品久一 | 九九电影在线 | 激情av在线资源 | 亚洲观看黄色网 | av亚洲产国偷v产偷v自拍小说 | 99精品网站 | 不卡的av在线播放 | 国产伦精品一区二区三区无广告 | 超碰免费久久 | 亚洲乱码国产乱码精品天美传媒 | 亚洲黄色小说网址 | 伊人夜夜| 国产呻吟在线 | 日日爱影视| 国产福利在线免费 | 国语对白少妇爽91 | 三级大片网站 | 国产99久久久久久免费看 | 国产一区二三区好的 | 久久国产精品免费观看 | 国产一级做a爱片久久毛片a | 日韩欧美视频一区 | 亚洲精品免费在线视频 | 五月婷婷在线播放 | 五月天最新网址 | 992tv成人免费看片 | 国产日产欧美在线观看 | 伊人电影在线观看 | 91视频黄色 | 天天天干天天天操 | 日韩黄色影院 | zzijzzij亚洲日本少妇熟睡 | 国产精品视频资源 | 国内精品久久久 | 国产成人亚洲在线观看 | 精品国产网址 | 在线看成人 | 免费观看性生活大片 | 国产免费区 | 国产精品一二 | 麻豆视频免费 | 91久久久国产精品 | 国产精品久久久久久久av大片 | 日韩最新在线 | www免费视频com━ | 亚洲黄色片| 激情五月激情综合网 | 制服丝袜一区二区 | 亚洲区精品 | 97福利在线观看 | 亚洲不卡av一区二区三区 | 一区二区丝袜 | 欧美 日韩 性 | 天天爱综合 | 免费a视频在线观看 | 色婷婷综合久久久中文字幕 | 国产性xxxx| 91尤物国产尤物福利在线播放 | 在线综合色 | 麻豆91视频 | 九九久久影视 | 亚洲黄色网络 | 91免费的视频在线播放 | 国产亚洲精品久久久久久网站 | 亚洲成人欧美 | 日韩一区二区三区高清在线观看 | 久久精品3 | 国产精品九九九九九 | 日韩精品视频免费看 | 欧美激情一区不卡 | 五月婷婷综合在线视频 | 美女视频黄在线观看 | 天天操天天干天天综合网 | 亚洲精品一区二区在线观看 | 久久久久久久久久电影 | 国产一区二区三区免费观看视频 | 精品久久中文 | 久久久久久久久久久影视 | 久久亚洲专区 | 精品国产一区二区三区免费 | 久久免费精品一区二区三区 | 国产欧美精品在线观看 | 88av网站 | 超碰在97 | 伊人春色电影网 | 免费观看一级一片 | 中文字幕一区二 | 国产区免费在线 | 久草a在线 | 在线观看成人国产 | 中文字幕色在线 | 狠狠躁18三区二区一区ai明星 | 麻豆av一区二区三区在线观看 | 久久精品高清 | 91在线小视频 | 九九精品毛片 | 97在线看片| 少妇bbw搡bbbb搡bbbb | 日本久久99 | 欧美在线观看视频一区二区三区 | 色视频在线观看免费 | 国产最新视频在线观看 | 黄色网免费 | 欧美国产高清 | 一本一道久久a久久精品蜜桃 | 1000部18岁以下禁看视频 | 国产一级视屏 | 91精品久久久久久粉嫩 | 日韩大片在线免费观看 | 麻豆久久久 | 欧美性色网站 | 日日干美女| 久色 网 | 成全在线视频免费观看 | 日韩欧美一区视频 | 亚洲日韩欧美一区二区在线 | 超碰97av在线 | 国产综合在线观看视频 | 国产视频综合在线 | 久久99久久精品国产 | 久色 网 | 国产在线观看网站 | 草久在线观看 | 亚洲精品国产第一综合99久久 | 人人澡视频| 久草在线资源免费 | 国产精品国产毛片 | 日韩在线免费视频观看 | 中文字幕在线看视频国产 | 亚洲激情视频在线 | 日韩在线视频国产 | 亚洲国产精品成人综合 | 一区精品在线 | 天天久久综合 | 99999精品视频 | 国产视频1区2区3区 久久夜视频 | 97夜夜澡人人爽人人免费 | 久久精品香蕉视频 | 免费日韩三级 | 日韩在线观看第一页 | 91精品免费在线 | 伊色综合久久之综合久久 | 青青草在久久免费久久免费 | 欧洲精品视频一区二区 | 午夜精品久久久久久久99热影院 | www.狠狠插.com | 81精品国产乱码久久久久久 | 欧美极品少妇xbxb性爽爽视频 | 亚洲在线a | 日本一区二区高清不卡 | 精品久久久久久亚洲 | 精品亚洲欧美无人区乱码 | 91视频久久久久久 | 在线观看精品视频 | 99精品视频在线观看 | 色97在线 | 国产日产精品一区二区三区四区 | 99免费在线观看视频 | 久久影视一区 | 亚洲综合狠狠干 | 色综合久久88色综合天天 | 韩日色视频| av电影在线观看完整版一区二区 | 91天堂影院| 91久草视频 | 久久国产精品99国产 | 久久久久久欧美二区电影网 | 探花视频在线观看 | 日韩欧美国产视频 | 久久精品国产一区二区电影 | 91亚色视频在线观看 | 久久精品爱爱视频 | 色91在线视频| 欧美一区二区三区四区夜夜大片 | 五月婷婷一区二区三区 | 亚洲天天| 国产亚洲精品日韩在线tv黄 | 亚洲欧美国产日韩在线观看 | 久久电影日韩 | 在线播放第一页 | 午夜精品视频一区二区三区在线看 | 久久一区国产 | 五月天久久综合 | 99视频一区 | 成人av高清在线 | 亚洲视频在线观看 | 天天操夜夜操天天射 | 又爽又黄在线观看 | 一区二区三区四区在线免费观看 | 欧美日韩国产一二 | 国产亚洲精品福利 | 激情综合网色播五月 | 色婷婷综合久色 | 日韩成人xxxx | 国产在线观看高清视频 | 日韩一区二区三区不卡 | 亚洲精品国产精品国自产观看浪潮 | 国产一区二区在线播放视频 | 狠狠干激情 | 日本xxxxav| 伊人五月天 | h文在线观看免费 | av综合 日韩 | 中文字幕免费播放 | 国产精品99久久久久久人免费 | 成人禁用看黄a在线 | 日韩欧美高清视频在线观看 | 中文字幕日韩在线播放 | 免费的成人av | 久久精品1区 | a特级毛片 | 色婷婷欧美 | 国产小视频在线观看免费 | 欧美日比视频 | 黄色小网站在线观看 | av丝袜在线 | 国产免费人成xvideos视频 | 黄色h在线观看 | 国产日韩欧美中文 | 国产成人av福利 | 精品免费久久久久久 | 一级国产视频 | 国产 视频 久久 | 中文字幕丝袜美腿 | 成人黄色在线视频 | 去看片| 日韩在线观看高清 | 在线观看黄色大片 | 久久精品欧美一 | 久久久久久黄色 | 国产小视频在线看 | 久久精品欧美一 | 激情综合网天天干 | 免费男女网站 | 久久久久久国产精品999 | 欧美激情另类 | 国产福利中文字幕 | 久久久久欠精品国产毛片国产毛生 | 狠狠躁日日躁狂躁夜夜躁av | 美女搞黄国产视频网站 | 中文超碰字幕 | 色99中文字幕 | 亚洲精品国产精品国自产在线 | 天天要夜夜操 | 成人精品一区二区三区中文字幕 | 国产精国产精品 | 色的网站在线观看 | 中文字幕一区二区三区乱码在线 | 91传媒视频在线观看 | 伊人黄色网 | 六月色丁 | 国产高清综合 | 国产精品18久久久久久久 | 9幺看片| 国产成人一区二区三区在线观看 | 在线小视频 | 天天摸天天干天天操天天射 | 国产精品久久久免费 | 国产中文字幕在线播放 | 久久伊人色综合 | 日韩精品资源 | 一区二区三区国产欧美 | 亚洲.www| 久久久精品网站 | 亚洲国产日韩在线 | 国产经典av | 国产成人a亚洲精品 | 精品国内自产拍在线观看视频 | 国产玖玖视频 | 一区二区三区免费看 | 伊人久久av | 精品福利在线视频 | 午夜精品在线看 | 国产精品久久久久久久久久免费 | 香蕉视频国产在线观看 | 免费国产ww| 91精选在线 | 狠狠狠色丁香综合久久天下网 | 在线视频观看成人 | 久久经典国产视频 | 亚洲欧美日本一区二区三区 | 国产欧美日韩一区 | 日本xxxxav| 欧美激情视频在线免费观看 | 亚州精品天堂中文字幕 | 在线免费视频 你懂得 | 国产精品免费在线播放 | 成人免费网站在线观看 | 日韩高清精品一区二区 | 亚洲精品国精品久久99热 | 9999国产| 精品在线视频一区二区三区 | 日韩中文字幕免费 | 天天操夜夜操夜夜操 | 五月天六月婷婷 | 丁香在线观看完整电影视频 | www久久九| 日韩色av色资源 | 精品v亚洲v欧美v高清v | 91亚洲精品久久久蜜桃网站 | 亚洲精品视频在线观看免费视频 | 狠狠操天天干 | www.久久久.com | 中文字幕成人av | 狠狠色丁香久久婷婷综合_中 | 午夜婷婷网 | 亚洲日本韩国一区二区 | 国产精品18久久久久vr手机版特色 | 91九色porny蝌蚪主页 | av电影一区二区三区 | 日韩在线网址 | 免费在线黄网 | 国产小视频91 | 丁香久久久 | 最新国产精品拍自在线播放 | 亚洲精品视频免费在线 | 在线国产福利 | 男女视频久久久 | 久久国产精品久久w女人spa | 中文在线最新版天堂 | 一区二区视频欧美 | 制服丝袜成人在线 | 97精品国产97久久久久久久久久久久 | 天天草天天干天天 | 久久久精选 | 欧美精品一区二区性色 | 亚洲精品97| 国产黄大片 | 五月婷在线观看 | 在线导航av | 久久尤物电影视频在线观看 | 91一区二区三区在线观看 | 337p西西人体大胆瓣开下部 | 丝袜足交在线 | 国产精品久久婷婷六月丁香 | 国产一区二区三区网站 | 精品久久免费 | 最新免费中文字幕 | 中文字幕在线免费97 | 操高跟美女 | 亚州av网站| 亚洲极色 | 天天爱天天色 | 久久久久久综合网天天 | 西西44人体做爰大胆视频 | 国产精品嫩草55av | 国产精品都在这里 | 午夜视频在线观看一区二区三区 | 久久中文欧美 | 欧美另类高清 | 亚洲第一区在线观看 | 成人免费观看电影 | 天天草天天草 | 日日草av | 96精品视频 | 久久精品超碰 | 国产精品一区二区在线看 | 国产69久久久欧美一级 | 久久国产精品第一页 | 国产精品久久久久永久免费 | 91精品国产福利在线观看 | 天天色天天射天天操 | 国产一区免费在线 | 午夜精品一区二区三区免费视频 | 天天草综合网 | 好看的国产精品视频 | 黄色免费看片网站 | 久久久久区 | 亚洲日本三级 | 国产在线精品播放 | 久久99亚洲精品久久 | 国产最新在线观看 | 中文字幕色在线 | 看av在线 | 91麻豆精品国产 | 成人中文字幕+乱码+中文字幕 | 视频在线观看亚洲 | 在线免费av观看 | 在线а√天堂中文官网 | 国产爽视频| 欧美在线视频一区二区三区 | 国产高清在线观看 | 91精品视频在线免费观看 | 亚洲综合射 | av免费网页 | 日日夜夜精品免费观看 | 久久综合狠狠综合 | 欧美另类tv | 久久国产精品久久精品国产演员表 | 国色天香av | 青草视频在线播放 | 99视频在线| 黄色的片子 | 97麻豆视频 | 久久婷婷视频 | 五月天色网站 | 在线蜜桃视频 | 国产精品夜夜夜一区二区三区尤 | 久久视频在线看 | 国产精品美女在线 | 精品五月天 | 国产精品欧美久久久久三级 | 中文字幕在线观看视频免费 | 91成人亚洲 | 国产美女被啪进深处喷白浆视频 | 在线免费黄 | 91看毛片 | 最近免费中文字幕大全高清10 | 午夜精品一区二区三区在线 | 色婷婷激婷婷情综天天 | 一级欧美日韩 | 深爱婷婷激情 | 日操干| 99久久精品视频免费 | 亚洲精品国产精品乱码不99热 | 激情av一区二区 | 午夜精品福利在线 | 国产精品短视频 | 在线观看精品视频 | 欧美一二三视频 | 一区二区三区电影大全 | av激情五月| 久久久久久国产精品999 | 午夜精品成人一区二区三区 | 一本到视频在线观看 | 九九色网 | 色中文字幕在线观看 | 成人91在线| 九九热在线观看 | 99精品免费观看 | 99久久精品国产欧美主题曲 | 婷婷色吧| 国产在线小视频 | 久久久影片 | 韩国av免费观看 | 日本中文字幕网 | 欧美国产精品久久久久久免费 | 欧美日韩国产在线 | 91网在线看 | 丁香午夜婷婷 | 中文字幕一区二区三区在线视频 | 久久99热这里只有精品国产 | 日韩视频 一区 | 麻豆一区二区 | 狠狠干夜夜爱 | 亚洲高清在线观看视频 | www色综合| 色综合中文字幕 | 国产免费黄视频在线观看 | a√资源在线 | 日韩理论片在线 | 一本—道久久a久久精品蜜桃 | www.黄色片网站 | 久久手机精品视频 | www黄免费 | 伊人手机在线 | 人人讲下载 | 久久久久久欧美二区电影网 | 欧美日韩视频精品 | 色婷婷国产精品 | 日韩av有码在线 | 亚洲美女精品 | 国产精品一区二区 91 | 亚洲人在线视频 | 中文字幕在线观看免费高清电影 | 天天操天天摸天天干 | 天天射日 | 日韩精品视频在线观看免费 | 日产乱码一二三区别在线 | 96av在线视频 | 久久人人爽人人爽人人片av软件 | 欧美精品久久久久久久亚洲调教 | 亚洲成人高清在线 | 国产精品成人自产拍在线观看 | 天天操天天射天天爱 | 免费一级日韩欧美性大片 | 久久久九色精品国产一区二区三区 | 五月婷婷黄色网 | 国产精品中文字幕在线播放 | 成人av电影免费 | 99精品国自产在线 | 久久久久久久久久久久av | 天天躁日日躁狠狠躁av中文 | 中文字幕 国产精品 | 一区二区三区在线影院 | 成人在线观看资源 | 婷婷成人在线 | 亚洲精品久久视频 | 91在线视频在线观看 | 日日夜夜中文字幕 | 亚洲美女久久 | 亚洲欧美日韩在线看 | 色婷婷骚婷婷 | 精品极品在线 | 最近2019好看的中文字幕免费 | 久久精品人人做人人综合老师 | 久久精品在线 | 999国产在线| www.xxxx欧美 | 狠狠综合久久av | 婷婷六月天在线 | 黄色av电影| 亚洲国产午夜视频 | 91亚洲精品久久久蜜桃借种 | 色网免费观看 | 日韩免费看 | 国内视频在线 | 免费看黄在线看 | 一个色综合网站 | 天天干天天想 | 久久久一本精品99久久精品66 | 婷婷激情五月综合 | 亚洲视频在线免费观看 | 六月丁香婷婷在线 | 久久大视频 | 久久天堂影院 | 久久在线免费观看 | 丝袜足交在线 | 天堂av在线网站 | 国产高清在线不卡 | 国产精品美女久久久久久久久 | 日批网站免费观看 | 精品福利av | 久久超级碰 | 91久久精品日日躁夜夜躁国产 | 手机在线观看国产精品 | 九九九电影免费看 | 欧美一区二区三区在线观看 | 人人爱人人射 | 国产精品69av | 国产电影黄色av | 国产一区二区在线免费播放 | 亚洲美女视频在线 | 三级黄色a | 国产精品 欧美 日韩 | 成人网444ppp| 欧美国产精品久久久久久免费 | 精品国产一区二区三区av性色 | 天天看天天干 | 亚洲国产午夜视频 | 国产精品18毛片一区二区 | 日韩大片在线免费观看 | 综合激情网... | 国产精品美女久久久久久免费 | 欧美日韩国产一区二区在线观看 | 国产精品白虎 | 麻豆久久久久久久 | 国产成人精品三级 | 成年人精品 | 视频一区二区三区视频 | 精品一区二区三区香蕉蜜桃 | 日韩在线欧美在线 | 91亚瑟视频 |