一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Linux 網(wǎng)橋代碼分析 (二)

 enchen008 2012-04-10

第三部分: ioctl管理網(wǎng)橋
3.1 通過ioctl系統(tǒng)調(diào)用創(chuàng)建網(wǎng)橋
     仍然以前的配置作為例,我們分用戶空間程序brctl是如何通過ioctl系統(tǒng)調(diào)用在kernel空間內(nèi)創(chuàng)建上述的數(shù)據(jù)結(jié)構(gòu)。創(chuàng)建網(wǎng)橋,我們不需要預(yù)知任何網(wǎng)絡(luò)設(shè)備信息,因此我們通過ioctl來創(chuàng)建網(wǎng)橋時不應(yīng)該與任何網(wǎng)絡(luò)設(shè)備綁定到一起。網(wǎng)橋模塊為此ioctl函數(shù)提供了一個恰如其分的名字 br_ioctl_deviceless_stub。Brctl工具使用的ioctl系統(tǒng)調(diào)用最終會調(diào)用此函數(shù),它相關(guān)代碼如下:

[linux-2.6.24.4/net/bridge/br.c]

brioctl_set(br_ioctl_deviceless_stub);

[linux-2.6.24.4/net/socket.c]

void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))   {  
  mutex_lock(&br_ioctl_mutex);  
  br_ioctl_hook = hook;  
  mutex_unlock(&br_ioctl_mutex);  
}  
void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) {
  mutex_lock(&br_ioctl_mutex);
  br_ioctl_hook = hook;
  mutex_unlock(&br_ioctl_mutex);

        用戶空間程序使用網(wǎng)橋相關(guān)的命令來調(diào)用ioctl函數(shù)時,它經(jīng)kernel依據(jù)命令所屬的分類分派到sock_ioctl函數(shù)。在sock_ioctl函數(shù)里面,當(dāng)ioctl命令為SIOCGIFBR,SIOCSIFBR, SIOCBRADDBR 和SIOCBRDELBR,它將ioctl的請求轉(zhuǎn)發(fā)到br_ioctl_deviceless_stub函數(shù)。

Br_ioctl_deviceless_stub函數(shù)代碼和分析如下:

[linux-2.6.24.4/net/bridge/br_ioctl.c]

int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)   {  
  switch (cmd) {  
    case SIOCGIFBR:  
    case SIOCSIFBR:  
      // 這兩個網(wǎng)橋命令是比較老式的,我們在這里不作討論  
      return old_deviceless(uarg);  
    // 新式的網(wǎng)橋ioctl命令有兩個,添加新網(wǎng)橋和刪除現(xiàn)有的網(wǎng)橋  
    // 需要用戶空間提供網(wǎng)橋的名字。  
    case SIOCBRADDBR:  
    case SIOCBRDELBR:  
    {  
      char buf[IFNAMSIZ];  
      if (!capable(CAP_NET_ADMIN))  
        return -EPERM;  
      if (copy_from_user(buf, uarg, IFNAMSIZ))  
        return -EFAULT;  
      buf[IFNAMSIZ-1] = 0;  
      if (cmd == SIOCBRADDBR)  
        return br_add_bridge(buf);  
      return br_del_bridge(buf);  
    }  
  }  
  return -EOPNOTSUPP;  
}  
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg) {
  switch (cmd) {
    case SIOCGIFBR:
    case SIOCSIFBR:
      // 這兩個網(wǎng)橋命令是比較老式的,我們在這里不作討論
      return old_deviceless(uarg);
    // 新式的網(wǎng)橋ioctl命令有兩個,添加新網(wǎng)橋和刪除現(xiàn)有的網(wǎng)橋
    // 需要用戶空間提供網(wǎng)橋的名字。
    case SIOCBRADDBR:
    case SIOCBRDELBR:
    {
      char buf[IFNAMSIZ];
      if (!capable(CAP_NET_ADMIN))
        return -EPERM;
      if (copy_from_user(buf, uarg, IFNAMSIZ))
        return -EFAULT;
      buf[IFNAMSIZ-1] = 0;
      if (cmd == SIOCBRADDBR)
        return br_add_bridge(buf);
      return br_del_bridge(buf);
    }
  }
  return -EOPNOTSUPP;

      該函數(shù)調(diào)用br_add_bridge和br_del_brdge函數(shù)的實現(xiàn)新建和刪除網(wǎng)橋的功能。由于這兩個函數(shù)所完成的事情剛好相反,在此,我們只討論br_add_bridge的代碼:

[linux-2.6.24.4/net/bridge/br_if.c]

int br_add_bridge(const char *name)   {  
  struct net_device *dev;  
  int ret;  
  // 創(chuàng)建網(wǎng)橋的核心工作,創(chuàng)建一個與網(wǎng)橋同名的網(wǎng)絡(luò)設(shè)備。  
  // 可以通過該設(shè)備分配的IP地址來管理該網(wǎng)橋。 同時該設(shè)備  
  // 是虛擬的設(shè)備,它的接收包和發(fā)送包處理函數(shù)與一般的真實網(wǎng)卡  
  // 設(shè)備不同。  
  dev = new_bridge_dev(name);  
  if (!dev)  
    return -ENOMEM;  
  rtnl_lock();  
  if (strchr(dev->name, '%')) {  
    ret = dev_alloc_name(dev, dev->name);  
    if (ret < 0) {  
      free_netdev(dev);  
      goto out;  
    }  
  }  
  // 向kernel注冊該網(wǎng)橋設(shè)備,這樣在用戶空間就以使用  
  // ifconfig來為之分配IP,或通ioctl來對該網(wǎng)橋添加新的接口。  
  ret = register_netdevice(dev);  
  if (ret)  
    goto out;  
  ret = br_sysfs_addbr(dev);  
  if (ret)  
    unregister_netdevice(dev);  
out:  
  rtnl_unlock();  
  return ret;  
}  
int br_add_bridge(const char *name) {
  struct net_device *dev;
  int ret;
  // 創(chuàng)建網(wǎng)橋的核心工作,創(chuàng)建一個與網(wǎng)橋同名的網(wǎng)絡(luò)設(shè)備。
  // 可以通過該設(shè)備分配的IP地址來管理該網(wǎng)橋。 同時該設(shè)備
  // 是虛擬的設(shè)備,它的接收包和發(fā)送包處理函數(shù)與一般的真實網(wǎng)卡
  // 設(shè)備不同。
  dev = new_bridge_dev(name);
  if (!dev)
    return -ENOMEM;
  rtnl_lock();
  if (strchr(dev->name, '%')) {
    ret = dev_alloc_name(dev, dev->name);
    if (ret < 0) {
      free_netdev(dev);
      goto out;
    }
  }
  // 向kernel注冊該網(wǎng)橋設(shè)備,這樣在用戶空間就以使用
  // ifconfig來為之分配IP,或通ioctl來對該網(wǎng)橋添加新的接口。
  ret = register_netdevice(dev);
  if (ret)
    goto out;
  ret = br_sysfs_addbr(dev);
  if (ret)
    unregister_netdevice(dev);
out:
  rtnl_unlock();
  return ret;

      現(xiàn)在創(chuàng)建網(wǎng)橋設(shè)備的任務(wù)落到new_bridge_dev的身上。New_bridge_dev函數(shù)的功能與一般的網(wǎng)卡驅(qū)動初化為代碼非常類似的。因為這里段代就創(chuàng)建一個網(wǎng)橋設(shè)備,從這個層面來說,這段代碼也算是驅(qū)動代碼,結(jié)構(gòu)和真實驅(qū)動非常類似。

[linux-2.6.24.4/net/bridge/br_if.c]

static struct net_device *new_bridge_dev(const char *name)   {  
  struct net_bridge *br;  
  struct net_device *dev;  
  // 分配net_device結(jié)構(gòu),它的priv數(shù)據(jù)為net_bridge結(jié)構(gòu)體。  
  // br_dev_setup函數(shù)初化了net_device結(jié)構(gòu)的很多函數(shù)指針。  
  dev = alloc_netdev(sizeof(struct net_bridge), name,  
                     br_dev_setup);  
  if (!dev)  
    return NULL;  
  br = netdev_priv(dev);  
  br->dev = dev;  
  spin_lock_init(&br->lock);  
  INIT_LIST_HEAD(&br->port_list);  
  spin_lock_init(&br->hash_lock);  
  br->bridge_id.prio[0] = 0x80;  
  br->bridge_id.prio[1] = 0x00;  
  ….  
  return dev;  
}  
static struct net_device *new_bridge_dev(const char *name) {
  struct net_bridge *br;
  struct net_device *dev;
  // 分配net_device結(jié)構(gòu),它的priv數(shù)據(jù)為net_bridge結(jié)構(gòu)體。
  // br_dev_setup函數(shù)初化了net_device結(jié)構(gòu)的很多函數(shù)指針。
  dev = alloc_netdev(sizeof(struct net_bridge), name,
                     br_dev_setup);
  if (!dev)
    return NULL;
  br = netdev_priv(dev);
  br->dev = dev;
  spin_lock_init(&br->lock);
  INIT_LIST_HEAD(&br->port_list);
  spin_lock_init(&br->hash_lock);
  br->bridge_id.prio[0] = 0x80;
  br->bridge_id.prio[1] = 0x00;
  ….
  return dev;

 [linux-2.6.24.4/net/bridge/br_device.c]

void br_dev_setup(struct net_device *dev)   {  
  // 為該網(wǎng)橋設(shè)備隨機(jī)分配MAC地址  
  random_ether_addr(dev->dev_addr);  
  // 初始化dev的部分函數(shù)指針,因為目前網(wǎng)橋設(shè)備主適用于以及網(wǎng)  
  // 以太網(wǎng)的部分功能對它也適用。  
  ether_setup(dev);  
  // 設(shè)置設(shè)備的ioctl函數(shù)為br_dev_ioctl。下面可以看到通過該ioctl函數(shù)  
  // 來為網(wǎng)橋添加網(wǎng)絡(luò)接口。  
  dev->do_ioctl = br_dev_ioctl;  
  // 網(wǎng)橋與一般網(wǎng)卡不同,網(wǎng)橋統(tǒng)一統(tǒng)計它的數(shù)據(jù)包和字節(jié)數(shù)等信息。  
  dev->get_stats = br_dev_get_stats;  
  // 網(wǎng)橋接口的數(shù)據(jù)包發(fā)送函數(shù),真實設(shè)備要向外發(fā)送數(shù)據(jù)時,是通過  
  // 網(wǎng)卡向外發(fā)送數(shù)據(jù)。而該網(wǎng)橋設(shè)備要向外發(fā)送數(shù)據(jù)時,它的處理邏輯與  
  // 網(wǎng)橋其它接口的基本一致。  
  dev->hard_start_xmit = br_dev_xmit;  
  dev->open = br_dev_open;  
  dev->set_multicast_list = br_dev_set_multicast_list;  
  dev->change_mtu = br_change_mtu;  
  dev->destructor = free_netdev;  
  SET_ETHTOOL_OPS(dev, &br_ethtool_ops);  
  dev->stop = br_dev_stop;  
  dev->tx_queue_len = 0;  
  dev->set_mac_address = br_set_mac_address;  
  dev->priv_flags = IFF_EBRIDGE;  
  dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |  
                  NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;  
}  
void br_dev_setup(struct net_device *dev) {
  // 為該網(wǎng)橋設(shè)備隨機(jī)分配MAC地址
  random_ether_addr(dev->dev_addr);
  // 初始化dev的部分函數(shù)指針,因為目前網(wǎng)橋設(shè)備主適用于以及網(wǎng)
  // 以太網(wǎng)的部分功能對它也適用。
  ether_setup(dev);
  // 設(shè)置設(shè)備的ioctl函數(shù)為br_dev_ioctl。下面可以看到通過該ioctl函數(shù)
  // 來為網(wǎng)橋添加網(wǎng)絡(luò)接口。
  dev->do_ioctl = br_dev_ioctl;
  // 網(wǎng)橋與一般網(wǎng)卡不同,網(wǎng)橋統(tǒng)一統(tǒng)計它的數(shù)據(jù)包和字節(jié)數(shù)等信息。
  dev->get_stats = br_dev_get_stats;
  // 網(wǎng)橋接口的數(shù)據(jù)包發(fā)送函數(shù),真實設(shè)備要向外發(fā)送數(shù)據(jù)時,是通過
  // 網(wǎng)卡向外發(fā)送數(shù)據(jù)。而該網(wǎng)橋設(shè)備要向外發(fā)送數(shù)據(jù)時,它的處理邏輯與
  // 網(wǎng)橋其它接口的基本一致。
  dev->hard_start_xmit = br_dev_xmit;
  dev->open = br_dev_open;
  dev->set_multicast_list = br_dev_set_multicast_list;
  dev->change_mtu = br_change_mtu;
  dev->destructor = free_netdev;
  SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
  dev->stop = br_dev_stop;
  dev->tx_queue_len = 0;
  dev->set_mac_address = br_set_mac_address;
  dev->priv_flags = IFF_EBRIDGE;
  dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
                  NETIF_F_GSO_MASK | NETIF_F_NO_CSUM | NETIF_F_LLTX;

 

3.2 通過ioctl系統(tǒng)調(diào)用為網(wǎng)橋添加端口

        僅僅創(chuàng)建網(wǎng)橋,還是不夠的。實際應(yīng)用中的網(wǎng)橋需要添加實際的端口(即物理接口),如例子中的eth1, eth2等。應(yīng)用程序在使用ioctl來為網(wǎng)橋增加物理接口,br_dev_ioctl的代碼和分析如下:

[linux-2.6.24.4/net/bridge/br_ioctl.c]

// dev 為網(wǎng)橋接口,ifreq 為添加/刪除的物理接口的參數(shù)  
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)   {  
  struct net_bridge *br = netdev_priv(dev);  
  switch(cmd) {  
    case SIOCDEVPRIVATE:  
      return old_dev_ioctl(dev, rq, cmd);  
    case SIOCBRADDIF:  
    case SIOCBRDELIF:  
      return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);  
  }  
  pr_debug("Bridge does not support ioctl 0x%x\n", cmd);  
  return -EOPNOTSUPP;  
}  
// dev 為網(wǎng)橋接口,ifreq 為添加/刪除的物理接口的參數(shù)
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) {
  struct net_bridge *br = netdev_priv(dev);
  switch(cmd) {
    case SIOCDEVPRIVATE:
      return old_dev_ioctl(dev, rq, cmd);
    case SIOCBRADDIF:
    case SIOCBRDELIF:
      return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
  }
  pr_debug("Bridge does not support ioctl 0x%x\n", cmd);
  return -EOPNOTSUPP;

    這段代碼一目了然,通過add_del_if函數(shù)來控制網(wǎng)橋的物理接口,該函數(shù)的代碼和分析如下:

[linux-2.6.24.4/net/bridge/br_ioctl.c]

// br 網(wǎng)橋,ifindex 添加/刪除物理接口的index  
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)   {  
  struct net_device *dev;  
  int ret;  
   
  if (!capable(CAP_NET_ADMIN))  
    return -EPERM;  
  dev = dev_get_by_index(&init_net, ifindex);  
  if (dev == NULL)  
    return -EINVAL;  
  if (isadd)  
    ret = br_add_if(br, dev);  
  else 
    ret = br_del_if(br, dev);  
  dev_put(dev);  
  return ret;  
}  
// br 網(wǎng)橋,ifindex 添加/刪除物理接口的index
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)  {
  struct net_device *dev;
  int ret;
 
  if (!capable(CAP_NET_ADMIN))
    return -EPERM;
  dev = dev_get_by_index(&init_net, ifindex);
  if (dev == NULL)
    return -EINVAL;
  if (isadd)
    ret = br_add_if(br, dev);
  else
    ret = br_del_if(br, dev);
  dev_put(dev);
  return ret;

     具體的代碼在br_add_if和br_del_if中,出于討論的方便,我們只分析br_add_if函數(shù)。

[linux-2.6.24.4/net/bridge/br_if.c]

int br_add_if(struct net_bridge *br, struct net_device *dev)   {  
  struct net_bridge_port *p;  
  int err = 0;  
  // Kernel僅支持以太網(wǎng)網(wǎng)橋  
  if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)  
    return -EINVAL;  
  // 把網(wǎng)橋接口當(dāng)作物理接口加入到另一個網(wǎng)橋中,是不行的。  
  // 邏輯和代碼上都會出現(xiàn) loop  
  if (dev->hard_start_xmit == br_dev_xmit)  
    return -ELOOP;  
  // 該物理接口加綁定到另一個網(wǎng)橋了。  
  if (dev->br_port != NULL)  
    return -EBUSY;  
  // 為該接口創(chuàng)建一個網(wǎng)橋端口數(shù)據(jù),并初始化好該端口的相關(guān)  
  // 數(shù)據(jù),詳情可參閱該函數(shù)代碼。  
  p = new_nbp(br, dev);  
  if (IS_ERR(p))  
    return PTR_ERR(p);  
  err = kobject_add(&p->kobj);  
  if (err)  
    goto err0;  
  // 將該接口的物理地址寫入到 MAC-端口映射表中。  
  // 該MAC是屬于網(wǎng)橋內(nèi)部端口的固定MAC地址,  
  // 它在fdb中的記錄是固定的,不會失效(agged)  
  err = br_fdb_insert(br, p, dev->dev_addr);  
  if (err)  
    goto err1;  
  err = br_sysfs_addif(p);  
   
  if (err)  
    goto err2;  
  rcu_assign_pointer(dev->br_port, p);  
  // 打開該接口的混雜模式,網(wǎng)橋中的各個端口必須處于  
  // 混雜模式,網(wǎng)橋才能正確工作。  
  dev_set_promiscuity(dev, 1);  
  // 加到端口列表  
  list_add_rcu(&p->list, &br->port_list);  
  spin_lock_bh(&br->lock);  
  br_stp_recalculate_bridge_id(br);  
  br_features_recompute(br);  
  if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&  
      (br->dev->flags & IFF_UP))  
    br_stp_enable_port(p);  
  spin_unlock_bh(&br->lock);  
  br_ifinfo_notify(RTM_NEWLINK, p);  
  dev_set_mtu(br->dev, br_min_mtu(br));  
  kobject_uevent(&p->kobj, KOBJ_ADD);  
  return 0;  
err2:  
  br_fdb_delete_by_port(br, p, 1);  
err1:  
  kobject_del(&p->kobj);  
err0:  
  kobject_put(&p->kobj);  
  return err;  

int br_add_if(struct net_bridge *br, struct net_device *dev)  {
  struct net_bridge_port *p;
  int err = 0;
  // Kernel僅支持以太網(wǎng)網(wǎng)橋
  if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER)
    return -EINVAL;
  // 把網(wǎng)橋接口當(dāng)作物理接口加入到另一個網(wǎng)橋中,是不行的。
  // 邏輯和代碼上都會出現(xiàn) loop
  if (dev->hard_start_xmit == br_dev_xmit)
    return -ELOOP;
  // 該物理接口加綁定到另一個網(wǎng)橋了。
  if (dev->br_port != NULL)
    return -EBUSY;
  // 為該接口創(chuàng)建一個網(wǎng)橋端口數(shù)據(jù),并初始化好該端口的相關(guān)
  // 數(shù)據(jù),詳情可參閱該函數(shù)代碼。
  p = new_nbp(br, dev);
  if (IS_ERR(p))
    return PTR_ERR(p);
  err = kobject_add(&p->kobj);
  if (err)
    goto err0;
  // 將該接口的物理地址寫入到 MAC-端口映射表中。
  // 該MAC是屬于網(wǎng)橋內(nèi)部端口的固定MAC地址,
  // 它在fdb中的記錄是固定的,不會失效(agged)
  err = br_fdb_insert(br, p, dev->dev_addr);
  if (err)
    goto err1;
  err = br_sysfs_addif(p);
 
  if (err)
    goto err2;
  rcu_assign_pointer(dev->br_port, p);
  // 打開該接口的混雜模式,網(wǎng)橋中的各個端口必須處于
  // 混雜模式,網(wǎng)橋才能正確工作。
  dev_set_promiscuity(dev, 1);
  // 加到端口列表
  list_add_rcu(&p->list, &br->port_list);
  spin_lock_bh(&br->lock);
  br_stp_recalculate_bridge_id(br);
  br_features_recompute(br);
  if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
      (br->dev->flags & IFF_UP))
    br_stp_enable_port(p);
  spin_unlock_bh(&br->lock);
  br_ifinfo_notify(RTM_NEWLINK, p);
  dev_set_mtu(br->dev, br_min_mtu(br));
  kobject_uevent(&p->kobj, KOBJ_ADD);
  return 0;
