OVS 两台主机连接

    Hurray 2187次浏览 0条评论 12508字

#笔记 #SDN #OVS #Ryu

> 利用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`

最后修改: