> 利用OVS实现两台主机的直连。
###条件
两台主机`Host1`和`Host2`需要用网线(或光纤)直接相连。
###无控制器的方案
假设两台主机直连的网卡都是`eth1`,两台主机都开启了`ovs-vswitchd`(运行`ovs-vsctl show`出现类似a740ceb8-9eb6-4757-86e4-f5d7a201554的代码)
对于Host1:
```
ovs-vsctl add-br br1
ovs-vsctl set Bridge br1 other_config:datapath-id=0000000000000001
mac="00\:00\:00\:00\:00\:01"
ovs-vsctl add-port br1 p1 -- set interface p1 type=internal
ovs-vsctl set Interface p1 ofport_request=2
ovs-vsctl set Interface p1 mac=$mac
ifconfig p1 172.16.0.1 netmask 255.255.255.0
ifconfig p1 promisc up
ovs-vsctl add-port br1 eth1
ovs-vsctl set Interface eth1 ofport_request=1
#ovs-vsctl set-controller br1 tcp:10.18.134.5:6633
ovs-ofctl add-flow br1 "in_port=1, actions=output:2"
ovs-ofctl add-flow br1 "in_port=2, actions=output:1"
arp -i p1 -s 172.16.0.1 00:00:00:00:00:01
arp -i p1 -s 172.16.0.2 00:00:00:00:00:02
```
对于Host2:
```
ovs-vsctl add-br br1
ovs-vsctl set Bridge br1 other_config:datapath-id=0000000000000002
mac="00\:00\:00\:00\:00\:02"
ovs-vsctl add-port br1 p1 -- set interface p1 type=internal
ovs-vsctl set Interface p1 ofport_request=2
ovs-vsctl set Interface p1 mac=$mac
ifconfig p1 172.16.0.1 netmask 255.255.255.0
ifconfig p1 promisc up
ovs-vsctl add-port br1 eth1
ovs-vsctl set Interface eth1 ofport_request=1
#ovs-vsctl set-controller br1 tcp:10.18.134.5:6633
ovs-ofctl add-flow br1 "in_port=1, actions=output:2"
ovs-ofctl add-flow br1 "in_port=2, actions=output:1"
arp -i p1 -s 172.16.0.1 00:00:00:00:00:01
arp -i p1 -s 172.16.0.2 00:00:00:00:00:02
```
之后测试`ping`、`iperf3`检查连通性(ip是172.16.0.*)
### 有控制器的方案
> 二者的区别在于流表(相当于路由表)的下发,一个是手动实现,一个是控制器下发实现。
假设两台主机直连的网卡都是`eth1`,两台主机都开启了`ovs-vswitchd`(运行`ovs-vsctl show`出现类似a740ceb8-9eb6-4757-86e4-f5d7a201554的代码)。
假设控制器地址为`10.18.134.5:6633`。控制器可以直接用`simple_switch_13.py`,这是一个自学习Mac-port的实现。
对于Host1:
```
ovs-vsctl add-br br1
ovs-vsctl set Bridge br1 other_config:datapath-id=0000000000000001
mac="00\:00\:00\:00\:00\:01"
ovs-vsctl add-port br1 p1 -- set interface p1 type=internal
ovs-vsctl set Interface p1 ofport_request=2
ovs-vsctl set Interface p1 mac=$mac
ifconfig p1 172.16.0.1 netmask 255.255.255.0
ifconfig p1 promisc up
ovs-vsctl add-port br1 eth1
ovs-vsctl set Interface eth1 ofport_request=1
ovs-vsctl set-controller br1 tcp:10.18.134.5:6633
#ovs-ofctl add-flow br1 "in_port=1, actions=output:2"
#ovs-ofctl add-flow br1 "in_port=2, actions=output:1"
arp -i p1 -s 172.16.0.1 00:00:00:00:00:01
arp -i p1 -s 172.16.0.2 00:00:00:00:00:02
```
对于Host2:
```
ovs-vsctl add-br br1
ovs-vsctl set Bridge br1 other_config:datapath-id=0000000000000002
mac="00\:00\:00\:00\:00\:02"
ovs-vsctl add-port br1 p1 -- set interface p1 type=internal
ovs-vsctl set Interface p1 ofport_request=2
ovs-vsctl set Interface p1 mac=$mac
ifconfig p1 172.16.0.1 netmask 255.255.255.0
ifconfig p1 promisc up
ovs-vsctl add-port br1 eth1
ovs-vsctl set Interface eth1 ofport_request=1
ovs-vsctl set-controller br1 tcp:10.18.134.5:6633
#ovs-ofctl add-flow br1 "in_port=1, actions=output:2"
#ovs-ofctl add-flow br1 "in_port=2, actions=output:1"
arp -i p1 -s 172.16.0.1 00:00:00:00:00:01
arp -i p1 -s 172.16.0.2 00:00:00:00:00:02
```
之后测试`ping`、`iperf3`检查连通性(ip是172.16.0.*)
附上一个手动实现的控制器:
```
#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
# Author: Hurray(hurray0@icloud.com)
# Date: 2017.08.14 12:43:42
import sys
reload(sys)
sys.setdefaultencoding('utf8')
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.controller import mac_to_port
from ryu.ofproto import ofproto_v1_0
from ryu.lib.mac import haddr_to_bin
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
'''二层交换机'''
class L2Switch(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION] #define the version of OpenFlow
def __init__(self, *args, **kwargs):
super(L2Switch, self).__init__(*args, **kwargs)
# self.mac_to_port = {}
self.to_port = []
def add_flow(self, datapath, in_port, src, dst, actions):
ofproto = datapath.ofproto
match = datapath.ofproto_parser.OFPMatch(
in_port = in_port,
dl_dst=haddr_to_bin(dst)
)
mod = datapath.ofproto_parser.OFPFlowMod(
datapath = datapath,
match = match, cookie = 0,
command = ofproto.OFPFC_ADD, # idle_timeout = 10,hard_timeout = 10,
priority = ofproto.OFP_DEFAULT_PRIORITY,
flags =ofproto.OFPFF_SEND_FLOW_REM, actions = actions)
print "add flow dp:%s, in_port:%s, dst:%s" % (datapath.id, in_port, dst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
pkt = packet.Packet(msg.data)
eth = pkt.get_protocol(ethernet.ethernet)
dst = eth.dst
src = eth.src
dpid = datapath.id #get the dpid
# self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst , msg.in_port)
#To learn a mac address to avoid FLOOD next time.
# self.mac_to_port[dpid][src] = msg.in_port
in_port = msg.in_port
out_port = 1 if in_port == 2 else 2
ofp_parser = datapath.ofproto_parser
if in_port + out_port < 30:
actions = [ofp_parser.OFPActionOutput(out_port)]
self.add_flow(datapath, in_port, src, dst, actions)
actions = [ofp_parser.OFPActionOutput(in_port)]
self.add_flow(datapath, out_port, dst, src, actions)
#We always send the packet_out to handle the first packet.
# packet_out = ofp_parser.OFPPacketOut(datapath = datapath, buffer_id = msg.buffer_id,
# in_port = msg.in_port, actions = actions)
# datapath.send_msg(packet_out)
#To show the message of ports' status.
@set_ev_cls(ofp_event.EventOFPPortStatus, MAIN_DISPATCHER)
def _port_status_handler(self, ev):
msg = ev.msg
reason = msg.reason
port_no = msg.desc.port_no
ofproto = msg.datapath.ofproto
if reason == ofproto.OFPPR_ADD:
self.logger.info("port added %s", port_no)
elif reason == ofproto.OFPPR_DELETE:
self.logger.info("port deleted %s", port_no)
elif reason == ofproto.OFPPR_MODIFY:
self.logger.info("port modified %s", port_no)
else:
self.logger.info("Illeagal port state %s %s", port_no, reason)
```
PS。其实关键点就在一句:`out_port = 1 if in_port == 2 else 2`
版权属于:Hurray's InfoShare
本文链接:https://hurray0.com/menu/53/
如果没有特别声明,则为本博原创。转载时须注明出处及本声明!