Signed-off-by: Ben Pfaff <b...@nicira.com>
---
 include/openflow/openflow-1.4.h | 44 +++++++++++++++++++--
 lib/ofp-msgs.h                  |  7 +++-
 lib/ofp-print.c                 |  2 +-
 lib/ofp-util.c                  | 86 ++++++++++++++++++++++++++++++++++++++---
 lib/ofp-util.h                  |  2 +-
 ofproto/ofproto.c               |  2 +-
 tests/ofp-print.at              | 14 +++++++
 tests/ofproto.at                | 32 +++++++++++++++
 8 files changed, 175 insertions(+), 14 deletions(-)

diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index 9c03cf4..08f98f9 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -38,9 +38,11 @@
 #define OPENFLOW_14_H 1
 
 #include "openflow/openflow-1.3.h"
-/*
- * OpenFlow 1.4 is more extensible by using TLV structures
- */
+
+
+/* ## ---------- ## */
+/* ## ofp14_port ## */
+/* ## ---------- ## */
 
 /* Port description property types. */
 enum ofp_port_desc_prop_type {
@@ -81,6 +83,42 @@ struct ofp14_port {
 };
 OFP_ASSERT(sizeof(struct ofp14_port) == 40);
 
+
+/* ## -------------- ## */
+/* ## ofp14_port_mod ## */
+/* ## -------------- ## */
+
+enum ofp14_port_mod_prop_type {
+    OFPPMPT14_ETHERNET          = 0,      /* Ethernet property. */
+    OFPPMPT14_OPTICAL           = 1,      /* Optical property. */
+    OFPPMPT14_EXPERIMENTER      = 0xFFFF, /* Experimenter property. */
+};
+
+/* Ethernet port mod property. */
+struct ofp14_port_mod_prop_ethernet {
+    ovs_be16      type;       /* OFPPMPT14_ETHERNET. */
+    ovs_be16      length;     /* Length in bytes of this property. */
+    ovs_be32      advertise;  /* Bitmap of OFPPF_*.  Zero all bits to prevent
+                                 any action taking place. */
+};
+OFP_ASSERT(sizeof(struct ofp14_port_mod_prop_ethernet) == 8);
+
+struct ofp14_port_mod {
+    ovs_be32 port_no;
+    uint8_t pad[4];
+    uint8_t hw_addr[OFP_ETH_ALEN];
+    uint8_t pad2[2];
+    ovs_be32 config;        /* Bitmap of OFPPC_* flags. */
+    ovs_be32 mask;          /* Bitmap of OFPPC_* flags to be changed. */
+    /* Followed by 0 or more OFPPMPT14_* properties. */
+};
+OFP_ASSERT(sizeof(struct ofp14_port_mod) == 24);
+
+
+/* ## -------------- ## */
+/* ## Miscellaneous. ## */
+/* ## -------------- ## */
+
 /* Common header for all async config Properties */
 struct ofp14_async_config_prop_header {
     ovs_be16    type;       /* One of OFPACPT_*. */
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index b548f6b..45271b7 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -184,8 +184,10 @@ enum ofpraw {
 
     /* OFPT 1.0 (15): struct ofp10_port_mod. */
     OFPRAW_OFPT10_PORT_MOD,
-    /* OFPT 1.1+ (16): struct ofp11_port_mod. */
+    /* OFPT 1.1-1.3 (16): struct ofp11_port_mod. */
     OFPRAW_OFPT11_PORT_MOD,
+    /* OFPT 1.4+ (16): struct ofp14_port_mod, uint8_t[8][]. */
+    OFPRAW_OFPT14_PORT_MOD,
 
     /* OFPT 1.1+ (17): struct ofp11_table_mod. */
     OFPRAW_OFPT11_TABLE_MOD,
@@ -486,7 +488,8 @@ enum ofptype {
                                   * OFPRAW_NXT_FLOW_MOD. */
     OFPTYPE_GROUP_MOD,           /* OFPRAW_OFPT11_GROUP_MOD. */
     OFPTYPE_PORT_MOD,            /* OFPRAW_OFPT10_PORT_MOD.
-                                  * OFPRAW_OFPT11_PORT_MOD. */
+                                  * OFPRAW_OFPT11_PORT_MOD.
+                                  * OFPRAW_OFPT14_PORT_MOD. */
     OFPTYPE_TABLE_MOD,           /* OFPRAW_OFPT11_TABLE_MOD. */
 
     /* Barrier messages. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 909a846..ba808af 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -970,7 +970,7 @@ ofp_print_port_mod(struct ds *string, const struct 
ofp_header *oh)
     struct ofputil_port_mod pm;
     enum ofperr error;
 
-    error = ofputil_decode_port_mod(oh, &pm);
+    error = ofputil_decode_port_mod(oh, &pm, true);
     if (error) {
         ofp_print_error(string, error);
         return;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 33d1728..3a6eb5d 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -3989,10 +3989,8 @@ ofputil_capabilities_mask(enum ofp_version ofp_version)
         return OFPC_COMMON | OFPC_ARP_MATCH_IP;
     case OFP12_VERSION:
     case OFP13_VERSION:
-        return OFPC_COMMON | OFPC12_PORT_BLOCKED;
     case OFP14_VERSION:
-        OVS_NOT_REACHED();
-        break;
+        return OFPC_COMMON | OFPC12_PORT_BLOCKED;
     default:
         /* Caller needs to check osf->header.version itself */
         return 0;
@@ -4250,11 +4248,25 @@ ofputil_encode_port_status(const struct 
ofputil_port_status *ps,
 
 /* ofputil_port_mod */
 
+static enum ofperr
+parse_port_mod_ethernet_property(struct ofpbuf *property,
+                                 struct ofputil_port_mod *pm)
+{
+    struct ofp14_port_mod_prop_ethernet *eth = ofpbuf_data(property);
+
+    if (ofpbuf_size(property) != sizeof *eth) {
+        return OFPERR_OFPBRC_BAD_LEN;
+    }
+
+    pm->advertise = netdev_port_features_from_ofp11(eth->advertise);
+    return 0;
+}
+
 /* Decodes the OpenFlow "port mod" message in '*oh' into an abstract form in
  * '*pm'.  Returns 0 if successful, otherwise an OFPERR_* value. */
 enum ofperr
 ofputil_decode_port_mod(const struct ofp_header *oh,
-                        struct ofputil_port_mod *pm)
+                        struct ofputil_port_mod *pm, bool loose)
 {
     enum ofpraw raw;
     struct ofpbuf b;
@@ -4283,6 +4295,52 @@ ofputil_decode_port_mod(const struct ofp_header *oh,
         pm->config = ntohl(opm->config) & OFPPC11_ALL;
         pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
         pm->advertise = netdev_port_features_from_ofp11(opm->advertise);
+    } else if (raw == OFPRAW_OFPT14_PORT_MOD) {
+        const struct ofp14_port_mod *opm = ofpbuf_pull(&b, sizeof *opm);
+        enum ofperr error;
+
+        memset(pm, 0, sizeof *pm);
+
+        error = ofputil_port_from_ofp11(opm->port_no, &pm->port_no);
+        if (error) {
+            return error;
+        }
+
+        memcpy(pm->hw_addr, opm->hw_addr, ETH_ADDR_LEN);
+        pm->config = ntohl(opm->config) & OFPPC11_ALL;
+        pm->mask = ntohl(opm->mask) & OFPPC11_ALL;
+
+        while (ofpbuf_size(&b) > 0) {
+            struct ofpbuf property;
+            enum ofperr error;
+            uint16_t type;
+
+            error = ofputil_pull_property(&b, &property, &type);
+            if (error) {
+                return error;
+            }
+
+            switch (type) {
+            case OFPPMPT14_ETHERNET:
+                error = parse_port_mod_ethernet_property(&property, pm);
+                break;
+
+            default:
+                log_property(loose, "unknown port_mod property %"PRIu16, type);
+                if (loose) {
+                    error = 0;
+                } else if (type == OFPPMPT14_EXPERIMENTER) {
+                    error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
+                } else {
+                    error = OFPERR_OFPBRC_BAD_TYPE;
+                }
+                break;
+            }
+
+            if (error) {
+                return error;
+            }
+        }
     } else {
         return OFPERR_OFPBRC_BAD_TYPE;
     }
@@ -4329,9 +4387,25 @@ ofputil_encode_port_mod(const struct ofputil_port_mod 
*pm,
         opm->advertise = netdev_port_features_to_ofp11(pm->advertise);
         break;
     }
-    case OFP14_VERSION:
-        OVS_NOT_REACHED();
+    case OFP14_VERSION: {
+        struct ofp14_port_mod_prop_ethernet *eth;
+        struct ofp14_port_mod *opm;
+
+        b = ofpraw_alloc(OFPRAW_OFPT14_PORT_MOD, ofp_version, sizeof *eth);
+        opm = ofpbuf_put_zeros(b, sizeof *opm);
+        opm->port_no = ofputil_port_to_ofp11(pm->port_no);
+        memcpy(opm->hw_addr, pm->hw_addr, ETH_ADDR_LEN);
+        opm->config = htonl(pm->config & OFPPC11_ALL);
+        opm->mask = htonl(pm->mask & OFPPC11_ALL);
+
+        if (pm->advertise) {
+            eth = ofpbuf_put_zeros(b, sizeof *eth);
+            eth->type = htons(OFPPMPT14_ETHERNET);
+            eth->length = htons(sizeof *eth);
+            eth->advertise = netdev_port_features_to_ofp11(pm->advertise);
+        }
         break;
+    }
     default:
         OVS_NOT_REACHED();
     }
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index bb3d647..63e1fd5 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -594,7 +594,7 @@ struct ofputil_port_mod {
 };
 
 enum ofperr ofputil_decode_port_mod(const struct ofp_header *,
-                                    struct ofputil_port_mod *);
+                                    struct ofputil_port_mod *, bool loose);
 struct ofpbuf *ofputil_encode_port_mod(const struct ofputil_port_mod *,
                                        enum ofputil_protocol);
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 557f124..ea11e5d 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3038,7 +3038,7 @@ handle_port_mod(struct ofconn *ofconn, const struct 
ofp_header *oh)
         return error;
     }
 
-    error = ofputil_decode_port_mod(oh, &pm);
+    error = ofputil_decode_port_mod(oh, &pm, false);
     if (error) {
         return error;
     }
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 640d114..7d31d5b 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1025,6 +1025,20 @@ OFPT_PORT_MOD (OF1.3) (xid=0x3):port: 3: 
addr:50:54:00:00:00:01
 ])
 AT_CLEANUP
 
+AT_SETUP([OFPT_PORT_MOD - OF1.4])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+05 10 00 28 00 00 00 03 00 00 00 03 00 00 00 00 \
+50 54 00 00 00 01 00 00 00 00 00 01 00 00 00 01 \
+00 00 00 08 00 00 00 01
+" 3], [0], [dnl
+OFPT_PORT_MOD (OF1.4) (xid=0x3):port: 3: addr:50:54:00:00:00:01
+     config: PORT_DOWN
+     mask:   PORT_DOWN
+     advertise: 10MB-HD
+])
+AT_CLEANUP
+
 AT_SETUP([OFPT_TABLE_MOD - OF1.1])
 AT_KEYWORDS([ofp-print])
 AT_CHECK([ovs-ofctl ofp-print "\
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 2ffe653..b9c6d28 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -423,6 +423,38 @@ done
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto - mod-port (OpenFlow 1.4)])
+OVS_VSWITCHD_START
+for command_config_state in \
+    'up 0 0' \
+    'down PORT_DOWN LINK_DOWN' \
+    'no-receive PORT_DOWN,NO_RECV LINK_DOWN' \
+    'no-forward PORT_DOWN,NO_RECV,NO_FWD LINK_DOWN' \
+    'no-packet-in PORT_DOWN,NO_RECV,NO_FWD,NO_PACKET_IN LINK_DOWN' \
+    'forward PORT_DOWN,NO_RECV,NO_PACKET_IN LINK_DOWN' \
+    'packet-in PORT_DOWN,NO_RECV LINK_DOWN' \
+    'up NO_RECV 0' \
+    'receive 0 0'
+do
+    set $command_config_state
+    command=$[1] config=`echo $[2] | sed 's/,/ /g'` state=$[3]
+    AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn mod-port br0 br0 $command])
+    AT_CHECK([ovs-ofctl -O OpenFlow14 -vwarn show br0], [0], [stdout])
+    AT_CHECK_UNQUOTED([STRIP_XIDS stdout], [0], [dnl
+OFPT_FEATURES_REPLY (OF1.4): dpid:fedcba9876543210
+n_tables:254, n_buffers:256
+capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS
+OFPST_PORT_DESC reply (OF1.4):
+ LOCAL(br0): addr:aa:55:aa:55:00:00
+     config:     $config
+     state:      $state
+     speed: 0 Mbps now, 0 Mbps max
+OFPT_GET_CONFIG_REPLY (OF1.4): frags=normal miss_send_len=0
+])
+done
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto - basic flow_mod commands (NXM)])
 OVS_VSWITCHD_START
 AT_CHECK([ovs-ofctl dump-flows br0 | ofctl_strip], [0], [NXST_FLOW reply:
-- 
1.9.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to