//使用veth
//1.创建两块虚拟网卡veth1、veth2,然后点对点连接,此后两块网卡的数据会互相发送到对方
$ ip link add veth1 type veth peer name veth2
//2.创建网络命名空间t1
$ ip netns add t1
//3.将veth0加入t1,此时veth0便看不到了,因为被加入到其他命名空间中了
$ ip link set veth0 netns t1
//4.配置veth0的ip地址
$ ip netns exec t1 ifconfig eth0 192.168.1.200/24
//5.设置t1网络的默认路由
$ ip netns exec t1 route add default gw 192.168.1.1
//6.此时将veth2加入本地网桥中,便可以实现veth1在t1中访问外部网络了,过程略,可参考docker中的网络配置步骤
//veth的实现方法(drivers/net/veth.c)
//向ip link注册服务
1.1 static __init int veth_init(void)
{
return rtnl_link_register(&veth_link_ops);
}
//处理ip link命令
2.1 static struct rtnl_link_ops veth_link_ops = {
.kind = DRV_NAME,
.priv_size = sizeof(struct veth_priv),
.setup = veth_setup,
.validate = veth_validate,
.newlink = veth_newlink,
.dellink = veth_dellink,
.policy = veth_policy,
.maxtype = VETH_INFO_MAX,
};
//新加入一条veth链接
2.2 static int veth_newlink(struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
int err;
struct net_device *peer;
struct veth_priv *priv;
char ifname[IFNAMSIZ];
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
//首先创建并注册peer
if (data != NULL && data[VETH_INFO_PEER] != NULL) {
struct nlattr *nla_peer;
//解析命令行参数
nla_peer = data[VETH_INFO_PEER];
err = nla_parse(peer_tb, IFLA_MAX,
nla_data(nla_peer) + sizeof(struct ifinfomsg),
nla_len(nla_peer) - sizeof(struct ifinfomsg),
ifla_policy);
...
} else
tbp = tb;
//初始化peer
...
//注册peer
err = register_netdevice(peer);
if (err < 0)
goto err_register_peer;
//初始化peer的对等端
...
//注册peer的对等端
err = register_netdevice(dev);
if (err < 0)
goto err_register_dev;
//互相将peer保存到private中,在xmit的时候使用
priv = netdev_priv(dev);
priv->peer = peer;
priv = netdev_priv(peer);
priv->peer = dev;
return 0;
err_register_dev:
err_alloc_name:
unregister_netdevice(peer);
return err;
err_register_peer:
free_netdev(peer);
return err;
}
//初始化veth设备
2.3 static void veth_setup(struct net_device *dev)
{
//以太网设备的通用初始化
ether_setup(dev);
//veth的操作列表
dev->netdev_ops = &veth_netdev_ops;
dev->ethtool_ops = &veth_ethtool_ops;
dev->features |= NETIF_F_LLTX;
dev->destructor = veth_dev_free;
}
//通过veth发送skb
2.4 static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_device *rcv = NULL;
struct veth_priv *priv, *rcv_priv;
struct veth_net_stats *stats, *rcv_stats;
int length, cpu;
//获取对等端
priv = netdev_priv(dev);
rcv = priv->peer;
rcv_priv = netdev_priv(rcv);
...
//设置skb的设备为对等端
skb->pkt_type = PACKET_HOST;
skb->protocol = eth_type_trans(skb, rcv);
if (dev->features & NETIF_F_NO_CSUM)
skb->ip_summed = rcv_priv->ip_summed;
...
//将skb放入到对等端的接收队列中,从此完成了skb向对等端的发送
netif_rx(skb);
return NETDEV_TX_OK;
tx_drop:
kfree_skb(skb);
stats->tx_dropped++;
return NETDEV_TX_OK;
rx_drop:
kfree_skb(skb);
rcv_stats->rx_dropped++;
return NETDEV_TX_OK;
}