summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ryu/app/gre_tunnel.py155
-rw-r--r--ryu/app/quantum_adapter.py29
-rw-r--r--ryu/app/tunnel_port_updater.py9
-rw-r--r--ryu/controller/network.py90
-rw-r--r--ryu/lib/mac.py2
-rw-r--r--ryu/lib/ovs/vsctl.py1
6 files changed, 219 insertions, 67 deletions
diff --git a/ryu/app/gre_tunnel.py b/ryu/app/gre_tunnel.py
index 2f677416..51aa3f1c 100644
--- a/ryu/app/gre_tunnel.py
+++ b/ryu/app/gre_tunnel.py
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import collections
import logging
-from collections import defaultdict
from ryu import exception as ryu_exc
from ryu.app.rest_nw_id import (NW_ID_VPORT_GRE,
@@ -177,6 +177,10 @@ class PortSet(handler_utils.QueueSerializer):
port_no, mac_address, add_del))
def _vm_port_mac_handler(self, dpid, port_no, network_id, add_del):
+ if network_id == NW_ID_VPORT_GRE:
+ self._tunnel_port_handler(dpid, port_no, add_del)
+ return
+
try:
mac_address = self.nw.get_mac(dpid, port_no)
except ryu_exc.PortNotFound:
@@ -473,6 +477,29 @@ class GRETunnel(app_manager.RyuApp):
def _link_is_up(self, dp, port_no):
return _link_is_up(self.dpset, dp, port_no)
+ def _port_is_active(self, network_id, dp, nw_port):
+ return (nw_port.network_id == network_id and
+ nw_port.mac_address is not None and
+ self._link_is_up(dp, nw_port.port_no))
+
+ def _tunnel_port_with_mac(self, remote_dp, dpid, network_id, port_no,
+ mac_address):
+ tunnel_ports = []
+ ports = self.nw.get_ports_with_mac(network_id, mac_address).copy()
+ ports.discard((dpid, port_no))
+ assert len(ports) <= 1
+ for port in ports:
+ try:
+ tunnel_port_no = self.tunnels.get_port(remote_dp.id, port.dpid)
+ except ryu_exc.PortNotFound:
+ pass
+ else:
+ if self._link_is_up(remote_dp, tunnel_port_no):
+ tunnel_ports.append(tunnel_port_no)
+
+ assert len(tunnel_ports) <= 1
+ return tunnel_ports
+
def _vm_port_add(self, ev):
dpid = ev.dpid
dp = self.dpset.get(dpid)
@@ -486,8 +513,12 @@ class GRETunnel(app_manager.RyuApp):
remote_dpids.remove(dpid)
# LOCAL_OUT_TABLE: unicast
+ # live-migration: there can be two ports with same mac_address
+ ports = self.nw.get_ports(dpid, network_id, mac_address)
+ assert ev.port_no in [port.port_no for port in ports]
rule = cls_rule(tun_id=tunnel_key, dl_dst=mac_address)
- actions = [ofproto_parser.OFPActionOutput(ev.port_no)]
+ actions = [ofproto_parser.OFPActionOutput(port.port_no)
+ for port in ports if self._link_is_up(dp, port.port_no)]
self.send_flow_mod(dp, rule, self.LOCAL_OUT_TABLE, ofproto.OFPFC_ADD,
self.LOCAL_OUT_PRI_MAC, actions)
@@ -495,9 +526,7 @@ class GRETunnel(app_manager.RyuApp):
rule = cls_rule(tun_id=tunnel_key, dl_dst=mac.BROADCAST)
actions = []
for port in self.nw.get_ports(dpid):
- if (port.network_id != network_id or port.mac_address is None):
- continue
- if not self._link_is_up(dp, port.port_no):
+ if not self._port_is_active(network_id, dp, port):
continue
actions.append(ofproto_parser.OFPActionOutput(port.port_no))
@@ -519,6 +548,7 @@ class GRETunnel(app_manager.RyuApp):
ofproto.OFPFC_ADD, self.LOCAL_OUT_PRI_DROP, [])
# TUNNEL_OUT_TABLE: unicast
+ mac_to_ports = collections.defaultdict(set)
for remote_dpid in remote_dpids:
remote_dp = self.dpset.get(remote_dpid)
if remote_dp is None:
@@ -531,19 +561,12 @@ class GRETunnel(app_manager.RyuApp):
continue
for port in self.nw.get_ports(remote_dpid):
- if port.network_id != network_id or port.mac_address is None:
- continue
- if not self._link_is_up(remote_dp, port.port_no):
+ if not self._port_is_active(network_id, remote_dp, port):
continue
# TUNNEL_OUT_TABLE: unicast
- rule = cls_rule(tun_id=tunnel_key, dl_dst=port.mac_address)
- output = ofproto_parser.OFPActionOutput(tunnel_port_no)
- resubmit_table = ofproto_parser.NXActionResubmitTable(
- in_port=ofproto.OFPP_IN_PORT, table=self.LOCAL_OUT_TABLE)
- actions = [output, resubmit_table]
- self.send_flow_mod(dp, rule, self.TUNNEL_OUT_TABLE,
- ofproto.OFPFC_ADD, self.TUNNEL_OUT_PRI_MAC,
- actions)
+ # live-migration: there can be more than one tunnel-ports that
+ # have a given mac address
+ mac_to_ports[port.mac_address].add(tunnel_port_no)
if first_instance:
# SRC_TABLE: TUNNEL-port: resubmit to LOAL_OUT_TABLE
@@ -555,6 +578,18 @@ class GRETunnel(app_manager.RyuApp):
ofproto.OFPFC_ADD, self.SRC_PRI_TUNNEL_PASS,
actions)
+ # TUNNEL_OUT_TABLE: unicast
+ for remote_mac_address, tunnel_ports in mac_to_ports.items():
+ rule = cls_rule(tun_id=tunnel_key, dl_dst=remote_mac_address)
+ outputs = [ofproto_parser.OFPActionOutput(tunnel_port_no)
+ for tunnel_port_no in tunnel_ports]
+ resubmit_table = ofproto_parser.NXActionResubmitTable(
+ in_port=ofproto.OFPP_IN_PORT, table=self.LOCAL_OUT_TABLE)
+ actions = outputs + [resubmit_table]
+ self.send_flow_mod(dp, rule, self.TUNNEL_OUT_TABLE,
+ ofproto.OFPFC_ADD, self.TUNNEL_OUT_PRI_MAC,
+ actions)
+
if first_instance:
# TUNNEL_OUT_TABLE: catch-all(resubmit to LOCAL_OUT_TABLE)
rule = cls_rule(tun_id=tunnel_key)
@@ -610,29 +645,37 @@ class GRETunnel(app_manager.RyuApp):
remote_ofproto_parser = remote_dp.ofproto_parser
# TUNNEL_OUT_TABLE: unicast
+ # live-migration: there can be another port that has
+ # same mac address
+ tunnel_ports = self._tunnel_port_with_mac(remote_dp, dpid,
+ network_id, ev.port_no,
+ mac_address)
+ tunnel_ports.append(tunnel_port_no)
+
rule = cls_rule(tun_id=ev.tunnel_key, dl_dst=mac_address)
- output = remote_ofproto_parser.OFPActionOutput(tunnel_port_no)
+ outputs = [remote_ofproto_parser.OFPActionOutput(port_no)
+ for port_no in tunnel_ports]
resubmit_table = remote_ofproto_parser.NXActionResubmitTable(
in_port=remote_ofproto.OFPP_IN_PORT,
table=self.LOCAL_OUT_TABLE)
- actions = [output, resubmit_table]
+ actions = outputs + [resubmit_table]
self.send_flow_mod(remote_dp, rule, self.TUNNEL_OUT_TABLE,
remote_ofproto.OFPFC_ADD,
self.TUNNEL_OUT_PRI_MAC, actions)
- if first_instance:
- # SRC_TABLE: TUNNEL-port
- rule = cls_rule(in_port=tunnel_port_no, tun_id=ev.tunnel_key)
- resubmit_table = remote_ofproto_parser.NXActionResubmitTable(
- in_port=remote_ofproto.OFPP_IN_PORT,
- table=self.LOCAL_OUT_TABLE)
- actions = [resubmit_table]
- self.send_flow_mod(remote_dp, rule, self.SRC_TABLE,
- remote_ofproto.OFPFC_ADD,
- self.SRC_PRI_TUNNEL_PASS, actions)
- else:
+ if not first_instance:
continue
+ # SRC_TABLE: TUNNEL-port
+ rule = cls_rule(in_port=tunnel_port_no, tun_id=ev.tunnel_key)
+ resubmit_table = remote_ofproto_parser.NXActionResubmitTable(
+ in_port=remote_ofproto.OFPP_IN_PORT,
+ table=self.LOCAL_OUT_TABLE)
+ actions = [resubmit_table]
+ self.send_flow_mod(remote_dp, rule, self.SRC_TABLE,
+ remote_ofproto.OFPFC_ADD,
+ self.SRC_PRI_TUNNEL_PASS, actions)
+
# TUNNEL_OUT_TABLE: broadcast
rule = cls_rule(tun_id=ev.tunnel_key, dl_dst=mac.BROADCAST)
tunnel_ports = self._list_tunnel_port(remote_dp, remote_dpids)
@@ -667,9 +710,7 @@ class GRETunnel(app_manager.RyuApp):
for port in self.nw.get_ports(dpid):
if port.port_no == ev.port_no:
continue
- if (port.network_id != network_id or port.mac_address is None):
- continue
- if not self._link_is_up(dp, port.port_no):
+ if not self._port_is_active(network_id, dp, port):
continue
local_ports.append(port.port_no)
@@ -704,10 +745,23 @@ class GRETunnel(app_manager.RyuApp):
[]) # priority is ignored
else:
# LOCAL_OUT_TABLE: unicast
- rule = cls_rule(tun_id=tunnel_key, dl_src=mac_address)
- self.send_flow_del(dp, rule, self.LOCAL_OUT_TABLE,
- ofproto.OFPFC_DELETE_STRICT,
- self.LOCAL_OUT_PRI_MAC, ev.port_no)
+ # live-migration: there can be two ports with same mac_address
+ ports = self.nw.get_ports(dpid, network_id, mac_address)
+ port_nos = [port.port_no for port in ports
+ if (port.port_no != ev.port_no and
+ self._link_is_up(dp, port.port_no))]
+ rule = cls_rule(tun_id=tunnel_key, dl_dst=mac_address)
+ if port_nos:
+ assert len(ports) == 1
+ actions = [ofproto_parser.OFPActionOutput(port_no)
+ for port_no in port_nos]
+ self.send_flow_mod(dp, rule, self.LOCAL_OUT_TABLE,
+ ofproto.OFPFC_MODIFY_STRICT,
+ self.LOCAL_OUT_PRI_MAC, actions)
+ else:
+ self.send_flow_del(dp, rule, self.LOCAL_OUT_TABLE,
+ ofproto.OFPFC_DELETE_STRICT,
+ self.LOCAL_OUT_PRI_MAC, ev.port_no)
# LOCAL_OUT_TABLE: broadcast
rule = cls_rule(tun_id=tunnel_key, dl_dst=mac.BROADCAST)
@@ -721,7 +775,8 @@ class GRETunnel(app_manager.RyuApp):
# remote dp
remote_dpids = self.nw.get_dpids(ev.network_id)
- remote_dpids.remove(dpid)
+ if dpid in remote_dpids:
+ remote_dpids.remove(dpid)
for remote_dpid in remote_dpids:
remote_dp = self.dpset.get(remote_dpid)
if remote_dp is None:
@@ -744,7 +799,7 @@ class GRETunnel(app_manager.RyuApp):
self.SRC_PRI_TUNNEL_PASS, None)
# SRC_TABLE: TUNNEL-port catch-call drop rule
- rule = cls_rule(in_port=tunnel_port_no, tun_id=tunnel_key)
+ rule = cls_rule(in_port=tunnel_port_no)
self.send_flow_del(remote_dp, rule, self.SRC_TABLE,
remote_ofproto.OFPFC_DELETE_STRICT,
self.SRC_PRI_TUNNEL_DROP, None)
@@ -771,15 +826,31 @@ class GRETunnel(app_manager.RyuApp):
actions)
# TUNNEL_OUT_TABLE: unicast
+ # live-migration: there can be more than one (dpid, port_no)
+ # with a given mac address
+ tunnel_ports = self._tunnel_port_with_mac(remote_dp, dpid,
+ network_id, ev.port_no,
+ mac_address)
rule = cls_rule(tun_id=tunnel_key, dl_dst=mac_address)
- self.send_flow_del(remote_dp, rule, self.TUNNEL_OUT_TABLE,
- remote_ofproto.OFPFC_DELETE_STRICT,
- self.TUNNEL_OUT_PRI_MAC, tunnel_port_no)
+ if tunnel_ports:
+ outputs = [remote_ofproto_parser.OFPActionOutput(port_no)
+ for port_no in tunnel_ports]
+ resubmit_table = remote_ofproto_parser.NXActionResubmitTable(
+ in_port=remote_ofproto.OFPP_IN_PORT,
+ table=self.LOCAL_OUT_TABLE)
+ actions = outputs + [resubmit_table]
+ self.send_flow_mod(remote_dp, rule, self.TUNNEL_OUT_TABLE,
+ remote_ofproto.OFPFC_ADD,
+ self.TUNNEL_OUT_PRI_MAC, actions)
+ else:
+ self.send_flow_del(remote_dp, rule, self.TUNNEL_OUT_TABLE,
+ remote_ofproto.OFPFC_DELETE_STRICT,
+ self.TUNNEL_OUT_PRI_MAC, tunnel_port_no)
# TODO:XXX multicast
def _get_vm_ports(self, dpid):
- ports = defaultdict(list)
+ ports = collections.defaultdict(list)
for port in self.nw.get_ports(dpid):
if port.network_id in RESERVED_NETWORK_IDS:
continue
diff --git a/ryu/app/quantum_adapter.py b/ryu/app/quantum_adapter.py
index 6c407e7d..29d063db 100644
--- a/ryu/app/quantum_adapter.py
+++ b/ryu/app/quantum_adapter.py
@@ -188,9 +188,16 @@ class OVSSwitch(object):
iface_id = port.ext_ids.get('iface-id')
if iface_id is None:
return
+ try:
+ network_id = self.ifaces.get_key(iface_id,
+ QuantumIfaces.KEY_NETWORK_ID)
+ except KeyError:
+ return
if not add:
+ self.network_api.remove_port(network_id, self.dpid, port.ofport)
ports = self.ifaces.get_key(iface_id, QuantumIfaces.KEY_PORTS)
+ other_ovs_ports = None
for p in ports:
dpid = p.get(QuantumIfaces.SUBKEY_DATAPATH_ID)
if dpid is None:
@@ -201,9 +208,9 @@ class OVSSwitch(object):
other_ovs_ports = self.ifaces.del_key(iface_id,
QuantumIfaces.KEY_PORTS,
p)
- if other_ovs_ports:
- # When live-migration, one of the two OVS ports is deleted.
- return
+ if other_ovs_ports:
+ # When live-migration, one of the two OVS ports is deleted.
+ return
port_data = {
'datapath_id': dpid_lib.dpid_to_str(self.dpid),
@@ -227,11 +234,6 @@ class OVSSwitch(object):
return
# update {network, port, mac}
- try:
- network_id = self.ifaces.get_key(iface_id,
- QuantumIfaces.KEY_NETWORK_ID)
- except KeyError:
- return
self.network_api.update_network(network_id)
self.network_api.update_port(network_id, self.dpid, port.ofport)
mac = port.ext_ids.get('attached-mac')
@@ -240,7 +242,6 @@ class OVSSwitch(object):
mac_lib.haddr_to_bin(mac))
def update_port(self, port_no, port_name, add):
- port_name = port_name.rstrip('\x00')
LOG.debug('update_port port_no %d %s %s', port_no, port_name, add)
assert port_name is not None
old_port = self.ports.get(port_no)
@@ -252,9 +253,9 @@ class OVSSwitch(object):
if self.ovs_bridge:
port_cfg = self.ovs_bridge.get_quantum_ports(port_name)
if port_cfg:
- if 'ofport' not in port_cfg:
+ if 'ofport' not in port_cfg or not port_cfg['ofport']:
port_cfg['ofport'] = port_no
- if port_cfg['ofport'] != port_no:
+ elif port_cfg['ofport'] != port_no:
LOG.warn('inconsistent port_no: %d port_cfg %s',
port_no, port_cfg)
return
@@ -369,12 +370,14 @@ class QuantumAdapter(app_manager.RyuApp):
@handler.set_ev_cls(dpset.EventPortAdd)
def port_add_handler(self, ev):
port = ev.port
- self._port_handler(ev.dp.id, port.port_no, port.name, True)
+ name = port.name.rstrip('\0')
+ self._port_handler(ev.dp.id, port.port_no, name, True)
@handler.set_ev_cls(dpset.EventPortDelete)
def port_del_handler(self, ev):
port = ev.port
- self._port_handler(ev.dp.id, port.port_no, port.name, False)
+ name = port.name.rstrip('\0')
+ self._port_handler(ev.dp.id, port.port_no, name, False)
def _conf_switch_set_ovsdb_addr(self, dpid, value):
ovs_switch = self._get_ovs_switch(dpid)
diff --git a/ryu/app/tunnel_port_updater.py b/ryu/app/tunnel_port_updater.py
index 4fdd8ce8..2946737a 100644
--- a/ryu/app/tunnel_port_updater.py
+++ b/ryu/app/tunnel_port_updater.py
@@ -431,17 +431,20 @@ class TunnelPortUpdater(app_manager.RyuApp):
def _vm_port_del(self, network_id, dpid):
LOG.debug('_vm_port_del %s %s', network_id, dpid_lib.dpid_to_str(dpid))
- if len(self.nw.get_ports(dpid, network_id)) > 1:
+ if len(self.nw.get_ports(dpid, network_id)) > 0:
return
- tunnel_networks = self.nw.get_networks(dpid).copy()
+ tunnel_networks = set(p.network_id
+ for p in self.nw.get_networks(dpid))
tunnel_networks.discard(network_id)
tunnel_networks.difference_update(rest_nw_id.RESERVED_NETWORK_IDS)
dpids = self.nw.get_dpids(network_id).copy()
dpids.discard(dpid)
del_dpids = []
for remote_dpid in dpids:
- if tunnel_networks & self.nw.get_networks(remote_dpid):
+ remote_networks = set(p.network_id
+ for p in self.nw.get_networks(remote_dpid))
+ if tunnel_networks & remote_networks:
continue
self.tunnel_requests.remove(dpid, remote_dpid)
del_dpids.append(remote_dpid)
diff --git a/ryu/controller/network.py b/ryu/controller/network.py
index 4663809c..dff8e7c0 100644
--- a/ryu/controller/network.py
+++ b/ryu/controller/network.py
@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import collections
import logging
from ryu.base import app_manager
@@ -145,7 +146,7 @@ class Port(object):
class DPIDs(dict):
- """dpid -> port_no -> network_id"""
+ """dpid -> port_no -> Port(port_no, network_id, mac_address)"""
def __init__(self, f, nw_id_unknown):
super(DPIDs, self).__init__()
self.send_event = f
@@ -180,11 +181,16 @@ class DPIDs(dict):
except KeyError:
raise PortNotFound(dpid=dpid, port=port_no, network_id=None)
- def get_ports(self, dpid, network_id=None):
+ def get_ports(self, dpid, network_id=None, mac_address=None):
if network_id is None:
return self.get(dpid, {}).values()
+ if mac_address is None:
+ return [p for p in self.get(dpid, {}).values()
+ if p.network_id == network_id]
+
+ # live-migration: There can be two ports that have same mac address.
return [p for p in self.get(dpid, {}).values()
- if p.network_id == network_id]
+ if p.network_id == network_id and p.mac_address == mac_address]
def get_port(self, dpid, port_no):
try:
@@ -242,6 +248,48 @@ class DPIDs(dict):
mac_address=port.mac_address)
+MacPort = collections.namedtuple('MacPort', ('dpid', 'port_no'))
+
+
+class MacToPort(collections.defaultdict):
+ """mac_address -> set of MacPort(dpid, port_no)"""
+ def __init__(self):
+ super(MacToPort, self).__init__(set)
+
+ def add_port(self, dpid, port_no, mac_address):
+ self[mac_address].add(MacPort(dpid, port_no))
+
+ def remove_port(self, dpid, port_no, mac_address):
+ ports = self[mac_address]
+ ports.discard(MacPort(dpid, port_no))
+ if not ports:
+ del self[mac_address]
+
+ def get_ports(self, mac_address):
+ return self[mac_address]
+
+
+class MacAddresses(dict):
+ """network_id -> mac_address -> set of (dpid, port_no)"""
+ def add_port(self, network_id, dpid, port_no, mac_address):
+ mac2port = self.setdefault(network_id, MacToPort())
+ mac2port.add_port(dpid, port_no, mac_address)
+
+ def remove_port(self, network_id, dpid, port_no, mac_address):
+ mac2port = self.get(network_id)
+ if mac2port is None:
+ return
+ mac2port.remove_port(dpid, port_no, mac_address)
+ if not mac2port:
+ del self[network_id]
+
+ def get_ports(self, network_id, mac_address):
+ mac2port = self.get(network_id)
+ if not mac2port:
+ return set()
+ return mac2port.get_ports(mac_address)
+
+
class Network(app_manager.RyuApp):
def __init__(self, nw_id_unknown=NW_ID_UNKNOWN):
super(Network, self).__init__()
@@ -249,6 +297,7 @@ class Network(app_manager.RyuApp):
self.nw_id_unknown = nw_id_unknown
self.networks = Networks(self.send_event_to_observers)
self.dpids = DPIDs(self.send_event_to_observers, nw_id_unknown)
+ self.mac_addresses = MacAddresses()
def _check_nw_id_unknown(self, network_id):
if network_id == self.nw_id_unknown:
@@ -303,10 +352,25 @@ class Network(app_manager.RyuApp):
def update_port(self, network_id, dpid, port):
self._update_port(network_id, dpid, port, True)
- def remove_port(self, network_id, dpid, port):
+ def _get_old_mac(self, network_id, dpid, port_no):
+ try:
+ port = self.dpids.get_port(dpid, port_no)
+ except PortNotFound:
+ pass
+ else:
+ if port.network_id == network_id:
+ return port.mac_address
+ return None
+
+ def remove_port(self, network_id, dpid, port_no):
# generate event first, then do the real task
- self.dpids.remove_port(dpid, port)
- self.networks.remove(network_id, dpid, port)
+ old_mac_address = self._get_old_mac(network_id, dpid, port_no)
+
+ self.dpids.remove_port(dpid, port_no)
+ self.networks.remove(network_id, dpid, port_no)
+ if old_mac_address is not None:
+ self.mac_addresses.remove_port(network_id, dpid, port_no,
+ old_mac_address)
#
# methods for gre tunnel
@@ -322,10 +386,17 @@ class Network(app_manager.RyuApp):
return self.dpids.get_networks(dpid)
def create_mac(self, network_id, dpid, port_no, mac_address):
+ self.mac_addresses.add_port(network_id, dpid, port_no, mac_address)
self.dpids.set_mac(network_id, dpid, port_no, mac_address)
def update_mac(self, network_id, dpid, port_no, mac_address):
+ old_mac_address = self._get_old_mac(network_id, dpid, port_no)
+
self.dpids.update_mac(network_id, dpid, port_no, mac_address)
+ if old_mac_address is not None:
+ self.mac_addresses.remove_port(network_id, dpid, port_no,
+ old_mac_address)
+ self.mac_addresses.add_port(network_id, dpid, port_no, mac_address)
def get_mac(self, dpid, port_no):
return self.dpids.get_mac(dpid, port_no)
@@ -336,12 +407,15 @@ class Network(app_manager.RyuApp):
return []
return [mac_address]
- def get_ports(self, dpid, network_id=None):
- return self.dpids.get_ports(dpid, network_id)
+ def get_ports(self, dpid, network_id=None, mac_address=None):
+ return self.dpids.get_ports(dpid, network_id, mac_address)
def get_port(self, dpid, port_no):
return self.dpids.get_port(dpid, port_no)
+ def get_ports_with_mac(self, network_id, mac_address):
+ return self.mac_addresses.get_ports(network_id, mac_address)
+
#
# methods for simple_isolation
#
diff --git a/ryu/lib/mac.py b/ryu/lib/mac.py
index 3cb2df39..d6c4bf1b 100644
--- a/ryu/lib/mac.py
+++ b/ryu/lib/mac.py
@@ -35,6 +35,8 @@ def is_multicast(addr):
def haddr_to_str(addr):
"""Format mac address in internal representation into human readable
form"""
+ if addr is None:
+ return 'None'
assert len(addr) == _HADDR_LEN
return ':'.join('%02x' % ord(char) for char in addr)
diff --git a/ryu/lib/ovs/vsctl.py b/ryu/lib/ovs/vsctl.py
index bda1dd62..4269141d 100644
--- a/ryu/lib/ovs/vsctl.py
+++ b/ryu/lib/ovs/vsctl.py
@@ -1309,7 +1309,6 @@ class VSCtl(object):
else:
# When port is created, ofport column might be None.
# So try with port name if it happended
- port_name = port_name.rstrip('\0')
for vsctl_port in br.ports:
iface_cfgs.extend(
self._iface_to_dict(vsctl_iface.iface_cfg)