diff --git a/NEWS b/NEWS
index ea7f3a1..156781c 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ Post-v2.5.0
        now implemented.  Only flow mod and port mod messages are supported
        in bundles.
      * New OpenFlow extension NXM_NX_MPLS_TTL to provide access to MPLS TTL.
+     * Port name can now be set with "ofname" column in the Interface table.
    - ovs-ofctl:
      * queue-get-config command now allows a queue ID to be specified.
      * '--bundle' option can now be used with OpenFlow 1.3.
diff --git a/lib/db-ctl-base.h b/lib/db-ctl-base.h
index f8f576b..5bd62d5 100644
--- a/lib/db-ctl-base.h
+++ b/lib/db-ctl-base.h
@@ -177,7 +177,7 @@ struct weak_ref_table {
 struct cmd_show_table {
     const struct ovsdb_idl_table_class *table;
     const struct ovsdb_idl_column *name_column;
-    const struct ovsdb_idl_column *columns[3]; /* Seems like a good number. */
+    const struct ovsdb_idl_column *columns[4]; /* Seems like a good number. */
     const struct weak_ref_table wref_table;
 };
 
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index daa0077..8795242 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -84,6 +84,7 @@ struct ofproto {
     struct hmap ports;          /* Contains "struct ofport"s. */
     struct shash port_by_name;
     struct simap ofp_requests;  /* OpenFlow port number requests. */
+    struct smap ofp_names;      /* OpenFlow port names. */
     uint16_t alloc_port_no;     /* Last allocated OpenFlow port number. */
     uint16_t max_ports;         /* Max possible OpenFlow port num, plus one. */
     struct hmap ofport_usage;   /* Map ofport to last used time. */
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index ff6affd..a2799f4 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -550,6 +550,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     hmap_init(&ofproto->ofport_usage);
     shash_init(&ofproto->port_by_name);
     simap_init(&ofproto->ofp_requests);
+    smap_init(&ofproto->ofp_names);
     ofproto->max_ports = ofp_to_u16(OFPP_MAX);
     ofproto->eviction_group_timer = LLONG_MIN;
     ofproto->tables = NULL;
@@ -1546,6 +1547,7 @@ ofproto_destroy__(struct ofproto *ofproto)
     hmap_destroy(&ofproto->ofport_usage);
     shash_destroy(&ofproto->port_by_name);
     simap_destroy(&ofproto->ofp_requests);
+    smap_destroy(&ofproto->ofp_names);
 
     OFPROTO_FOR_EACH_TABLE (table, ofproto) {
         oftable_destroy(table);
@@ -1945,7 +1947,7 @@ ofproto_port_open_type(const char *datapath_type, const char *port_type)
  * 'ofp_portp' is non-null). */
 int
 ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
-                 ofp_port_t *ofp_portp)
+                 ofp_port_t *ofp_portp, const char *ofp_name)
 {
     ofp_port_t ofp_port = ofp_portp ? *ofp_portp : OFPP_NONE;
     int error;
@@ -1956,6 +1958,9 @@ ofproto_port_add(struct ofproto *ofproto, struct netdev *netdev,
 
         simap_put(&ofproto->ofp_requests, netdev_name,
                   ofp_to_u16(ofp_port));
+        if (ofp_name) {
+            smap_replace(&ofproto->ofp_names, netdev_name, ofp_name);
+        }
         error = update_port(ofproto, netdev_name);
     }
     if (ofp_portp) {
@@ -2009,6 +2014,8 @@ ofproto_port_del(struct ofproto *ofproto, ofp_port_t ofp_port)
         simap_delete(&ofproto->ofp_requests, ofp_request_node);
     }
 
+    smap_remove(&ofproto->ofp_names, name);
+
     error = ofproto->ofproto_class->port_del(ofproto, ofp_port);
     if (!error && ofport) {
         /* 'name' is the netdev's name and update_port() is going to close the
@@ -2285,6 +2292,7 @@ ofport_open(struct ofproto *ofproto,
 {
     enum netdev_flags flags;
     struct netdev *netdev;
+    const char *ofp_name;
     int error;
 
     error = netdev_open(ofproto_port->name, ofproto_port->type, &netdev);
@@ -2307,7 +2315,13 @@ ofport_open(struct ofproto *ofproto,
     }
     pp->port_no = ofproto_port->ofp_port;
     netdev_get_etheraddr(netdev, &pp->hw_addr);
-    ovs_strlcpy(pp->name, ofproto_port->name, sizeof pp->name);
+
+    ofp_name = smap_get(&ofproto->ofp_names, ofproto_port->name);
+    if (!ofp_name) {
+        ofp_name = ofproto_port->name;
+    }
+    ovs_strlcpy(pp->name, ofp_name, sizeof pp->name);
+
     netdev_get_flags(netdev, &flags);
     pp->config = flags & NETDEV_UP ? 0 : OFPUTIL_PC_PORT_DOWN;
     pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN;
@@ -8011,3 +8025,52 @@ ofproto_port_set_realdev(struct ofproto *ofproto, ofp_port_t vlandev_ofp_port,
     }
     return error;
 }
+
+const char *
+ofproto_port_get_ofpname(struct ofproto *ofproto, ofp_port_t ofp_port)
+{
+    struct ofport *ofport;
+
+    ofport = ofproto_get_port(ofproto, ofp_port);
+    return (ofport ? ofport->pp.name : NULL);
+}
+
+void
+ofproto_port_set_ofpname(struct ofproto *ofproto, ofp_port_t ofp_port,
+                         const char *ofp_name)
+{
+    struct ofport *ofport;
+    const char *devname;
+    size_t name_size;
+
+    ofport = ofproto_get_port(ofproto, ofp_port);
+    if (!ofport) {
+        return;
+    }
+
+    devname = netdev_get_name(ofport->netdev);
+    name_size = sizeof(ofport->pp.name);
+
+    if (!devname ||
+        (ofp_name && !strncmp(ofp_name, ofport->pp.name, name_size - 1)) ||
+        (!ofp_name && !strncmp(devname, ofport->pp.name, name_size - 1))) {
+        /* No need to change port name. */
+        return;
+    }
+
+    /* Send a OFPPR_DELETE followed by OFPPR_ADD port_status message
+     * to notify controller a port name change. */
+    connmgr_send_port_status(ofproto->connmgr, NULL, &ofport->pp,
+                             OFPPR_DELETE);
+
+    if (!ofp_name) {
+        smap_remove(&ofproto->ofp_names, devname);
+        ovs_strlcpy(ofport->pp.name, devname, name_size);
+    } else {
+        smap_replace(&ofproto->ofp_names, netdev_get_name(ofport->netdev),
+                 ofp_name);
+        ovs_strlcpy(ofport->pp.name, ofp_name, name_size);
+    }
+    connmgr_send_port_status(ofproto->connmgr, NULL, &ofport->pp,
+                             OFPPR_ADD);
+}
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 2d241c9..3382ef1 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -288,7 +288,8 @@ int ofproto_port_dump_done(struct ofproto_port_dump *);
 
 const char *ofproto_port_open_type(const char *datapath_type,
                                    const char *port_type);
