def _wait_bpdu_timer(self): time_exceed = False while True: self.wait_timer_event = hub.Event() message_age = (self.designated_times.message_age if self.designated_times else 0) timer = self.port_times.max_age - message_age timeout = hub.Timeout(timer) try: self.wait_timer_event.wait() except hub.Timeout as t: if t is not timeout: err_msg = 'Internal error. Not my timeout.' raise RyuException(msg=err_msg) self.logger.info('[port=%d] Wait BPDU timer is exceeded.', self.ofport.port_no, extra=self.dpid_str) time_exceed = True finally: timeout.cancel() self.wait_timer_event = None if time_exceed: break if time_exceed: # Bridge.recalculate_spanning_tree hub.spawn(self.wait_bpdu_timeout)
def _wait(self): """ Wait until specific OFP message received or timer is exceeded. """ assert self.waiter is None self.waiter = hub.Event() self.rcv_msgs = [] timeout = False timer = hub.Timeout(WAIT_TIMER) try: self.waiter.wait() except hub.Timeout as t: if t is not timer: raise RyuException('Internal error. Not my timeout.') timeout = True finally: timer.cancel() self.waiter = None if timeout: raise TestTimeout(self.state) if (self.rcv_msgs and isinstance(self.rcv_msgs[0], ofproto_v1_3_parser.OFPErrorMsg)): raise TestReceiveError(self.state, self.rcv_msgs[0])
def do_handshake(self, site, version): site['handshake_state'] = 'PENDING' ipaddr = \ self.net_switch_app.switch['datapath'].address[0] auth = HTTPBasicAuth('admin', 'admin') headers = { 'content-type': 'application/json', 'Accept': 'application/json', 'charsets': 'utf-8' } r = requests.post('http://' + site['fa_url'] + url_tenants + '/' + str(site['tenant_id']) + '/handshake', headers=headers, auth=auth, data=json.dumps({ "version": version, "src_site": self.my_site, "tenant_id": site['tenant_id'], "tunnel_ip": ipaddr, "tunnel_type": 'VXLAN' })) if int(r.status_code) == 200: msg = r.json() validate(msg, handshake_schema) site['handshake_state'] = 'SUCCESS' site['tunnel_attr'] = { "tunnel_ip": msg['tunnel_ip'], "tunnel_type": msg['tunnel_type'] } return raise RyuException("FA handshake failed %s" % r.text)
def hand_shake(self, req, tenant_id, **kwargs): if (tenant_id in tenants_net_tables and tenants_net_tables[tenant_id] ) and (tenant_id in tenants_site_tables and tenants_site_tables[tenant_id]): net_table = tenants_net_tables[tenant_id] site_table = tenants_site_tables[tenant_id] else: return Response( content_type='application/json', status=500, body="Handshake failed: Missing site/net table XXX Pending.") # Handshake validation msg = json.loads(req.body) validate(msg, handshake_schema) if msg['version'] != net_table['version']: raise RyuException("Handshake failed: Version mismatch %s %s" % (msg['version'], net_table['version'])) logging.info("Start jandshake for tenant %s", tenant_id) for site in tenants_site_tables[tenant_id]: if site['name'] == msg['src_site']: status, body = self._process_handshake_req( site, tenant_id, msg) body = json.dumps(body) return Response(content_type='application/json', body=body) return Response(content_type='application/json', status=500, body="Handshake failed: Src site was not found.")
def _site_tenant(self, site_id, tenant_id): if tenant_id in tenants_site_tables: site_table = tenants_site_tables[tenant_id] distant_tenant_attr = site_table[site_id] return distant_tenant_attr raise RyuException("Tenant translation failed")
def _get_sites_vnid(self, site_name, tenant_id, network_id): if tenant_id in tenants_net_tables: net_table = tenants_net_tables[tenant_id] net_list = net_table['table'][network_id] for site_net_attr in net_list: if site_net_attr['site_name'] == site_name: return site_net_attr['vnid'] raise RyuException("Network translation failed")
def _register_networks(self, table, tenant_id): pip = self.net_switch_app.switch['datapath'].address[0] for vnid in table['table']: logging.info("Register %s in controller", vnid) rep = self.net_switch_app.send_request( EventRegisterVNIDReq(vnid, pip)) if rep.port: self._add_flows_for_vnid(tenant_id, vnid, rep.port) else: raise RyuException( "Error failed to create port for vnid %s\n" % vnid)
def switch_features_handler(self, ev): datapath = ev.msg.datapath for port_no, port in ev.msg.ports.items(): if port.name == self.CONF.netfa.fa_br_name: # We found our datapath self.switch = {'datapath': datapath} if port.name == self.CONF.netfa.fa_tun_name: # We found our fa tunnel port self.tunnel_port = port if not self.switch or not self.tunnel_port: raise RyuException("No NET FA bridge yet") logging.info('Found Federation Agent Bridge %s with tunnel port %s', self.CONF.netfa.fa_br_name, self.CONF.netfa.fa_tun_name)
def loc_query_handler(self, ev): vnid = ev.vNID vip = ev.vIP logging.debug('Enter loc_query_handler for %d:%s', vnid, vip) for tenant_id, net_table in tenants_net_tables.items(): if vnid in net_table['table']: for net in net_table['table'][vnid]: if net['site_name'] != self.CONF.netfa.my_site: self._send_location_req(tenant_id, vnid, vip, net) found = True break if not found: raise RyuException("Can not find VNID %s" % vnid)
def _state_machine(self): """ Port state machine. Change next status when timer is exceeded or _change_status() method is called.""" role_str = { ROOT_PORT: 'ROOT_PORT ', DESIGNATED_PORT: 'DESIGNATED_PORT ', NON_DESIGNATED_PORT: 'NON_DESIGNATED_PORT' } state_str = { PORT_STATE_DISABLE: 'DISABLE', PORT_STATE_BLOCK: 'BLOCK', PORT_STATE_LISTEN: 'LISTEN', PORT_STATE_LEARN: 'LEARN', PORT_STATE_FORWARD: 'FORWARD' } if self.state is PORT_STATE_DISABLE: self.ofctl.set_port_status(self.ofport, self.state) while True: self.logger.info('[port=%d] %s / %s', self.ofport.port_no, role_str[self.role], state_str[self.state], extra=self.dpid_str) self.state_event = hub.Event() timer = self._get_timer() if timer: timeout = hub.Timeout(timer) try: self.state_event.wait() except hub.Timeout as t: if t is not timeout: err_msg = 'Internal error. Not my timeout.' raise RyuException(msg=err_msg) new_state = self._get_next_state() self._change_status(new_state, thread_switch=False) finally: timeout.cancel() else: self.state_event.wait() self.state_event = None
def _test_throughput_check(self, throughputs, start, end): msgs = [] elapsed_sec = end[0] - start[0] for throughput in throughputs: match = str(throughput[KEY_FLOW].match) # get oxm_fields of OFPMatch fields = dict(throughput[KEY_FLOW].match._fields2) if match not in start[1] or match not in end[1]: raise TestError(self.state, match=match) increased_bytes = end[1][match][0] - start[1][match][0] increased_packets = end[1][match][1] - start[1][match][1] if throughput[KEY_PKTPS]: key = KEY_PKTPS conv = 1 measured_value = increased_packets unit = 'pktps' elif throughput[KEY_KBPS]: key = KEY_KBPS conv = 1024 / 8 # Kilobits -> bytes measured_value = increased_bytes unit = 'kbps' else: raise RyuException( 'An invalid key exists that is neither "%s" nor "%s".' % (KEY_KBPS, KEY_PKTPS)) expected_value = throughput[key] * elapsed_sec * conv margin = expected_value * THROUGHPUT_THRESHOLD self.logger.debug("measured_value:[%s]", measured_value) self.logger.debug("expected_value:[%s]", expected_value) self.logger.debug("margin:[%s]", margin) if math.fabs(measured_value - expected_value) > margin: msgs.append('{0} {1:.2f}{2}'.format( fields, measured_value / elapsed_sec / conv, unit)) if msgs: raise TestFailure(self.state, detail=', '.join(msgs))
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 _validate_datapath(self): if not self.net_switch_app.switch: raise RyuException("FA handshake failed: No datapath")
def _find_url(self, tenant_id, name): for site in tenants_site_tables[tenant_id]: if site['name'] == name: return site['fa_url'] raise RyuException("Error finding FA url on %s" % name)