- Vì cây MST được sử dụng như một graph cơ bản cho các thuật toán.. Sử dụng các thuật toán định tuyến khác thay vào code mẫu ở trên?. - Sử dụng thuật toán Bellman Ford: from pox.core imp
Trang 1TRƯỜNG ĐẠI HỌC BÁCH KHOA HÀ NỘI
VIỆN ĐIỆN TỬ - VIỄN THÔNG
-BÁO CÁO THÍ NGHIỆM MÔN HỌC
CƠ SỞ TRUYỀN SỐ LIỆU (ET4070)
Họ và tên sinh viên : Phạm Duy Đông
Mã số SV : 20182426 Nhóm thí nghiệm : C18 Ngày nộp báo cáo : 16/1/2022
Hà Nội, 2022
Trang 2BÀI 1: TẠO TOPOLOGY BẰNG MININET
1 Flow-entry và flowtable là gì?
- Flowtable chứa các flow-entry, mỗi flow-entry định nghĩa một hoặc nhiều hoạt động khi switch nhận được các luồng (flow) có đặc điểm giống như mô tả
2 Nêu các lệnh cần thiết để tạo flow-entry giúp tất cả các host có thể ping được với nhau?
sudo ovs-ofctl add-flow [switch name] dl_type=0x0806, nw_dst=[address host dest], action=output:[port to dest]
sudo ovs-ofctl add-flow [switch name] dl_type=0x0800, nw_dst=[address host dest], action=output:[port to dest]
3 Thời gian time-out của flow-entry trong flowtable là gì? Giá trị mặc định bằng bao nhiêu?
- Có 2 loại thời gian time-out:
Idle time-out là thời gian mà sau khi entry bị xóa khỏi flow table và phần cứng cung cấp vì không có gói tin tương ứng với nó
Hard time-out là thời gian sau khi một flow entry bị xóa khỏi flow table và phần cứng cung cấp dù có hay không gói tin tương ứng với nó
- Mặc định là không có time-out
Trang 3BÀI 2: TẠO CÂY BẮC CẦU TỐI THIỂU
1 Tại sao phải tạo cây MST?
- Vì cây MST được sử dụng như một graph cơ bản cho các thuật toán Các cây là mạng tối thiểu, cung cấp một đường đi giữa 2 nút bất kì, giải quyết các vấn đề về bài toán định tuyến Điều đó giúp đơn giản hóa mạng về dạng của nó
Trang 4BÀI 3: ĐỊNH TUYẾN SỬ DỤNG THUẬT TOÁN DIJKSTRA
1 Sử dụng các thuật toán định tuyến khác thay vào code mẫu ở trên?
- Sử dụng thuật toán Bellman Ford:
from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.util import dpid_to_str
from pox.lib.util import str_to_dpid
from pox.lib.util import str_to_bool
from pox.lib.packet.arp import arp
from pox.lib.packet.ipv4 import ipv4
from pox.openflow.discovery import Discovery import pox.lib.packet as pkt
import time
log = core.getLogger()
# We don't want to flood immediately when a switch connects
# Can be overriden on commandline
_flood_delay = 0
class L3Routing (object):
def init (self, connection, transparent): self.connection = connection
self.transparent = transparent
self.graph={}
self.listSWitch=[]
self.listHost=[]
self.host={'1':1, '2':1, '3':1,'4':1} self.path=[]
self.macToPort = {}
# We want to hear PacketIn messages, so we listen
# to the connection
connection.addListeners(self)
# We just use this to know when to log a helpful message
Trang 5"""
Handle packet in messages from the switch to implement above algorithm
"""
packet = event.parsed
def bellman_ford(graph, source, dst): # Step 1: Prepare the distance and
predecessor for each node
distance, predecessor = dict(), dict() for node in graph:
distance[node], predecessor[node] = float('inf'), None
distance[source] = 0
# Step 2: Relax the edges
for _ in range(len(graph) - 1):
for node in graph:
for neighbour in graph[node]: # If the distance between the node and the neighbour is lower than the current, store it
if distance[neighbour] > distance[node] + 1:
distance[neighbour], predecessor[neighbour] = distance[node] + 1, node
# Step 3: Check for negative weight cycles for node in graph:
for neighbour in graph[node]:
assert distance[neighbour] <= distance[node] + graph[node][neighbour],
"Negative weight cycle."
print(predecessor)
check =True
while check:
for node in predecessor:
if node == dst:
if dst == source:
self.path.append(dst)
check=False
break
else:
self.path.append(node)
Trang 6def flood (message = None):
""" Floods the packet """
msg = of.ofp_packet_out()
if time.time() -
self.connection.connect_time >= _flood_delay: # Only flood if we've been connected for
a little while
if self.hold_down_expired is False: # Oh yes it is!
self.hold_down_expired = True
log.info("%s: Flood hold-down expired flooding",
dpid_to_str(event.dpid))
if message is not None:
log.debug(message)
#log.debug("%i: flood %s -> %s", event.dpid,packet.src,packet.dst)
# OFPP_FLOOD is optional; on some switches you may need to change
# this to OFPP_ALL
msg.actions.append(of.ofp_action_output(port = of.OFPP_FLOOD))
else:
pass
#log.info("Holding down flood for %s", dpid_to_str(event.dpid))
msg.data = event.ofp
msg.in_port = event.port
self.connection.send(msg)
if not self.transparent:
if packet.type == packet.LLDP_TYPE or packet.dst.isBridgeFiltered():
drop()
return
if packet.dst.is_multicast:
flood()
else:
for l in
core.openflow_discovery.adjacency:
sw_src = l. str ().split("->")
[0].split(".")[0].split("-")[5][1].strip() port_src= l. str ().split("->")
Trang 7[1].split(".")[0].split("-")[5][1].strip() port_dst=l. str ().split("->") [1].split(".")[1].strip()
log.debug("SW src: %s SW dst: %s Port src: %s Port dst: %s" %(sw_src, sw_dst, port_src, port_dst))
if sw_src in self.listSWitch:
list = self.graph[sw_src]
list[sw_dst]=int(port_src)
self.graph[sw_src]=list
else:
tlist={}
tlist[sw_dst]=int(port_src)
self.graph[sw_src]= tlist
self.listSWitch.append(sw_src)
if isinstance (packet.next, arp):
arp_packet = packet.find(pkt.arp) src_ip =
arp_packet.protosrc.toStr().split(".")[3] dst_ip =
arp_packet.protodst.toStr().split(".")[3] dpid =
dpid_to_str(event.dpid).split("-")[5][1]
if isinstance(packet.next, ipv4):
ip_packet = packet.find(pkt.ipv4)
if ip_packet is not None:
src_ip =
ip_packet.srcip.toStr().split(".")[3]
dst_ip =
ip_packet.dstip.toStr().split(".")[3]
log.debug("IP src= %s IP dst= %s" % (src_ip, dst_ip))
self.path=[]
bellman_ford(self.graph,dst_ip,src_ip) print(self.path)
dpid = dpid_to_str(event.dpid).split("-") [5][1]
for index in range(len(self.path)):
if dpid is self.path[index]:
if self.path[index] is self.path[-1]: msg = of.ofp_flow_mod()
msg.match =
of.ofp_match.from_packet(packet, event.port) msg.idle_timeout = 10
msg.hard_timeout = 30
Trang 8msg.data = event.ofp
self.connection.send(msg)
else:
msg = of.ofp_flow_mod()
msg.match =
of.ofp_match.from_packet(packet, event.port) msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = self.graph[self.path[index]]
[self.path[index+1]]))
msg.data = event.ofp
self.connection.send(msg)
class l3_routing (object):
def init (self, transparent):
core.openflow.addListeners(self)
self.transparent = transparent
def _handle_ConnectionUp (self, event): log.debug("Connection %s" %
(event.connection,))
L3Routing(event.connection,
self.transparent)
def launch (transparent=False,
hold_down=_flood_delay):
"""
Starts an L3 routing
"""
try:
global _flood_delay
_flood_delay = int(str(hold_down), 10) assert _flood_delay >= 0
except:
raise RuntimeError("Expected hold-down to be
a number")
core.registerNew(l3_routing,
str_to_bool(transparent))
2 Ở module định tuyến tại sao cần phải xử lý gói tin ARP?
Trang 9- Các gói tin IP không được gửi trực tiếp mà được bỏ vào một khung rồi mới gửi đi, khung này có địa chỉ gửi và địa chỉ đích Các địa chỉ này là địa chỉ MAC (vật lý) của một card mạng Một card mạng nhận các khung có địa chỉ đích là địa chỉ MAC của mình ARP là giao thức phân giải địa chỉ, kết nối giữa
IP và MAC nên cần phải xử lý gói tin ARP
Trang 10BÀI 4: ĐỊNH TUYẾN SỬ DỤNG THUẬT TOÁN BELLMAN
1 Sử dụng các thuật toán định tuyến khác thay vào code mẫu ở trên?
- Sử dụng thuật toán Dijkstra:
from pox.core import core
import pox.openflow.libopenflow_01 as of
from pox.lib.util import dpid_to_str
from pox.lib.util import str_to_dpid
from pox.lib.util import str_to_bool
from pox.lib.packet.arp import arp
from pox.lib.packet.ipv4 import ipv4
from pox.openflow.discovery import Discovery
import pox.lib.packet as pkt
import time
log = core.getLogger()
# We don't want to flood immediately when a switch connects
# Can be overriden on commandline
_flood_delay = 0
class L3Routing (object):
def init (self, connection, transparent):
self.connection = connection
self.transparent = transparent
self.graph={}
self.listSWitch=[]
Trang 11self.path=[]
self.macToPort = {}
# We want to hear PacketIn messages, so we listen # to the connection
connection.addListeners(self)
# We just use this to know when to log a helpful message
self.hold_down_expired = _flood_delay == 0
def _handle_PacketIn (self, event):
"""
Handle packet in messages from the switch to implement above algorithm
"""
packet = event.parsed
def
dijkstra(graph,src,dest,visited=[],distances={},prede cessors={}):
# a few sanity checks
if src not in graph:
raise TypeError('the root of the shortest path tree cannot be found in the graph')
if dest not in graph:
raise TypeError('the target of the shortest path cannot be found in the graph')
# ending condition
if src == dest:
Trang 12while pred != None:
self.path.append(pred)
pred=predecessors.get(pred,None)
else :
# if it is the initial run, initializes the cost
if not visited:
distances[src]=0
# visit the neighbors
for neighbor in graph[src] :
if neighbor not in visited:
new_distance = distances[src] + 1
if new_distance <
distances.get(neighbor,float('inf')):
distances[neighbor] =
new_distance
predecessors[neighbor] = src # mark as visited
visited.append(src)
# now that all neighbors have been visited: recurse
# select the non visited node with lowest distance 'x'
# run Dijskstra with src='x'
unvisited={}
for k in graph:
if k not in visited:
unvisited[k] =
distances.get(k,float('inf'))
x=min(unvisited, key=unvisited.get)
Trang 13dijkstra(graph,x,dest,visited,distances,predecessors)
def flood (message = None):
""" Floods the packet """
msg = of.ofp_packet_out()
if time.time() - self.connection.connect_time
>= _flood_delay:
# Only flood if we've been connected for a little while
if self.hold_down_expired is False:
# Oh yes it is!
self.hold_down_expired = True
log.info("%s: Flood hold-down expired flooding",
dpid_to_str(event.dpid))
if message is not None: log.debug(message) #log.debug("%i: flood %s -> %s",
event.dpid,packet.src,packet.dst)
# OFPP_FLOOD is optional; on some switches you may need to change
# this to OFPP_ALL
msg.actions.append(of.ofp_action_output(port
= of.OFPP_FLOOD))
else:
pass
#log.info("Holding down flood for %s", dpid_to_str(event.dpid))
Trang 14self.connection.send(msg)
if not self.transparent:
if packet.type == packet.LLDP_TYPE or
packet.dst.isBridgeFiltered():
drop()
return
if packet.dst.is_multicast:
flood()
else:
for l in core.openflow_discovery.adjacency: sw_src = l. str ().split("->")
[0].split(".")[0].split("-")[5][1].strip()
port_src= l. str ().split("->")
[0].split(".")[1].strip()
sw_dst = l. str ().split("->")
[1].split(".")[0].split("-")[5][1].strip()
port_dst=l. str ().split("->")
[1].split(".")[1].strip()
log.debug("SW src: %s SW dst: %s Port src: %s Port dst: %s" %(sw_src, sw_dst, port_src, port_dst))
if sw_src in self.listSWitch:
list = self.graph[sw_src]
list[sw_dst]=int(port_src)
self.graph[sw_src]=list
else:
tlist={}
tlist[sw_dst]=int(port_src)
self.graph[sw_src]= tlist
self.listSWitch.append(sw_src)
if isinstance (packet.next, arp):
Trang 15dst_ip =
arp_packet.protodst.toStr().split(".")[3]
dpid = dpid_to_str(event.dpid).split("-")[5] [1]
if isinstance(packet.next, ipv4):
ip_packet = packet.find(pkt.ipv4)
if ip_packet is not None:
src_ip = ip_packet.srcip.toStr().split(".") [3]
dst_ip = ip_packet.dstip.toStr().split(".") [3]
log.debug("IP src= %s IP dst= %s" %(src_ip, dst_ip))
self.path=[]
dijkstra(self.graph, dst_ip, src_ip)
print(self.path)
dpid = dpid_to_str(event.dpid).split("-")[5][1] for index in range(len(self.path)):
if dpid is self.path[index]:
if self.path[index] is self.path[-1]: msg = of.ofp_flow_mod()
msg.match =
of.ofp_match.from_packet(packet, event.port)
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = self.host[dpid]))
Trang 16else:
msg = of.ofp_flow_mod()
msg.match =
of.ofp_match.from_packet(packet, event.port)
msg.idle_timeout = 10
msg.hard_timeout = 30
msg.actions.append(of.ofp_action_output(port = self.graph[self.path[index]][self.path[index+1]])) msg.data = event.ofp
self.connection.send(msg)
class l3_routing (object):
def init (self, transparent):
core.openflow.addListeners(self)
self.transparent = transparent
def _handle_ConnectionUp (self, event):
log.debug("Connection %s" % (event.connection,)) L3Routing(event.connection, self.transparent)
def launch (transparent=False,
hold_down=_flood_delay):
"""
Starts an L3 routing
"""
try:
global _flood_delay
Trang 17except:
raise RuntimeError("Expected hold-down to be a number")
core.registerNew(l3_routing,
str_to_bool(transparent))
2 Ở module định tuyến tại sao cần phải xử lý gói tin ARP?
- Các gói tin IP không được gửi trực tiếp mà được bỏ vào một khung rồi mới gửi
đi, khung này có địa chỉ gửi và địa chỉ đích Các địa chỉ này là địa chỉ MAC (vật lý) của một card mạng Một card mạng nhận các khung có địa chỉ đích là địa chỉ MAC của mình ARP là giao thức phân giải địa chỉ, kết nối giữa IP và MAC nên cần phải xử lý gói tin ARP
Trang 18BÀI 7: MỘT SỐ ỨNG DỤNG MẠNG – FIREWALL
1 Khi topology có loop, trên POX cần chạy module gì để mạng có thể hoạt động ổn định?
- Khi topology có loop, trên POX cần chạy module openflow spanning trê để không bị loop, mạng hoạt động ổn định