-int ofproto_port_add(struct ofproto *, struct netdev *, ofp_port_t *ofp_portp);
+int ofproto_port_add(struct ofproto *, struct netdev *, ofp_port_t *ofp_portp,
+                     const char *);
 int ofproto_port_del(struct ofproto *, ofp_port_t ofp_port);
 int ofproto_port_get_stats(const struct ofport *, struct netdev_stats *stats);
 
@@ -521,6 +522,12 @@ int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
 enum ofputil_table_miss ofproto_table_get_miss_config(const struct ofproto *,
                                                       uint8_t table_id);
 
+const char *ofproto_port_get_ofpname(struct ofproto *ofproto,
+                                     ofp_port_t ofp_port);
+void ofproto_port_set_ofpname(struct ofproto *ofproto,
+                              ofp_port_t ofp_port,
+                              const char *ofp_name);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/tests/ofproto.at b/tests/ofproto.at
index c4260ab..5f38160 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -77,6 +77,66 @@ OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto - set OpenFlow port name])
+OVS_VSWITCHD_START(
+       [add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 --\
+        add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2 ofname=n2])
+check_ofname () {
+    AT_CHECK([ovs-ofctl -vwarn show br0], [0], [stdout])
+    echo >expout "OFPT_FEATURES_REPLY: dpid:fedcba9876543210
+n_tables:254, n_buffers:256
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IP
+actions: output enqueue set_vlan_vid set_vlan_pcp strip_vlan mod_dl_src mod_dl_dst mod_nw_src mod_nw_dst mod_nw_tos mod_tp_src mod_tp_dst
+ 1($1): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+ 2(n2): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+ LOCAL(br0): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+OFPT_GET_CONFIG_REPLY: frags=normal miss_send_len=0"
+    AT_CHECK([[sed '
+s/ (xid=0x[0-9a-fA-F]*)//
+s/00:0.$/00:0x/' < stdout]],
+      [0], [expout])
+}
+
+AT_CHECK([ovs-vsctl set Interface p1 ofname=p2])
+check_ofname p2
+
+AT_CHECK([ovs-ofctl -P standard monitor br0 --detach --no-chdir --pidfile])
+# Use NXT_SET_ASYNC_CONFIG to enable only port status message
+ovs-appctl -t ovs-ofctl ofctl/send 01040028000000020000232000000013000000000000000500000007000000020000000000000005
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+AT_CHECK([ovs-vsctl set Interface p1 ofname=n2])
+check_ofname n2
+OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
+AT_CHECK([[sed '
+s/ (xid=0x[0-9a-fA-F]*)//
+s/ *duration.*//
+s/00:0.$/00:0x/' < monitor.log]],
+      [0], [dnl
+OFPT_PORT_STATUS: DEL: 1(p2): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+OFPT_PORT_STATUS: ADD: 1(n2): addr:aa:55:aa:55:00:0x
+     config:     PORT_DOWN
+     state:      LINK_DOWN
+     speed: 0 Mbps now, 0 Mbps max
+])
+
+AT_CHECK([ovs-vsctl clear Interface p1 ofname])
+check_ofname p1
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 dnl This is really bare-bones.
 dnl It at least checks request and reply serialization and deserialization.
 AT_SETUP([ofproto - port stats - (OpenFlow 1.0)])
diff --git a/utilities/ovs-vsctl.c b/utilities/ovs-vsctl.c
index c9c0f6d..44b386a 100644
--- a/utilities/ovs-vsctl.c
+++ b/utilities/ovs-vsctl.c
@@ -1008,6 +1008,7 @@ static struct cmd_show_table cmd_show_tables[] = {
     {&ovsrec_table_interface,
      &ovsrec_interface_col_name,
      {&ovsrec_interface_col_type,
+      &ovsrec_interface_col_ofname,
       &ovsrec_interface_col_options,
       &ovsrec_interface_col_error},
      {NULL, NULL, NULL}
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 700f65c..bb49fe0 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -667,6 +667,10 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
 
             LIST_FOR_EACH (iface, port_elem, &port->ifaces) {
                 iface_set_ofport(iface->cfg, iface->ofp_port);
+
+                ofproto_port_set_ofpname(br->ofproto, iface->ofp_port,
+                                         iface->cfg->ofname);
+
                 /* Clear eventual previous errors */
                 ovsrec_interface_set_error(iface->cfg, NULL);
                 iface_configure_cfm(iface);
@@ -1777,7 +1781,8 @@ iface_do_create(const struct bridge *br,
     }
 
     *ofp_portp = iface_pick_ofport(iface_cfg);
-    error = ofproto_port_add(br->ofproto, netdev, ofp_portp);
+    error = ofproto_port_add(br->ofproto, netdev, ofp_portp,
+                             iface_cfg->ofname);
     if (error) {
         goto error;
     }
@@ -1860,7 +1865,8 @@ iface_create(struct bridge *br, const struct ovsrec_interface *iface_cfg,
             error = netdev_open(port->name, "internal", &netdev);
             if (!error) {
                 ofp_port_t fake_ofp_port = OFPP_NONE;
-                ofproto_port_add(br->ofproto, netdev, &fake_ofp_port);
+                ofproto_port_add(br->ofproto, netdev, &fake_ofp_port,
+                                 iface_cfg->ofname);
                 netdev_close(netdev);
             } else {
                 VLOG_WARN("could not open network device %s (%s)",
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index e0937f4..d147d04 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "7.13.0",
- "cksum": "2202834738 22577",
+ "version": "7.13.1",
+ "cksum": "643309718 22653",
  "tables": {
    "Open_vSwitch": {
      "columns": {
@@ -204,6 +204,8 @@
          "mutable": false},
        "type": {
          "type": "string"},
+       "ofname": {
+         "type": {"key": "string", "min": 0, "max": 1}},
        "options": {
          "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
        "ingress_policing_rate": {
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 166f264..1869c81 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -1724,6 +1724,20 @@
         on a host.
       </column>
 
+
+      <column name="ofname">
+        <p>
+          OpenFlow port name for this interface. This name is truncated to
+          <code>OFP_MAX_PORT_NAME_LEN-1</code>, and reported to controllers in
+          port description. If not set, <ref column='name'/> is used.
+        </p>
+        <p>
+          OpenFlow does not have a way to announce a port name change, so if
+          <ref column="ofname"/> is changed, Open vSwitch represents it over
+          OpenFlow as a port deletion followed immediately by a port addition.
+        </p>
+      </column>
+
       <column name="ifindex">
         A positive interface index as defined for SNMP MIB-II in RFCs 1213 and
         2863, if the interface has one, otherwise 0.  The ifindex is useful for
