def _port_del(self, ev): # free mac addresses associated to this VM port, # and delete related flow entries for later reuse of mac address dps_needs_barrier = set() msg = ev.msg datapath = msg.datapath datapath_id = datapath.id port_no = msg.desc.port_no rule = nx_match.ClsRule() rule.set_in_port(port_no) datapath.send_flow_del(rule=rule, cookie=0) rule = nx_match.ClsRule() datapath.send_flow_del(rule=rule, cookie=0, out_port=port_no) dps_needs_barrier.add(datapath) try: port_nw_id = self.nw.get_network(datapath_id, port_no) except PortUnknown: # race condition between rest api delete port # and openflow port deletion ofp_event pass else: if port_nw_id in (NW_ID_UNKNOWN, NW_ID_EXTERNAL): datapath.send_barrier() return for mac_ in self.mac2port.mac_list(datapath_id, port_no): for (_dpid, dp) in self.dpset.get_all(): if self.mac2port.port_get(dp.id, mac_) is None: continue rule = nx_match.ClsRule() rule.set_dl_src(mac_) dp.send_flow_del(rule=rule, cookie=0) rule = nx_match.ClsRule() rule.set_dl_dst(mac_) dp.send_flow_del(rule=rule, cookie=0) dps_needs_barrier.add(dp) self.mac2port.mac_del(dp.id, mac_) self.mac2net.del_mac(mac_) self.nw.port_deleted(datapath.id, port_no) for dp in dps_needs_barrier: dp.send_barrier()
def state_change_handler(self, ev): dp = ev.datapath assert dp is not None LOG.debug(dp) if ev.state == MAIN_DISPATCHER: self._register(dp) switch = self._get_switch(dp.id) LOG.debug('register %s', switch) self.send_event_to_observers(event.EventSwitchEnter(switch)) if not self.link_discovery: return if self.install_flow: ofproto = dp.ofproto ofproto_parser = dp.ofproto_parser # TODO:XXX need other versions if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: rule = nx_match.ClsRule() rule.set_dl_dst( addrconv.mac.text_to_bin(lldp.LLDP_MAC_NEAREST_BRIDGE)) rule.set_dl_type(ETH_TYPE_LLDP) actions = [ ofproto_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, self.LLDP_PACKET_LEN) ] dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions) else: LOG.error('cannot install flow. unsupported version. %x', dp.ofproto.OFP_VERSION) for port in switch.ports: if not port.is_reserved(): self._port_added(port) self.lldp_event.set() elif ev.state == DEAD_DISPATCHER: # dp.id is None when datapath dies before handshake if dp.id is None: return switch = self._get_switch(dp.id) self._unregister(dp) LOG.debug('unregister %s', switch) self.send_event_to_observers(event.EventSwitchLeave(switch)) if not self.link_discovery: return for port in switch.ports: if not port.is_reserved(): self.ports.del_port(port) self._link_down(port) self.lldp_event.set()
def test_rule_set_in_port(self, dp): in_port = 32 self._verify = ['in_port', in_port] rule = nx_match.ClsRule() rule.set_in_port(in_port) self.add_rule(dp, rule)
def test_rule_set_dl_type_lacp(self, dp): dl_type = ether.ETH_TYPE_SLOW self._verify = ['dl_type', dl_type] rule = nx_match.ClsRule() rule.set_dl_type(dl_type) self.add_rule(dp, rule)
def add_action(self, dp, action, rule = None): if rule is None: rule = nx_match.ClsRule() self.send_flow_mod( dp, rule, 0, dp.ofproto.OFPFC_ADD, 0, 0, None, 0xffffffff, None, dp.ofproto.OFPFF_SEND_FLOW_REM, action)
def _pre_install_flow_entry(self, switch): # 'switch' is a Switch object # add flow entry for BGP, both IPv4 and IPv6 rule4 = nx_match.ClsRule() rule4.set_dl_type(ether.ETH_TYPE_IP) rule4.set_nw_proto(inet.IPPROTO_TCP) rule4.set_tp_dst(BGP4.BGP_TCP_PORT) rule6 = nx_match.ClsRule() rule6.set_dl_type(ether.ETH_TYPE_IPV6) rule6.set_nw_proto(inet.IPPROTO_TCP) rule6.set_tp_dst(BGP4.BGP_TCP_PORT) actions = [] actions.append( switch.dp.ofproto_parser.OFPActionOutput( port=ofproto_v1_0.OFPP_CONTROLLER, # 0 means "omit all the packet content", and # 65535(0xffff) is the max len could be assigned max_len=65535)) msg4 = switch.dp.ofproto_parser.NXTFlowMod( datapath=switch.dp, cookie=0, command=switch.dp.ofproto.OFPFC_MODIFY, # 0 timeout means no timeout idle_timeout=0, hard_timeout=0, out_port=ofproto_v1_0.OFPP_CONTROLLER, rule=rule4, actions=actions) msg6 = switch.dp.ofproto_parser.NXTFlowMod( datapath=switch.dp, cookie=0, command=switch.dp.ofproto.OFPFC_MODIFY, idle_timeout=0, hard_timeout=0, out_port=ofproto_v1_0.OFPP_CONTROLLER, rule=rule6, actions=actions) switch.dp.send_msg(msg4) switch.dp.send_msg(msg6) LOG.debug('Pre-installed flow entry')
def test_rule_set_dl_src(self, dp): dl_src = 'b8:a1:94:51:78:83' dl_src_bin = self.haddr_to_bin(dl_src) self._verify = ['dl_src', dl_src_bin] rule = nx_match.ClsRule() rule.set_dl_src(dl_src_bin) self.add_rule(dp, rule)
def _port_flow_add(self, dp, port_no): self.logger.debug('ovs_port_update dpid %s port_no %s', dpid_lib.dpid_to_str(dp.id), port_no) rule = nx_match.ClsRule() rule.set_in_port(port_no) ofproto = dp.ofproto actions = [dp.ofproto_parser.OFPActionOutput(ofproto.OFPP_NORMAL)] dp.send_flow_mod(rule=rule, cookie=self._COOKIE_NORMAL, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=self._PRIORITY_NORMAL, actions=actions)
def port_state_change_handler(self, ev): dp = ev.datapath assert dp is not None LOG.debug(dp) ev.state = MAIN_DISPATCHER self.install_flow = True if self.install_flow: ofproto = dp.ofproto ofproto_parser = dp.ofproto_parser # TODO:XXX need other versions if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: rule = nx_match.ClsRule() rule.set_dl_dst( addrconv.mac.text_to_bin(lldp.LLDP_MAC_NEAREST_BRIDGE)) rule.set_dl_type(ETH_TYPE_LLDP) actions = [ ofproto_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, self.LLDP_PACKET_LEN) ] dp.send_flow_mod(rule=rule, cookie=self.LLDP_FLOW_COOKIE, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions, priority=0xFFFF) elif ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: match = ofproto_parser.OFPMatch( eth_type=ETH_TYPE_LLDP, eth_dst=lldp.LLDP_MAC_NEAREST_BRIDGE) # OFPCML_NO_BUFFER is set so that the LLDP is not # buffered on switch parser = ofproto_parser actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] inst = [ parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) ] mod = parser.OFPFlowMod(datapath=dp, match=match, cookie=self.LLDP_FLOW_COOKIE, idle_timeout=0, hard_timeout=0, instructions=inst, priority=0xFFFF) dp.send_msg(mod) else: LOG.error('cannot install flow. unsupported version. %x', dp.ofproto.OFP_VERSION)
def cls_rule(in_port=None, tun_id=None, dl_src=None, dl_dst=None): """Convenience function to initialize nx_match.ClsRule()""" rule = nx_match.ClsRule() if in_port is not None: rule.set_in_port(in_port) if tun_id is not None: rule.set_tun_id(tun_id) if dl_src is not None: rule.set_dl_src(dl_src) if dl_dst is not None: rule.set_dl_dst(dl_dst) return rule
def send_delete_all_flows(self): rule = nx_match.ClsRule() self.send_flow_mod(rule=rule, cookie=0, command=self.ofproto.OFPFC_DELETE, idle_timeout=0, hard_timeout=0, priority=0, buffer_id=0, out_port=self.ofproto.OFPP_NONE, flags=0, actions=None)
def packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto rule = nx_match.ClsRule() datapath.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=ofproto.OFP_DEFAULT_PRIORITY, flags=0, actions=None)
def dp_handler(self, ev): if not ev.enter: return dp = ev.dp rule = nx_match.ClsRule() ofproto = dp.ofproto dp.send_flow_mod(rule=rule, cookie=self._COOKIE_CATCHALL, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=self._PRIORITY_CATCHALL, actions=[]) for port in ev.ports: self._port_add(dp, port.port_no)
def _modflow_and_send_packet(msg, src, dst, actions): datapath = msg.datapath ofproto = datapath.ofproto # # install flow and then send packet # rule = nx_match.ClsRule() rule.set_in_port(msg.in_port) rule.set_dl_dst(dst) rule.set_dl_src(src) datapath.send_flow_mod( rule=rule, cookie=0, command=datapath.ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=ofproto.OFP_DEFAULT_PRIORITY, buffer_id=0xffffffff, out_port=ofproto.OFPP_NONE, flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions) datapath.send_packet_out(msg.buffer_id, msg.in_port, actions)
def set_switch_flow(self, datapath, src_mac, k_id): dpid = datapath.id outport_list = self.Topo.switch_outport(src_mac, dpid, k_id) # Set rule rule = nx_match.ClsRule() rule.set_dl_type(ether.ETH_TYPE_IP) ## match camera MAC #rule.set_dl_src( haddr_to_bin(src_mac) ) src_id = int(src_mac.replace(':', ''), 16) nw_src = self.Topo.convert_host_id_to_ip(src_id) rule.set_nw_src(self.ipv4_to_int(nw_src)) ## match IP with descriptor K nw_dst = self.Topo.convert_k_id_to_ip(k_id) ## Discard IP phase 4: reserved for sender rule.set_nw_dst_masked(self.ipv4_to_int(nw_dst), self.ipv4_to_int("255.255.255.0")) self.logger.info("!!! --- K = %s, dst_ip = %s", str(k_id), nw_dst) # Duplicate packet action_list = [] for port in outport_list: action = datapath.ofproto_parser.OFPActionOutput(port) action_list.append(action) self.logger.info("!!! ----- Add port: %s", port) # Deal with different type of switch if len(action_list) > 0: # At least one output if self.Topo.switch_type(dpid) == 0: # Switch - on the way pass else: # Switch - the last hop # Set broadcast MAC dl_dst = 'ff:ff:ff:ff:ff:ff' dl_dst_bin = haddr_to_bin(dl_dst) action = datapath.ofproto_parser.OFPActionSetDlDst( dl_dst_bin) action_list.append(action) # Send action self.add_action(datapath, action_list, rule=rule)
def generate_add_flowmod(in_port=None): if in_port is None: in_port = 32 rule = nx_match.ClsRule() rule.set_in_port(in_port) match_tuple = rule.match_tuple() match = ofproto_v1_0_parser.OFPMatch(*match_tuple) cookie = 0 command = ofproto_v1_0.OFPFC_ADD idle_timeout = 0 hard_timeout = 0 priority = ofproto_v1_0.OFP_DEFAULT_PRIORITY buffer_id = 0xffffffff out_port = ofproto_v1_0.OFPP_NONE flags = 0 actions = None datapath = OF_1_0_DATAPATH return ofproto_v1_0_parser.OFPFlowMod(datapath, match, cookie, command, idle_timeout, hard_timeout, priority, buffer_id, out_port, flags, actions)
def _packet_in_handler(self, ev): msg = ev.msg datapath = msg.datapath ofproto = datapath.ofproto dst, src, _eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) dpid = datapath.id self.mac2port.dpid_add(dpid) LOG.info("packet in %s %s %s %s", dpid, haddr_to_str(src), haddr_to_str(dst), msg.in_port) self.mac2port.port_add(dpid, msg.in_port, src) out_port = self.mac2port.port_get(dpid, dst) if out_port == None: LOG.info("out_port not found") out_port = ofproto.OFPP_FLOOD actions = [datapath.ofproto_parser.OFPActionOutput(out_port)] if out_port != ofproto.OFPP_FLOOD: rule = nx_match.ClsRule() rule.set_in_port(msg.in_port) rule.set_dl_dst(dst) rule.set_dl_type(nx_match.ETH_TYPE_IP) rule.set_nw_dscp(0) datapath.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=ofproto.OFP_DEFAULT_PRIORITY, flags=ofproto.OFPFF_SEND_FLOW_REM, actions=actions) datapath.send_packet_out(msg.buffer_id, msg.in_port, actions)
def state_change_handler(self, ev): dp = ev.datapath assert dp is not None LOG.debug(dp) if ev.state == MAIN_DISPATCHER: dp_multiple_conns = False if dp.id in self.dps: LOG.warning('Multiple connections from %s', dpid_to_str(dp.id)) dp_multiple_conns = True (self.dps[dp.id]).close() self._register(dp) switch = self._get_switch(dp.id) LOG.debug('register %s', switch) if not dp_multiple_conns: self.send_event_to_observers(event.EventSwitchEnter(switch)) else: evt = event.EventSwitchReconnected(switch) self.send_event_to_observers(evt) if not self.link_discovery: return if self.install_flow: ofproto = dp.ofproto ofproto_parser = dp.ofproto_parser # TODO:XXX need other versions if ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION: rule = nx_match.ClsRule() rule.set_dl_dst( addrconv.mac.text_to_bin(lldp.LLDP_MAC_NEAREST_BRIDGE)) rule.set_dl_type(ETH_TYPE_LLDP) actions = [ ofproto_parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, self.LLDP_PACKET_LEN) ] dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions, priority=0xFFFF) elif ofproto.OFP_VERSION >= ofproto_v1_2.OFP_VERSION: match = ofproto_parser.OFPMatch( eth_type=ETH_TYPE_LLDP, eth_dst=lldp.LLDP_MAC_NEAREST_BRIDGE) # OFPCML_NO_BUFFER is set so that the LLDP is not # buffered on switch parser = ofproto_parser actions = [ parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER) ] inst = [ parser.OFPInstructionActions( ofproto.OFPIT_APPLY_ACTIONS, actions) ] mod = parser.OFPFlowMod(datapath=dp, match=match, idle_timeout=0, hard_timeout=0, instructions=inst, priority=0xFFFF) dp.send_msg(mod) else: LOG.error('cannot install flow. unsupported version. %x', dp.ofproto.OFP_VERSION) # Do not add ports while dp has multiple connections to controller. if not dp_multiple_conns: for port in switch.ports: if not port.is_reserved(): self._port_added(port) self.lldp_event.set() elif ev.state == DEAD_DISPATCHER: # dp.id is None when datapath dies before handshake if dp.id is None: return switch = self._get_switch(dp.id) if switch: if switch.dp is dp: self._unregister(dp) LOG.debug('unregister %s', switch) evt = event.EventSwitchLeave(switch) self.send_event_to_observers(evt) if not self.link_discovery: return for port in switch.ports: if not port.is_reserved(): self.ports.del_port(port) self._link_down(port) self.lldp_event.set()
def _send_location_req(self, tenant_id, vnid, vip, net): logging.debug('Send location-req %d:%d %s to %s', tenant_id, vnid, vip, net['site_name']) fa_url = self._find_url(tenant_id, net['site_name']) auth = HTTPBasicAuth('admin', 'admin') headers = { 'content-type': 'application/json', 'Accept': 'application/json', 'charsets': 'utf-8' } r = requests.post('http://' + fa_url + url_tenants + '/' + str(net['tenant_id']) + '/location-req', headers=headers, auth=auth, data=json.dumps({ "src_tenant_id": tenant_id, "dst_tenant_id": net['tenant_id'], "vnid": net['vnid'], "vip": vip })) if int(r.status_code) == 200: reply = r.json() validate(reply, location_reply_schema) pip = self.switch['datapath'].address[0] dp = self.switch['datapath'] # send to SDN controller location update self.send_event( 'FaSdnController', EventLocUpdateReq(pip, reply['vnid'], str(reply['vip']), str(reply['vmac']))) # Set outgoing flow in the datapath dp = self.switch['datapath'] ofproto = dp.ofproto tunnel_port = self.tunnel_port parser = dp.ofproto_parser actions = [] rule = nx_match.ClsRule() # hardware rule.set_in_port(tunnel_port.port_no) rule.set_dl_type(0x0800) # ip rule.set_nw_dst(ipv4_text_to_int(vip)) #rule.set_nw_proto(packet[1].proto) #rule.set_nw_proto(4) # "ip" # encap rule.set_tun_id( vnid ) # We assume NET sends the source VNID in the VXLAN header for now # set tunnel key SET_TUNNEL actions.append(dp.ofproto_parser.NXActionSetTunnel(net['vnid'])) # set tunnel dst pIP REG_LOAD actions.append( dp.ofproto_parser.NXActionRegLoad( 0x1f, # ofs_nbits (ofs < 6 | nbits - 1) 0x014004, # dst ipv4_text_to_int(str(reply['pip']['ip'])))) # forward OUTPUT(PROXY) actions.append( dp.ofproto_parser.OFPActionOutput(ofproto.OFPP_IN_PORT)) logging.debug('Set outgoing flow for %d:%s=>%s', net['vnid'], vip, reply['pip']['ip']) dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions)
def _add_flows_for_vnid(self, tenant_id, vnid, port): dp = self.net_switch_app.switch['datapath'] ofproto = dp.ofproto tunnel_port = self.net_switch_app.tunnel_port parser = dp.ofproto_parser # Outbound flow actions = [] rule = nx_match.ClsRule() # hardware command = ovs_vsctl.VSCtlCommand('get', ('Interface', port, 'ofport')) self.net_switch_app.vsctl.run_command([command]) assert len(command.result) == 1 ofport = command.result[0][0] rule.set_in_port(ofport) logging.debug("Set outbound flow for vnid %s(%s):", vnid, self._vnid_uuid_to_vnid(vnid)) for site in tenants_site_tables[tenant_id]: if site['name'] != self.my_site: remote_vnid = self._get_sites_vnid(site['name'], tenant_id, vnid) remote_ip = str(site['site_proxy'][0]['ip']) # set tunnel key SET_TUNNEL actions.append( dp.ofproto_parser.NXActionSetTunnel( self._vnid_uuid_to_vnid(remote_vnid))) # set tunnel dst pIP REG_LOAD actions.append( dp.ofproto_parser.NXActionRegLoad( 0x1f, # ofs_nbits (ofs < 6 | nbits - 1) 0x014004, # dst ipv4_text_to_int(remote_ip))) # forward OUTPUT(PROXY) actions.append( dp.ofproto_parser.OFPActionOutput(tunnel_port.port_no)) logging.debug( '--------ACTION: vnid:%s(%s)=>site %s:vnid:%s(%s) via tunnel %s', vnid, self._vnid_uuid_to_vnid(vnid), site['name'], remote_vnid, self._vnid_uuid_to_vnid(remote_vnid), site['site_proxy'][0]['ip']) res = dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions) # Inbound flow actions = [] rule = nx_match.ClsRule() rule.set_in_port(tunnel_port.port_no) rule.set_tun_id(self._vnid_uuid_to_vnid(vnid)) # forward OUTPUT to local SDN controller vnid port actions.append(dp.ofproto_parser.OFPActionOutput(ofport)) logging.debug('Set inbound flow for %s(%s)=> local SDN port:%s', vnid, self._vnid_uuid_to_vnid(vnid), ofport) res = dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions)
def location_request(self, req, tenant_id, **kwargs): msg = json.loads(req.body) validate(msg, location_request_schema) logging.debug('Enter location_request with %s', msg) # send location request to controller reply = self.net_switch_app.send_request( EventLocationReq(msg['vnid'], str(msg['vip']))) # XXX return error code if reply.vIP == "0.0.0.0": return Response(content_type='application/json', status=500) # set incoming flow in the datapath dp = self.net_switch_app.switch['datapath'] tunnel_port = self.net_switch_app.tunnel_port rule = nx_match.ClsRule() actions = [] ofproto = dp.ofproto # hardware rule.set_in_port(tunnel_port.port_no) rule.set_dl_type(0x0800) # ip rule.set_nw_dst(ipv4_text_to_int(str(msg['vip']))) #rule.set_nw_proto(packet[1].proto) #rule.set_nw_proto(4) # "ip" # encap rule.set_tun_id(msg['vnid']) # set tunnel key SET_TUNNEL actions.append(dp.ofproto_parser.NXActionSetTunnel(msg['vnid'])) # set tunnel dst pIP REG_LOAD actions.append( dp.ofproto_parser.NXActionRegLoad( 0x1f, # ofs_nbits (ofs < 6 | nbits - 1) 0x014004, # dst ipv4_text_to_int(reply.pIP))) # forward OUTPUT(PROXY) actions.append(dp.ofproto_parser.OFPActionOutput(ofproto.OFPP_IN_PORT)) logging.debug('Installing incoming flow for %d:%s=>%s', msg['vnid'], msg['vip'], reply.pIP) dp.send_flow_mod(rule=rule, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, actions=actions) # Send reply to peer FA net_list = tenants_net_tables[tenant_id]['table'][msg['vnid']] vnid = "" for net in net_list: if net['tenant_id'] == msg['src_tenant_id']: vnid = net['vnid'] if not vnid: raise RyuException("Can not find peer network") body = { "vnid": vnid, "vip": msg['vip'], "vmac": reply.vMAC, "tenant_id": msg['src_tenant_id'], "pip": { "ip": self.net_switch_app.switch['datapath'].address[0] } } body = json.dumps(body) return Response(content_type='application/json', body=body)
def border_switch_out(self, msg, pkt, dst_switch, dst_reply, _4or6): """ Deploy the flow table on border switch and send the packet from the initial switch. """ if _4or6 == 4: ip_layer = self.find_packet(pkt, 'ipv4') else: ip_layer = self.find_packet(pkt, 'ipv6') initial_dp = msg.datapath initial_switch = self.dpid_to_switch[initial_dp.id] dp = dst_switch.dp ipDestAddr = netaddr.IPAddress(ip_layer.dst) macAddr = dst_switch.ip_to_mac[ipDestAddr][0] outport_no = dst_reply.outport_no if _4or6 == 4: # ip src exact match wildcards = ofproto_v1_0.OFPFW_ALL wildcards &= ~ofproto_v1_0.OFPFW_DL_TYPE wildcards &= ~(0x3f << ofproto_v1_0.OFPFW_NW_DST_SHIFT) match = dp.ofproto_parser.OFPMatch( # because of wildcards, parameters other than dl_type # and nw_dst could be any value wildcards=wildcards, in_port=0, dl_src=0, dl_dst=0, dl_vlan=0, dl_vlan_pcp=0, dl_type=ether.ETH_TYPE_IP, nw_tos=0, nw_proto=0, nw_src=0, nw_dst=ipDestAddr.value, tp_src=0, tp_dst=0) else: rule = nx_match.ClsRule() rule.set_dl_type(ether.ETH_TYPE_IPV6) rule.set_ipv6_dst(struct.unpack('!8H', ipDestAddr.packed)) actions = [] actions.append( dp.ofproto_parser.OFPActionSetDlSrc( dst_switch.ports[outport_no].hw_addr.packed)) actions.append(dp.ofproto_parser.OFPActionSetDlDst(macAddr.packed)) actions.append(dp.ofproto_parser.OFPActionOutput(outport_no)) if _4or6 == 4: mod = dp.ofproto_parser.OFPFlowMod( datapath=dp, match=match, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, actions=actions) else: mod = dp.ofproto_parser.NXTFlowMod( datapath=dp, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, rule=rule, actions=actions) out = dp.ofproto_parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) dp.send_msg(mod) initial_dp.send_msg(out)
def _port_flow_del(self, dp, port_no): self.logger.debug('_port_flow_del dp %s port_no %d', dpid_lib.dpid_to_str(dp.id), port_no) rule = nx_match.ClsRule() rule.set_in_port(port_no) dp.send_flow_del(rule=rule, cookie=self._COOKIE_NORMAL)
def packet_in_handler(self, ev): # LOG.debug('packet in ev %s msg %s', ev, ev.msg) msg = ev.msg datapath = msg.datapath dst, src, _eth_type = struct.unpack_from('!6s6sH', buffer(msg.data), 0) try: port_nw_id = self.nw.get_network(datapath.id, msg.in_port) except PortUnknown: port_nw_id = NW_ID_UNKNOWN if port_nw_id != NW_ID_UNKNOWN: # Here it is assumed that the # (port <-> network id)/(mac <-> network id) relationship # is stable once the port is created. The port will be destroyed # before assigning new network id to the given port. # This is correct nova-network/nova-compute. try: # allow external -> known nw id change self.mac2net.add_mac(src, port_nw_id, NW_ID_EXTERNAL) except MacAddressDuplicated: LOG.warn( 'mac address %s is already in use.' ' So (dpid %s, port %s) can not use it', haddr_to_str(src), datapath.id, msg.in_port) # # should we install drop action pro-actively for future? # self._drop_packet(msg) return old_port = self.mac2port.port_add(datapath.id, msg.in_port, src) if old_port is not None and old_port != msg.in_port: # We really overwrite already learned mac address. # So discard already installed stale flow entry which conflicts # new port. rule = nx_match.ClsRule() rule.set_dl_dst(src) datapath.send_flow_mod( rule=rule, cookie=0, command=datapath.ofproto.OFPFC_DELETE, idle_timeout=0, hard_timeout=0, priority=datapath.ofproto.OFP_DEFAULT_PRIORITY, out_port=old_port) # to make sure the old flow entries are purged. datapath.send_barrier() src_nw_id = self.mac2net.get_network(src, NW_ID_UNKNOWN) dst_nw_id = self.mac2net.get_network(dst, NW_ID_UNKNOWN) # we handle multicast packet as same as broadcast broadcast = (dst == mac.BROADCAST) or mac.is_multicast(dst) out_port = self.mac2port.port_get(datapath.id, dst) # # there are several combinations: # in_port: known nw_id, external, unknown nw, # src mac: known nw_id, external, unknown nw, # dst mac: known nw_id, external, unknown nw, and broadcast/multicast # where known nw_id: is quantum network id # external: means that these ports are connected to outside # unknown nw: means that we don't know this port is bounded to # specific nw_id or external # broadcast: the destination mac address is broadcast address # (or multicast address) # # Can the following logic be refined/shortened? # # When NW_ID_UNKNOWN is found, registering ports might be delayed. # So just drop only this packet and not install flow entry. # It is expected that when next packet arrives, the port is registers # with some network id if port_nw_id != NW_ID_EXTERNAL and port_nw_id != NW_ID_UNKNOWN: if broadcast: # flood to all ports of external or src_nw_id self._flood_to_nw_id(msg, src, dst, src_nw_id) elif src_nw_id == NW_ID_EXTERNAL: self._modflow_and_drop_packet(msg, src, dst) return elif src_nw_id == NW_ID_UNKNOWN: self._drop_packet(msg) return else: # src_nw_id != NW_ID_EXTERNAL and src_nw_id != NW_ID_UNKNOWN: # # try learned mac check if the port is net_id # or # flood to all ports of external or src_nw_id self._learned_mac_or_flood_to_nw_id(msg, src, dst, src_nw_id, out_port) elif port_nw_id == NW_ID_EXTERNAL: if src_nw_id != NW_ID_EXTERNAL and src_nw_id != NW_ID_UNKNOWN: if broadcast: # flood to all ports of external or src_nw_id self._flood_to_nw_id(msg, src, dst, src_nw_id) elif (dst_nw_id != NW_ID_EXTERNAL and dst_nw_id != NW_ID_UNKNOWN): if src_nw_id == dst_nw_id: # try learned mac # check if the port is external or same net_id # or # flood to all ports of external or src_nw_id self._learned_mac_or_flood_to_nw_id( msg, src, dst, src_nw_id, out_port) else: # should not occur? LOG.debug("should this case happen?") self._drop_packet(msg) elif dst_nw_id == NW_ID_EXTERNAL: # try learned mac # or # flood to all ports of external or src_nw_id self._learned_mac_or_flood_to_nw_id( msg, src, dst, src_nw_id, out_port) else: assert dst_nw_id == NW_ID_UNKNOWN LOG.debug("Unknown dst_nw_id") self._drop_packet(msg) elif src_nw_id == NW_ID_EXTERNAL: self._modflow_and_drop_packet(msg, src, dst) else: # should not occur? assert src_nw_id == NW_ID_UNKNOWN self._drop_packet(msg) else: # drop packets assert port_nw_id == NW_ID_UNKNOWN self._drop_packet(msg)
def deploy_flow_entry(self, msg, pkt, switch_list, _4or6): """ deploy flow entry into switch e.g. if 'switch_list' is [A, B, C], then this method will deploy flow entries A->B, B->C """ # TODO # this method and last_switch_out should be restructured dp = msg.datapath length = len(switch_list) for i in xrange(length - 1): this_switch = switch_list[i] next_switch = switch_list[i + 1] outport_no = this_switch.peer_to_local_port[next_switch] if _4or6 == 4: ip_layer = self.find_packet(pkt, 'ipv4') else: ip_layer = self.find_packet(pkt, 'ipv6') ip_dst = netaddr.IPAddress(ip_layer.dst) outport = this_switch.ports[outport_no] mac_src = outport.hw_addr mac_dst = next_switch.ports[outport.peer_port_no].hw_addr if _4or6 == 4: # ip src exact match wildcards = ofproto_v1_0.OFPFW_ALL wildcards &= ~ofproto_v1_0.OFPFW_DL_TYPE wildcards &= ~(0x3f << ofproto_v1_0.OFPFW_NW_DST_SHIFT) match = dp.ofproto_parser.OFPMatch( # because of wildcards, parameters other than dl_type # and nw_dst could be any value wildcards=wildcards, in_port=0, dl_src=0, dl_dst=0, dl_vlan=0, dl_vlan_pcp=0, dl_type=ether.ETH_TYPE_IP, nw_tos=0, nw_proto=0, nw_src=0, nw_dst=ip_dst.value, tp_src=0, tp_dst=0) else: rule = nx_match.ClsRule() rule.set_dl_type(ether.ETH_TYPE_IPV6) rule.set_ipv6_dst(struct.unpack('!8H', ip_dst.packed)) actions = [] actions.append(dp.ofproto_parser.OFPActionSetDlSrc(mac_src.packed)) actions.append(dp.ofproto_parser.OFPActionSetDlDst(mac_dst.packed)) actions.append(dp.ofproto_parser.OFPActionOutput(outport_no)) if _4or6 == 4: mod = dp.ofproto_parser.OFPFlowMod( datapath=this_switch.dp, match=match, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, actions=actions) else: mod = dp.ofproto_parser.NXTFlowMod( datapath=this_switch.dp, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, rule=rule, actions=actions) this_switch.dp.send_msg(mod) LOG.info('Flow entry deployed to %s', this_switch) # send packet out from the first switch switch = switch_list[0] next_switch = switch_list[1] outport_no = switch.peer_to_local_port[next_switch] outport = switch.ports[outport_no] mac_src = outport.hw_addr mac_dst = next_switch.ports[outport.peer_port_no].hw_addr actions = [] actions.append(dp.ofproto_parser.OFPActionSetDlSrc(mac_src.packed)) actions.append(dp.ofproto_parser.OFPActionSetDlDst(mac_dst.packed)) actions.append(dp.ofproto_parser.OFPActionOutput(outport_no)) out = dp.ofproto_parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) switch.dp.send_msg(out)
def last_switch_out(self, msg, pkt, outport_no, _4or6): """ The packet has already reached the last switch and needs to be forwarded. Does NOT support output to routers out of the AS """ if _4or6 == 4: ip_layer = self.find_packet(pkt, 'ipv4') else: ip_layer = self.find_packet(pkt, 'ipv6') dp = msg.datapath switch = self.dpid_to_switch[dp.id] ipDestAddr = netaddr.IPAddress(ip_layer.dst) LOG.debug('last_switch_out: switch %s, port_no %s', switch, outport_no) try: # TODO introduce ARP timeout mac_addr = switch.ip_to_mac[ipDestAddr][0] except KeyError: # don't know MAC address yet, send ARP/ICMP message # and temporarily store the packets if _4or6 == 4: self._send_arp_request(msg.datapath, outport_no, ipDestAddr) else: self._send_icmp_NS(msg.datapath, outport_no, ipDestAddr) switch.msg_buffer.append((msg, pkt, outport_no, _4or6)) return False if _4or6 == 4: # ip src exact match wildcards = ofproto_v1_0.OFPFW_ALL wildcards &= ~ofproto_v1_0.OFPFW_DL_TYPE wildcards &= ~(0x3f << ofproto_v1_0.OFPFW_NW_DST_SHIFT) match = dp.ofproto_parser.OFPMatch( # because of wildcards, parameters other than dl_type # and nw_dst could be any value wildcards=wildcards, in_port=0, dl_src=0, dl_dst=0, dl_vlan=0, dl_vlan_pcp=0, dl_type=ether.ETH_TYPE_IP, nw_tos=0, nw_proto=0, nw_src=0, nw_dst=ipDestAddr.value, tp_src=0, tp_dst=0) else: rule = nx_match.ClsRule() rule.set_dl_type(ether.ETH_TYPE_IPV6) rule.set_ipv6_dst(struct.unpack('!8H', ipDestAddr.packed)) actions = [] actions.append( dp.ofproto_parser.OFPActionSetDlSrc( switch.ports[outport_no].hw_addr.packed)) actions.append(dp.ofproto_parser.OFPActionSetDlDst(mac_addr.packed)) actions.append(dp.ofproto_parser.OFPActionOutput(outport_no)) if _4or6 == 4: mod = dp.ofproto_parser.OFPFlowMod( datapath=dp, match=match, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, actions=actions) else: mod = dp.ofproto_parser.NXTFlowMod( datapath=dp, cookie=0, command=dp.ofproto.OFPFC_MODIFY, idle_timeout=Routing.FLOW_IDLE_TIMEOUT, hard_timeout=Routing.FLOW_HARD_TIMEOUT, out_port=outport_no, rule=rule, actions=actions) out = dp.ofproto_parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id, in_port=msg.in_port, actions=actions) dp.send_msg(mod) dp.send_msg(out) return True