err2:
  br_fdb_delete_by_port(br, p, 1);
err1:
  kobject_del(&p->kobj);
err0:
  kobject_put(&p->kobj);
  return err;
}

 

第四部分: 總結(jié)
    網(wǎng)橋是2層的網(wǎng)格連接設(shè)備,它工作在協(xié)議棧的第二層。本文以簡單的例子作為基礎(chǔ),分析網(wǎng)橋處理報文,更新MAC-端口映射表,和如何控制網(wǎng)橋和端口的功能。文中帖上了大量的關(guān)鍵代碼,并以代碼加上注釋這種貼近程序員的方式來分析代碼。對于缺少kernel網(wǎng)絡(luò)編程經(jīng)驗的朋友,在某些代碼處,寫了在背景知識的分析和解釋。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    视频一区日韩经典中文字幕| 日韩人妻精品免费一区二区三区| 欧美一级黄片免费视频| 欧美综合色婷婷欧美激情| 伊人网免费在线观看高清版| 久久99青青精品免费| 中文字幕一区二区三区大片| 欧美日韩一级aa大片| 欧美午夜国产在线观看| 亚洲精品有码中文字幕在线观看| 中文字幕91在线观看| 日本最新不卡免费一区二区 | 欧美日韩中国性生活视频| 中国少妇精品偷拍视频| 亚洲高清亚洲欧美一区二区| 亚洲欧美日韩综合在线成成| 亚洲国产av国产av| 色欧美一区二区三区在线| 1024你懂的在线视频| 国产欧洲亚洲日产一区二区| 免费大片黄在线观看日本| 风间中文字幕亚洲一区| 欧美亚洲国产日韩一区二区| 亚洲欧美日韩网友自拍| 成人亚洲国产精品一区不卡| 国产真人无遮挡免费视频一区 | 亚洲欧美日韩色图七区| 人妻熟女欲求不满一区二区| 69精品一区二区蜜桃视频| 欧美亚洲国产日韩一区二区| 亚洲一区二区精品久久av| 中文字幕日韩欧美亚洲午夜| 黄片在线免费观看全集| 高清一区二区三区大伊香蕉| 色哟哟精品一区二区三区| 开心久久综合激情五月天| 日韩欧美第一页在线观看| 国产精品第一香蕉视频| 中文字幕一区二区久久综合| 国产视频在线一区二区| 五月婷日韩中文字幕四虎|