git clone http://github.com/osrg/ryu.git
内置的ryu应用程序
base中有一个非常重要的文件:app_manager.py,其作用是RYU应用的管理中心。用于加载RYU应用程序,接受从APP发送过来的信息,同时也完成消息的路由。
其主要的函数有app注册、注销、查找、并定义了RYUAPP基类,定义了RYUAPP的基本属性。包含name, threads, events, event_handlers和observers等成员,以及对应的许多基本函数。如:start(), stop()等。
这个文件中还定义了AppManager基类,用于管理APP。定义了加载APP等函数。不过如果仅仅是开发APP的话,这个类可以不必关心。
定义了RYU的命令系统
这个文件夹主要存放的是开源社区贡献者的代码
controller文件夹中许多非常重要的文件,如 events.py ,ofp_handler.py, controller.py等。其中controller.py中定义了OpenFlowController基类。用于定义OpenFlow的控制器,用于处理交换机和控制器的连接等事件,同时还可以产生事件和路由事件。
其事件系统的定义,可以查看events.py和ofp_events.py。
在ofp_handler.py中定义了基本的handler,完成了基本的如:握手,错误信息处理和keep alive 等功能。
在dpset.py文件中,定义了交换机端的一些消息,如端口状态信息等,用于描述和操作交换机。如添加端口,删除端口等操作。
lib中定义了我们需要使用到的基本的数据结构,如dpid, mac和ip等数据结构。在lib/packet目录下,还定义了许多网络协议,如ICMP, DHCP, MPLS和IGMP等协议内容。而每一个数据包的类中都有parser和serialize两个函数。用于解析和序列化数据包
协议的数据格式,如何处理数据包
包含了switches.py等文件,基本定义了一套交换机的数据结构。
3. 源码解析
因为时间关系,所以很多的代码我还没有细看,就只把用到的模块贴出来了
**rest_router.py**
class RestRouterAPI(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_0.OFP_VERSION,
ofproto_v1_2.OFP_VERSION,
ofproto_v1_3.OFP_VERSION]
# 调用wsgi模块来创建wsgi架构,提供web服务
_CONTEXTS = {'dpset': dpset.DPSet,
'wsgi': WSGIApplication}
def __init__(self, *args, **kwargs):
super(RestRouterAPI, self).__init__(*args, **kwargs)
# logger configure
RouterController.set_logger(self.logger)
wsgi = kwargs['wsgi']
self.waiters = {}
self.data = {'waiters': self.waiters}
mapper = wsgi.mapper
wsgi.registory['RouterController'] = self.data
requirements = {'switch_id': SWITCHID_PATTERN,
'vlan_id': VLANID_PATTERN}
# For no vlan data
path = '/router/{switch_id}'
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='get_data',
conditions=dict(method=['GET']))
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='set_data',
conditions=dict(method=['POST']))
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='delete_data',
conditions=dict(method=['DELETE']))
# For vlan data
path = '/router/{switch_id}/{vlan_id}'
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='get_vlan_data',
conditions=dict(method=['GET']))
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='set_vlan_data',
conditions=dict(method=['POST']))
mapper.connect('router', path, controller=RouterController,
requirements=requirements,
action='delete_vlan_data',
conditions=dict(method=['DELETE']))
# 为每一个连接的ovs交换机创建一个router,并存储在_ROUTE_LIST中
@set_ev_cls(dpset.EventDP, dpset.DPSET_EV_DISPATCHER)
def datapath_handler(self, ev):
if ev.enter:
RouterController.register_router(ev.dp)
else:
RouterController.unregister_router(ev.dp)
# 处理收到的数据包
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def packet_in_handler(self, ev):
RouterController.packet_in_handler(ev.msg)
def _stats_reply_handler(self, ev):
msg = ev.msg
dp = msg.datapath
if (dp.id not in self.waiters
or msg.xid not in self.waiters[dp.id]):
return
event, msgs = self.waiters[dp.id][msg.xid]
msgs.append(msg)
if ofproto_v1_3.OFP_VERSION == dp.ofproto.OFP_VERSION:
more = dp.ofproto.OFPMPF_REPLY_MORE
else:
more = dp.ofproto.OFPSF_REPLY_MORE
if msg.flags & more:
return
del self.waiters[dp.id][msg.xid]
event.set()
# for OpenFlow version1.0
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def stats_reply_handler_v1_0(self, ev):
self._stats_reply_handler(ev)
# for OpenFlow version1.2/1.3
@set_ev_cls(ofp_event.EventOFPStatsReply, MAIN_DISPATCHER)
def stats_reply_handler_v1_2(self, ev):
self._stats_reply_handler(ev)
# TODO: Update routing table when port status is changed.
# 提供一个RouterController作为总路由器控制程序
class RouterController(ControllerBase):
# 存储所有的交换机
_ROUTER_LIST = {}
_LOGGER = None
def __init__(self, req, link, data, **config):
super(RouterController, self).__init__(req, link, data, **config)
self.waiters = data['waiters']
@classmethod
def set_logger(cls, logger):
cls._LOGGER = logger
cls._LOGGER.propagate = False
hdlr = logging.StreamHandler()
fmt_str = '[RT][%(levelname)s] switch_id=%(sw_id)s: %(message)s'
hdlr.setFormatter(logging.Formatter(fmt_str))
cls._LOGGER.addHandler(hdlr)
# 连接新的交换机
@classmethod
def register_router(cls, dp):
dpid = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
try:
router = Router(dp, cls._LOGGER)
except OFPUnknownVersion as message:
cls._LOGGER.error(str(message), extra=dpid)
return
cls._ROUTER_LIST.setdefault(dp.id, router)
cls._LOGGER.info('Join as router.', extra=dpid)
@classmethod
def unregister_router(cls, dp):
if dp.id in cls._ROUTER_LIST:
cls._ROUTER_LIST[dp.id].delete()
del cls._ROUTER_LIST[dp.id]
dpid = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
cls._LOGGER.info('Leave router.', extra=dpid)
# 当收到packet-in数据包后,因为msg.datapath可以描述我们收到这个OpenFlow消息的交换机信息,所以利用dpid找到对应的router来处理packet-in
@classmethod
def packet_in_handler(cls, msg):
dp_id = msg.datapath.id
if dp_id in cls._ROUTER_LIST:
router = cls._ROUTER_LIST[dp_id]
router.packet_in_handler(msg)
# 提供GET、POST、DELETE等网络服务
# GET /router/{switch_id}
@rest_command
def get_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'get_data', req)
# GET /router/{switch_id}/{vlan_id}
@rest_command
def get_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'get_data', req)
# POST /router/{switch_id}
@rest_command
def set_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'set_data', req)
# POST /router/{switch_id}/{vlan_id}
@rest_command
def set_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'set_data', req)
# DELETE /router/{switch_id}
@rest_command
def delete_data(self, req, switch_id, **_kwargs):
return self._access_router(switch_id, VLANID_NONE,
'delete_data', req)
# DELETE /router/{switch_id}/{vlan_id}
@rest_command
def delete_vlan_data(self, req, switch_id, vlan_id, **_kwargs):
return self._access_router(switch_id, vlan_id,
'delete_data', req)
def _access_router(self, switch_id, vlan_id, func, req):
rest_message = []
routers = self._get_router(switch_id)
try:
param = req.json if req.body else {}
except ValueError:
raise SyntaxError('invalid syntax %s', req.body)
for router in routers.values():
function = getattr(router, func)
data = function(vlan_id, param, self.waiters)
rest_message.append(data)
return rest_message
def _get_router(self, switch_id):
routers = {}
if switch_id == REST_ALL:
routers = self._ROUTER_LIST
else:
sw_id = dpid_lib.str_to_dpid(switch_id)
if sw_id in self._ROUTER_LIST:
routers = {sw_id: self._ROUTER_LIST[sw_id]}
if routers:
return routers
else:
raise NotFoundError(switch_id=switch_id)
#就是根据相应的vlan调取VlanRouter
class Router(object):
class VlanRouter(object):
def __init__(self, vlan_id, dp, port_data, logger):
super(VlanRouter, self).__init__()
self.vlan_id = vlan_id
self.dp = dp
self.sw_id = {'sw_id': dpid_lib.dpid_to_str(dp.id)}
self.logger = logger
self.port_data = port_data
self.address_data = AddressData()
self.routing_tbl = RoutingTable()
self.packet_buffer = SuspendPacketList(self.send_icmp_unreach_error)
self.ofctl = OfCtl.factory(dp, logger)
# Set flow: default route (drop)
self._set_defaultroute_drop()
def delete(self, waiters):
# Delete flow.
msgs = self.ofctl.get_all_flow(waiters)
for msg in msgs:
for stats in msg.body:
vlan_id = VlanRouter._cookie_to_id(REST_VLANID, stats.cookie)
if vlan_id == self.vlan_id:
self.ofctl.delete_flow(stats)
assert len(self.packet_buffer) == 0
@staticmethod
def _cookie_to_id(id_type, cookie):
def _id_to_cookie(self, id_type, rest_id):
def _get_priority(self, priority_type, route=None):
return get_priority(priority_type, vid=self.vlan_id, route=route)
def _response(self, msg):
if msg and self.vlan_id:
msg.setdefault(REST_VLANID, self.vlan_id)
return msg
def get_data(self):
# 为GET提供数据
def _get_address_data(self):
# 获取地址信息
def _get_routing_data(self):
# 获取路由信息
def set_data(self, data):
details = None
try:
# Set address data
if REST_ADDRESS in data:
address = data[REST_ADDRESS]
address_id = self._set_address_data(address)
details = 'Add address [address_id=%d]' % address_id
# Set routing data
elif REST_GATEWAY in data:
gateway = data[REST_GATEWAY]
if REST_DESTINATION in data:
destination = data[REST_DESTINATION]
else:
destination = DEFAULT_ROUTE
route_id = self._set_routing_data(destination, gateway)
details = 'Add route [route_id=%d]' % route_id
except CommandFailure as err_msg:
msg = {REST_RESULT: REST_NG, REST_DETAILS: str(err_msg)}
return self._response(msg)
if details is not None:
msg = {REST_RESULT: REST_OK, REST_DETAILS: details}
return self._response(msg)
else:
raise ValueError('Invalid parameter.')
def _set_address_data(self, address):
# 将address存储在address_data中,并下发流表信息,最后发送GARP
address = self.address_data.add(address)
cookie = self._id_to_cookie(REST_ADDRESSID, address.address_id)
# Set flow: host MAC learning (packet in)
priority = self._get_priority(PRIORITY_MAC_LEARNING)
self.ofctl.set_packetin_flow(cookie, priority,
dl_type=ether.ETH_TYPE_IP,
dl_vlan=self.vlan_id,
dst_ip=address.nw_addr,
dst_mask=address.netmask)
log_msg = 'Set host MAC learning (packet in) flow [cookie=0x%x]'
self.logger.info(log_msg, cookie, extra=self.sw_id)
# set Flow: IP handling(PacketIn)
priority = self._get_priority(PRIORITY_IP_HANDLING)
self.ofctl.set_packetin_flow(cookie, priority,
dl_type=ether.ETH_TYPE_IP,
dl_vlan=self.vlan_id,
dst_ip=address.default_gw)
self.logger.info('Set IP handling (packet in) flow [cookie=0x%x]',
cookie, extra=self.sw_id)
# Set flow: L2 switching (normal)
outport = self.ofctl.dp.ofproto.OFPP_NORMAL
priority = self._get_priority(PRIORITY_L2_SWITCHING)
self.ofctl.set_routing_flow(
cookie, priority, outport, dl_vlan=self.vlan_id,
nw_src=address.nw_addr, src_mask=address.netmask,
nw_dst=address.nw_addr, dst_mask=address.netmask)
self.logger.info('Set L2 switching (normal) flow [cookie=0x%x]',
cookie, extra=self.sw_id)
# Send GARP
self.send_arp_request(address.default_gw, address.default_gw)
return address.address_id
def _set_routing_data(self, destination, gateway):
# 判断网关地址是否为合法网段以及是否已被占用后,将信息存储在routing_table中,并下发流表(dst为目的地址的时候交给控制器处理),发送arp请求获取网关地址的mac
err_msg = 'Invalid [%s] value.' % REST_GATEWAY
dst_ip = ip_addr_aton(gateway, err_msg=err_msg)
address = self.address_data.get_data(ip=dst_ip)
if address is None:
msg = 'Gateway=%s\'s address is not registered.' % gateway
raise CommandFailure(msg=msg)
elif dst_ip == address.default_gw:
msg = 'Gateway=%s is used as default gateway of address_id=%d'\
% (gateway, address.address_id)
raise CommandFailure(msg=msg)
else:
src_ip = address.default_gw
route = self.routing_tbl.add(destination, gateway)
self._set_route_packetin(route)
self.send_arp_request(src_ip, dst_ip)
return route.route_id
def _set_defaultroute_drop(self):
# 设置一条默认drop的流表
def _set_route_packetin(self, route):
# 将匹配到dst_ip,dst_mask的数据包交给控制器处理
cookie = self._id_to_cookie(REST_ROUTEID, route.route_id)
priority, log_msg = self._get_priority(PRIORITY_TYPE_ROUTE,
route=route)
self.ofctl.set_packetin_flow(cookie, priority,
dl_type=ether.ETH_TYPE_IP,
dl_vlan=self.vlan_id,
dst_ip=route.dst_ip,
dst_mask=route.netmask)
self.logger.info('Set %s (packet in) flow [cookie=0x%x]', log_msg,
cookie, extra=self.sw_id)
def delete_data(self, data, waiters):
if REST_ROUTEID in data:
route_id = data[REST_ROUTEID]
msg = self._delete_routing_data(route_id, waiters)
elif REST_ADDRESSID in data:
address_id = data[REST_ADDRESSID]
msg = self._delete_address_data(address_id, waiters)
else:
raise ValueError('Invalid parameter.')
return self._response(msg)
def _delete_address_data(self, address_id, waiters):
def _delete_routing_data(self, route_id, waiters):
def _chk_addr_relation_route(self, address_id):
# Check exist of related routing data.
relate_list = []
gateways = self.routing_tbl.get_gateways()
for gateway in gateways:
address = self.address_data.get_data(ip=gateway)
if address is not None:
if (address_id == REST_ALL
and address.address_id not in relate_list):
relate_list.append(address.address_id)
elif address.address_id == address_id:
relate_list = [address_id]
break
return relate_list
def packet_in_handler(self, msg, header_list):
# handle packet in
# Check invalid TTL (for OpenFlow V1.2/1.3)
ofproto = self.dp.ofproto
if ofproto.OFP_VERSION == ofproto_v1_2.OFP_VERSION or \
ofproto.OFP_VERSION == ofproto_v1_3.OFP_VERSION:
if msg.reason == ofproto.OFPR_INVALID_TTL:
self._packetin_invalid_ttl(msg, header_list)
return
# Analyze event type.
# ARP
if ARP in header_list:
self._packetin_arp(msg, header_list)
return
# IPv4
if IPV4 in header_list:
rt_ports = self.address_data.get_default_gw()
# 判断是否是发送给router的数据包
if header_list[IPV4].dst in rt_ports:
# Packet to router's port.
if ICMP in header_list:
if header_list[ICMP].type == icmp.ICMP_ECHO_REQUEST:
self._packetin_icmp_req(msg, header_list)
return
elif TCP in header_list or UDP in header_list:
self._packetin_tcp_udp(msg, header_list)
return
else:
# 认为是发送给网关或者内部主机的数据包
self._packetin_to_node(msg, header_list)
return
def _packetin_arp(self, msg, header_list):
# 判断源地址是否与router处于同一网段
src_addr = self.address_data.get_data(ip=header_list[ARP].src_ip)
if src_addr is None:
return
# 能收到arp的情况仅为两种:网关节点或者相连的终端
# 如果是网关节点,则更新路由表中和流表项
# 如果是相连的终端,则为该终端下发相应的流表
gw_flg = self._update_routing_tbl(msg, header_list)
if gw_flg is False:
self._learning_host_mac(msg, header_list)
# ARP packet handling.
in_port = self.ofctl.get_packetin_inport(msg)
src_ip = header_list[ARP].src_ip
dst_ip = header_list[ARP].dst_ip
srcip = ip_addr_ntoa(src_ip)
dstip = ip_addr_ntoa(dst_ip)
rt_ports = self.address_data.get_default_gw()
# 如果是GARP,则正常转发
if src_ip == dst_ip:
# GARP -> packet forward (normal)
output = self.ofctl.dp.ofproto.OFPP_NORMAL
self.ofctl.send_packet_out(in_port, output, msg.data)
self.logger.info('Receive GARP from [%s].', srcip,
extra=self.sw_id)
self.logger.info('Send GARP (normal).', extra=self.sw_id)
# 如果目的地址不包含在当前路由器内
elif dst_ip not in rt_ports:
dst_addr = self.address_data.get_data(ip=dst_ip)
# 判断目的地址是否和路由器在同一网段
if (dst_addr is not None and
src_addr.address_id == dst_addr.address_id):
# ARP from internal host -> packet forward (normal)
output = self.ofctl.dp.ofproto.OFPP_NORMAL
self.ofctl.send_packet_out(in_port, output, msg.data)
self.logger.info('Receive ARP from an internal host [%s].',
srcip, extra=self.sw_id)
self.logger.info('Send ARP (normal)', extra=self.sw_id)
else:
if header_list[ARP].opcode == arp.ARP_REQUEST:
# 发送arp reply
elif header_list[ARP].opcode == arp.ARP_REPLY:
# ARP reply to router port -> suspend packets forward
log_msg = 'Receive ARP reply from [%s] to router port [%s].'
self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
packet_list = self.packet_buffer.get_data(src_ip)
if packet_list:
# stop ARP reply wait thread.
for suspend_packet in packet_list:
self.packet_buffer.delete(pkt=suspend_packet)
# send suspend packet.
output = self.ofctl.dp.ofproto.OFPP_TABLE
for suspend_packet in packet_list:
self.ofctl.send_packet_out(suspend_packet.in_port,
output,
suspend_packet.data)
self.logger.info('Send suspend packet to [%s].',
srcip, extra=self.sw_id)
def _packetin_icmp_req(self, msg, header_list):
# Send ICMP echo reply.
def _packetin_tcp_udp(self, msg, header_list):
# Send ICMP port unreach error.
in_port = self.ofctl.get_packetin_inport(msg)
self.ofctl.send_icmp(in_port, header_list, self.vlan_id,
icmp.ICMP_DEST_UNREACH,
icmp.ICMP_PORT_UNREACH_CODE,
msg_data=msg.data)
srcip = ip_addr_ntoa(header_list[IPV4].src)
dstip = ip_addr_ntoa(header_list[IPV4].dst)
self.logger.info('Receive TCP/UDP from [%s] to router port [%s].',
srcip, dstip, extra=self.sw_id)
self.logger.info('Send ICMP destination unreachable to [%s].', srcip,
extra=self.sw_id)
# 当收到发送给网关和相连主机的数据包时,发送arp请求
def _packetin_to_node(self, msg, header_list):
if len(self.packet_buffer) >= MAX_SUSPENDPACKETS:
self.logger.info('Packet is dropped, MAX_SUSPENDPACKETS exceeded.',
extra=self.sw_id)
return
# Send ARP request to get node MAC address.
in_port = self.ofctl.get_packetin_inport(msg)
src_ip = None
dst_ip = header_list[IPV4].dst
srcip = ip_addr_ntoa(header_list[IPV4].src)
dstip = ip_addr_ntoa(dst_ip)
address = self.address_data.get_data(ip=dst_ip)
if address is not None:
log_msg = 'Receive IP packet from [%s] to an internal host [%s].'
self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
src_ip = address.default_gw
else:
route = self.routing_tbl.get_data(dst_ip=dst_ip)
if route is not None:
log_msg = 'Receive IP packet from [%s] to [%s].'
self.logger.info(log_msg, srcip, dstip, extra=self.sw_id)
gw_address = self.address_data.get_data(ip=route.gateway_ip)
if gw_address is not None:
src_ip = gw_address.default_gw
dst_ip = route.gateway_ip
if src_ip is not None:
self.packet_buffer.add(in_port, header_list, msg.data)
self.send_arp_request(src_ip, dst_ip, in_port=in_port)
self.logger.info('Send ARP request (flood)', extra=self.sw_id)
def _packetin_invalid_ttl(self, msg, header_list):
# Send ICMP TTL error.
srcip = ip_addr_ntoa(header_list[IPV4].src)
self.logger.info('Receive invalid ttl packet from [%s].', srcip,
extra=self.sw_id)
in_port = self.ofctl.get_packetin_inport(msg)
src_ip = self._get_send_port_ip(header_list)
if src_ip is not None:
self.ofctl.send_icmp(in_port, header_list, self.vlan_id,
icmp.ICMP_TIME_EXCEEDED,
icmp.ICMP_TTL_EXPIRED_CODE,
msg_data=msg.data, src_ip=src_ip)
self.logger.info('Send ICMP time exceeded to [%s].', srcip,
extra=self.sw_id)
def send_arp_all_gw(self):
向所有的网关发送arp请求
def send_arp_request(self, src_ip, dst_ip, in_port=None):
# Send ARP request from all ports.
for send_port in self.port_data.values():
if in_port is None or in_port != send_port.port_no:
src_mac = send_port.mac
dst_mac = mac_lib.BROADCAST_STR
arp_target_mac = mac_lib.DONTCARE_STR
inport = self.ofctl.dp.ofproto.OFPP_CONTROLLER
output = send_port.port_no
self.ofctl.send_arp(arp.ARP_REQUEST, self.vlan_id,
src_mac, dst_mac, src_ip, dst_ip,
arp_target_mac, inport, output)
def send_icmp_unreach_error(self, packet_buffer):
# Send ICMP host unreach error.
self.logger.info('ARP reply wait timer was timed out.',
extra=self.sw_id)
src_ip = self._get_send_port_ip(packet_buffer.header_list)
if src_ip is not None:
self.ofctl.send_icmp(packet_buffer.in_port,
packet_buffer.header_list,
self.vlan_id,
icmp.ICMP_DEST_UNREACH,
icmp.ICMP_HOST_UNREACH_CODE,
msg_data=packet_buffer.data,
src_ip=src_ip)
dstip = ip_addr_ntoa(packet_buffer.dst_ip)
self.logger.info('Send ICMP destination unreachable to [%s].',
dstip, extra=self.sw_id)
# 更新路由表和流表项
def _update_routing_tbl(self, msg, header_list):
# Set flow: routing to gateway.
out_port = self.ofctl.get_packetin_inport(msg)
src_mac = header_list[ARP].src_mac
dst_mac = self.port_data[out_port].mac
src_ip = header_list[ARP].src_ip
gateway_flg = False
for key, value in self.routing_tbl.items():
if value.gateway_ip == src_ip:
gateway_flg = True
if value.gateway_mac == src_mac:
continue
self.routing_tbl[key].gateway_mac = src_mac
cookie = self._id_to_cookie(REST_ROUTEID, value.route_id)
priority, log_msg = self._get_priority(PRIORITY_TYPE_ROUTE,
route=value)
self.ofctl.set_routing_flow(cookie, priority, out_port,
dl_vlan=self.vlan_id,
src_mac=dst_mac,
dst_mac=src_mac,
nw_dst=value.dst_ip,
dst_mask=value.netmask,
dec_ttl=True)
self.logger.info('Set %s flow [cookie=0x%x]', log_msg, cookie,
extra=self.sw_id)
return gateway_flg
# 为路由表中没有存储的gateway地址下发流表项
def _learning_host_mac(self, msg, header_list):
# Set flow: routing to internal Host.
out_port = self.ofctl.get_packetin_inport(msg)
src_mac = header_list[ARP].src_mac
dst_mac = self.port_data[out_port].mac
src_ip = header_list[ARP].src_ip
gateways = self.routing_tbl.get_gateways()
if src_ip not in gateways:
address = self.address_data.get_data(ip=src_ip)
if address is not None:
cookie = self._id_to_cookie(REST_ADDRESSID, address.address_id)
priority = self._get_priority(PRIORITY_IMPLICIT_ROUTING)
self.ofctl.set_routing_flow(cookie, priority,
out_port, dl_vlan=self.vlan_id,
src_mac=dst_mac, dst_mac=src_mac,
nw_dst=src_ip,
idle_timeout=IDLE_TIMEOUT,
dec_ttl=True)
self.logger.info('Set implicit routing flow [cookie=0x%x]',
cookie, extra=self.sw_id)
def _get_send_port_ip(self, header_list):
try:
src_mac = header_list[ETHERNET].src
if IPV4 in header_list:
src_ip = header_list[IPV4].src
else:
src_ip = header_list[ARP].src_ip
except KeyError:
self.logger.debug('Receive unsupported packet.', extra=self.sw_id)
return None
address = self.address_data.get_data(ip=src_ip)
if address is not None:
return address.default_gw
else:
route = self.routing_tbl.get_data(gw_mac=src_mac)
if route is not None:
address = self.address_data.get_data(ip=route.gateway_ip)
if address is not None:
return address.default_gw
self.logger.debug('Receive packet from unknown IP[%s].',
ip_addr_ntoa(src_ip), extra=self.sw_id)