Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 16 Jan 2013 15:24:43 +0000 (16:24 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Wed, 16 Jan 2013 15:24:43 +0000 (16:24 +0100)
Conflicts:
lib/dpif-netdev.c

1  2 
Makefile.am
lib/automake.mk
lib/dpif-netdev.c
lib/dpif-provider.h
lib/dpif.c
lib/netdev-provider.h
lib/netdev.c

diff --combined Makefile.am
@@@ -43,16 -43,17 +43,17 @@@ EXTRA_DIST = 
        DESIGN \
        FAQ \
        INSTALL \
+       INSTALL.Debian \
        INSTALL.Fedora \
        INSTALL.KVM \
        INSTALL.Libvirt \
        INSTALL.RHEL \
        INSTALL.SSL \
        INSTALL.XenServer \
-       INSTALL.bridge \
        INSTALL.userspace \
        IntegrationGuide \
        NOTICE \
+       OPENFLOW-1.1+ \
        PORTING \
        README-gcov \
        REPORTING-BUGS \
@@@ -105,7 -106,6 +106,7 @@@ ro_shell = printf '\043 Generated autom
  
  SUFFIXES += .in
  .in:
 +      @mkdir -p $$(dirname $@)
        $(PERL) $(srcdir)/build-aux/soexpand.pl -I$(srcdir) < $< | \
            sed \
                -e 's,[@]PKIDIR[@],$(PKIDIR),g' \
@@@ -147,7 -147,7 +148,7 @@@ dist-hook-git: distfile
          (cd datapath && $(MAKE) distfiles);                               \
          (cat distfiles; sed 's|^|datapath/|' datapath/distfiles) |        \
            sort -u > all-distfiles;                                        \
 -        (cd $(srcdir) && git ls-files) | grep -v '\.gitignore$$' |        \
 +        (cd $(srcdir) && git ls-files) | grep -vFf $(srcdir)/.non-distfiles |     \
            sort -u > all-gitfiles;                                         \
          comm -1 -3 all-distfiles all-gitfiles > missing-distfiles;        \
          if test -s missing-distfiles; then                                \
@@@ -169,6 -169,20 +170,20 @@@ CLEANFILES += distfile
  endif
  .PHONY: dist-hook-git
  
+ # Check that every .c file includes <config.h>.
+ ALL_LOCAL += config-h-check
+ config-h-check:
+       @cd $(srcdir); \
+       if test -e .git && (git --version) >/dev/null 2>&1 && \
+          git --no-pager grep -L '#include <config\.h>' `git ls-files | grep '\.c$$' | \
+                grep -vE '^datapath|^lib/sflow|^third-party'`; \
+       then \
+           echo "See above for list of violations of the rule that"; \
+           echo "every C source file must #include <config.h>."; \
+           exit 1; \
+       fi
+ .PHONY: config-h-check
  # Check that "struct vlog_ratelimit" is always declared "static".
  ALL_LOCAL += rate-limit-check
  rate-limit-check:
@@@ -212,6 -226,11 +227,11 @@@ install-data-local: $(INSTALL_DATA_LOCA
  uninstall-local: $(UNINSTALL_LOCAL)
  .PHONY: $(DIST_HOOKS) $(CLEAN_LOCAL) $(INSTALL_DATA_LOCAL) $(UNINSTALL_LOCAL)
  
+ modules_install:
+ if LINUX_ENABLED
+       cd datapath/linux && $(MAKE) modules_install
+ endif
  include lib/automake.mk
  include ofproto/automake.mk
  include utilities/automake.mk
@@@ -225,4 -244,3 +245,4 @@@ include rhel/automake.m
  include xenserver/automake.mk
  include python/automake.mk
  include python/compat/automake.mk
 +include planetlab/automake.mk
diff --combined lib/automake.mk
@@@ -88,8 -88,6 +88,8 @@@ lib_libopenvswitch_a_SOURCES = 
        lib/multipath.c \
        lib/multipath.h \
        lib/netdev-dummy.c \
 +      lib/netdev-tunnel.c \
 +      lib/netdev-pltap.c \
        lib/netdev-provider.h \
        lib/netdev.c \
        lib/netdev.h \
        lib/ofp-util.c \
        lib/ofp-util.def \
        lib/ofp-util.h \
+       lib/ofp-version-opt.h \
+       lib/ofp-version-opt.c \
        lib/ofpbuf.c \
        lib/ofpbuf.h \
        lib/ovsdb-data.c \
        lib/timeval.h \
        lib/token-bucket.c \
        lib/token-bucket.h \
 +      lib/tunalloc.c \
 +      lib/tunalloc.h \
        lib/type-props.h \
        lib/unaligned.h \
        lib/unicode.c \
@@@ -291,6 -289,7 +293,7 @@@ MAN_FRAGMENTS += 
        lib/daemon-syn.man \
        lib/leak-checker.man \
        lib/memory-unixctl.man \
+       lib/ofp-version.man \
        lib/ovs.tmac \
        lib/ssl-bootstrap.man \
        lib/ssl-bootstrap-syn.man \
diff --combined lib/dpif-netdev.c
@@@ -138,15 -138,15 +138,15 @@@ static struct shash dp_netdevs = SHASH_
  /* Maximum port MTU seen so far. */
  static int max_mtu = ETH_PAYLOAD_MAX;
  
- static int get_port_by_number(struct dp_netdev *, uint16_t port_no,
+ static int get_port_by_number(struct dp_netdev *, uint32_t port_no,
                                struct dp_netdev_port **portp);
  static int get_port_by_name(struct dp_netdev *, const char *devname,
                              struct dp_netdev_port **portp);
  static void dp_netdev_free(struct dp_netdev *);
  static void dp_netdev_flow_flush(struct dp_netdev *);
  static int do_add_port(struct dp_netdev *, const char *devname,
-                        const char *type, uint16_t port_no);
- static int do_del_port(struct dp_netdev *, uint16_t port_no);
+                        const char *type, uint32_t port_no);
+ static int do_del_port(struct dp_netdev *, uint32_t port_no);
  static int dpif_netdev_open(const struct dpif_class *, const char *name,
                              bool create, struct dpif **);
  static int dp_netdev_output_userspace(struct dp_netdev *, const struct ofpbuf *,
@@@ -181,6 -181,14 +181,22 @@@ dpif_netdev_enumerate(struct sset *all_
      return 0;
  }
  
+ static const char *
+ dpif_netdev_port_open_type(const struct dpif_class *class, const char *type)
+ {
+     return strcmp(type, "internal") ? type
+                   : class != &dpif_netdev_class ? "dummy"
+                   : "tap";
+ }
++static const char *
++dpif_planetlab_port_open_type(const struct dpif_class *class, const char *type)
++{
++    return strcmp(type, "internal") ? type
++                  : class != &dpif_planetlab_class ? "dummy"
++                  : "pltap";
++}
++
  static struct dpif *
  create_dpif_netdev(struct dp_netdev *dp)
  {
      return &dpif->dpif;
  }
  
 -    if (dp->class != &dpif_netdev_class) {
+ static int
+ choose_port(struct dp_netdev *dp, const char *name)
+ {
+     int port_no;
++    if (dp->class != &dpif_netdev_class && 
++        dp->class != &dpif_planetlab_class) {
+         const char *p;
+         int start_no = 0;
+         /* If the port name begins with "br", start the number search at
+          * 100 to make writing tests easier. */
+         if (!strncmp(name, "br", 2)) {
+             start_no = 100;
+         }
+         /* If the port name contains a number, try to assign that port number.
+          * This can make writing unit tests easier because port numbers are
+          * predictable. */
+         for (p = name; *p != '\0'; p++) {
+             if (isdigit((unsigned char) *p)) {
+                 port_no = start_no + strtol(p, NULL, 10);
+                 if (port_no > 0 && port_no < MAX_PORTS
+                     && !dp->ports[port_no]) {
+                     return port_no;
+                 }
+                 break;
+             }
+         }
+     }
+     for (port_no = 1; port_no < MAX_PORTS; port_no++) {
+         if (!dp->ports[port_no]) {
+             return port_no;
+         }
+     }
+     return -1;
+ }
  static int
  create_dp_netdev(const char *name, const struct dpif_class *class,
                   struct dp_netdev **dpp)
      }
      hmap_init(&dp->flow_table);
      list_init(&dp->port_list);
      error = do_add_port(dp, name, "internal", OVSP_LOCAL);
      if (error) {
          dp_netdev_free(dp);
@@@ -316,18 -364,9 +373,9 @@@ dpif_netdev_get_stats(const struct dpi
      return 0;
  }
  
- static const char* internal_port_type(const struct dp_netdev* dp)
- {
-       if (dp->class == &dpif_netdev_class)
-               return "tap";
-       if (dp->class == &dpif_planetlab_class)
-               return "pltap";
-       return "dummy";
- }
  static int
  do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
-             uint16_t port_no)
+             uint32_t port_no)
  {
      struct dp_netdev_port *port;
      struct netdev *netdev;
      /* XXX reject devices already in some dp_netdev. */
  
      /* Open and validate network device. */
-     open_type = (strcmp(type, "internal") ? type : internal_port_type(dp));
+     open_type = dpif_netdev_port_open_type(dp->class, type);
      error = netdev_open(devname, open_type, &netdev);
      if (error) {
          return error;
      return 0;
  }
  
- static int
- choose_port(struct dpif *dpif, struct netdev *netdev)
- {
-     struct dp_netdev *dp = get_dp_netdev(dpif);
-     int port_no;
-     if (dpif->dpif_class != &dpif_netdev_class &&
-         dpif->dpif_class != &dpif_planetlab_class)
-     {
-         /* If the port name contains a number, try to assign that port number.
-          * This can make writing unit tests easier because port numbers are
-          * predictable. */
-         const char *p;
-         for (p = netdev_get_name(netdev); *p != '\0'; p++) {
-             if (isdigit((unsigned char) *p)) {
-                 port_no = strtol(p, NULL, 10);
-                 if (port_no > 0 && port_no < MAX_PORTS
-                     && !dp->ports[port_no]) {
-                     return port_no;
-                 }
-                 break;
-             }
-         }
-     }
-     for (port_no = 0; port_no < MAX_PORTS; port_no++) {
-         if (!dp->ports[port_no]) {
-             return port_no;
-         }
-     }
-     return -1;
- }
  static int
  dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
-                      uint16_t *port_nop)
+                      uint32_t *port_nop)
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
      int port_no;
  
-     if (*port_nop != UINT16_MAX) {
+     if (*port_nop != UINT32_MAX) {
          if (*port_nop >= MAX_PORTS) {
              return EFBIG;
          } else if (dp->ports[*port_nop]) {
          }
          port_no = *port_nop;
      } else {
-         port_no = choose_port(dpif, netdev);
+         port_no = choose_port(dp, netdev_get_name(netdev));
      }
      if (port_no >= 0) {
          *port_nop = port_no;
  }
  
  static int
- dpif_netdev_port_del(struct dpif *dpif, uint16_t port_no)
+ dpif_netdev_port_del(struct dpif *dpif, uint32_t port_no)
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
      return port_no == OVSP_LOCAL ? EINVAL : do_del_port(dp, port_no);
  }
  
  static bool
- is_valid_port_number(uint16_t port_no)
+ is_valid_port_number(uint32_t port_no)
  {
      return port_no < MAX_PORTS;
  }
  
  static int
  get_port_by_number(struct dp_netdev *dp,
-                    uint16_t port_no, struct dp_netdev_port **portp)
+                    uint32_t port_no, struct dp_netdev_port **portp)
  {
      if (!is_valid_port_number(port_no)) {
          *portp = NULL;
@@@ -479,7 -483,7 +492,7 @@@ get_port_by_name(struct dp_netdev *dp
  }
  
  static int
- do_del_port(struct dp_netdev *dp, uint16_t port_no)
+ do_del_port(struct dp_netdev *dp, uint32_t port_no)
  {
      struct dp_netdev_port *port;
      char *name;
@@@ -514,7 -518,7 +527,7 @@@ answer_port_query(const struct dp_netde
  }
  
  static int
- dpif_netdev_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
+ dpif_netdev_port_query_by_number(const struct dpif *dpif, uint32_t port_no,
                                   struct dpif_port *dpif_port)
  {
      struct dp_netdev *dp = get_dp_netdev(dpif);
      int error;
  
      error = get_port_by_number(dp, port_no, &port);
-     if (!error) {
+     if (!error && dpif_port) {
          answer_port_query(port, dpif_port);
      }
      return error;
@@@ -537,7 -541,7 +550,7 @@@ dpif_netdev_port_query_by_name(const st
      int error;
  
      error = get_port_by_name(dp, devname, &port);
-     if (!error) {
+     if (!error && dpif_port) {
          answer_port_query(port, dpif_port);
      }
      return error;
@@@ -666,7 -670,7 +679,7 @@@ static in
  dpif_netdev_flow_from_nlattrs(const struct nlattr *key, uint32_t key_len,
                                struct flow *flow)
  {
-     if (odp_flow_key_to_flow(key, key_len, flow)) {
+     if (odp_flow_key_to_flow(key, key_len, flow) != ODP_FIT_PERFECT) {
          /* This should not happen: it indicates that odp_flow_key_from_flow()
           * and odp_flow_key_to_flow() disagree on the acceptable form of a
           * flow.  Log the problem as an error, with enough details to enable
@@@ -875,7 -879,7 +888,7 @@@ dpif_netdev_flow_dump_next(const struc
          struct ofpbuf buf;
  
          ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
-         odp_flow_key_from_flow(&buf, &flow->key);
+         odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port);
  
          *key = buf.data;
          *key_len = buf.size;
@@@ -925,7 -929,7 +938,7 @@@ dpif_netdev_execute(struct dpif *dpif, 
      ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
      ofpbuf_put(&copy, execute->packet->data, execute->packet->size);
  
-     flow_extract(&copy, 0, NULL, -1, &key);
+     flow_extract(&copy, 0, 0, NULL, -1, &key);
      error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
                                            &key);
      if (!error) {
@@@ -1023,7 -1027,7 +1036,7 @@@ dp_netdev_port_input(struct dp_netdev *
      if (packet->size < ETH_HEADER_LEN) {
          return;
      }
-     flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
+     flow_extract(packet, 0, 0, NULL, port->port_no, &key);
      flow = dp_netdev_lookup_flow(dp, &key);
      if (flow) {
          dp_netdev_flow_used(flow, packet);
@@@ -1086,7 -1090,7 +1099,7 @@@ dp_netdev_set_dl(struct ofpbuf *packet
  
  static void
  dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
-                       uint16_t out_port)
+                       uint32_t out_port)
  {
      struct dp_netdev_port *p = dp->ports[out_port];
      if (p) {
@@@ -1113,7 -1117,7 +1126,7 @@@ dp_netdev_output_userspace(struct dp_ne
  
      buf = &u->buf;
      ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
-     odp_flow_key_from_flow(buf, flow);
+     odp_flow_key_from_flow(buf, flow, flow->in_port);
      key_len = buf->size;
      ofpbuf_pull(buf, key_len);
      ofpbuf_reserve(buf, 2);
@@@ -1181,13 -1185,14 +1194,14 @@@ execute_set_action(struct ofpbuf *packe
  {
      enum ovs_key_attr type = nl_attr_type(a);
      const struct ovs_key_ipv4 *ipv4_key;
+     const struct ovs_key_ipv6 *ipv6_key;
      const struct ovs_key_tcp *tcp_key;
      const struct ovs_key_udp *udp_key;
  
      switch (type) {
      case OVS_KEY_ATTR_TUN_ID:
      case OVS_KEY_ATTR_PRIORITY:
-     case OVS_KEY_ATTR_IPV6:
+     case OVS_KEY_ATTR_SKB_MARK:
      case OVS_KEY_ATTR_IPV4_TUNNEL:
          /* not implemented */
          break;
                          ipv4_key->ipv4_tos, ipv4_key->ipv4_ttl);
          break;
  
+     case OVS_KEY_ATTR_IPV6:
+         ipv6_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_ipv6));
+         packet_set_ipv6(packet, ipv6_key->ipv6_proto, ipv6_key->ipv6_src,
+                         ipv6_key->ipv6_dst, ipv6_key->ipv6_tclass,
+                         ipv6_key->ipv6_label, ipv6_key->ipv6_hlimit);
+         break;
      case OVS_KEY_ATTR_TCP:
          tcp_key = nl_attr_get_unspec(a, sizeof(struct ovs_key_tcp));
          packet_set_tcp_port(packet, tcp_key->tcp_src, tcp_key->tcp_dst);
@@@ -1274,48 -1286,41 +1295,49 @@@ dp_netdev_execute_actions(struct dp_net
      }
  }
  
- #define DPIF_NETDEV_CLASS_FUNCTIONS                   \
++#define DPIF_NETDEV_CLASS_FUNCTIONS(PORT_OPEN_TYPE)   \
 +    dpif_netdev_enumerate,                            \
++    PORT_OPEN_TYPE,                                   \
 +    dpif_netdev_open,                                 \
 +    dpif_netdev_close,                                        \
 +    dpif_netdev_destroy,                              \
 +    dpif_netdev_run,                                  \
 +    dpif_netdev_wait,                                 \
 +    dpif_netdev_get_stats,                            \
 +    dpif_netdev_port_add,                             \
 +    dpif_netdev_port_del,                             \
 +    dpif_netdev_port_query_by_number,                 \
 +    dpif_netdev_port_query_by_name,                   \
 +    dpif_netdev_get_max_ports,                                \
 +    NULL,                       /* port_get_pid */    \
 +    dpif_netdev_port_dump_start,                      \
 +    dpif_netdev_port_dump_next,                               \
 +    dpif_netdev_port_dump_done,                               \
 +    dpif_netdev_port_poll,                            \
 +    dpif_netdev_port_poll_wait,                               \
 +    dpif_netdev_flow_get,                             \
 +    dpif_netdev_flow_put,                             \
 +    dpif_netdev_flow_del,                             \
 +    dpif_netdev_flow_flush,                           \
 +    dpif_netdev_flow_dump_start,                      \
 +    dpif_netdev_flow_dump_next,                               \
 +    dpif_netdev_flow_dump_done,                               \
 +    dpif_netdev_execute,                              \
 +    NULL,                       /* operate */         \
 +    dpif_netdev_recv_set,                             \
 +    dpif_netdev_queue_to_priority,                    \
 +    dpif_netdev_recv,                                 \
 +    dpif_netdev_recv_wait,                            \
 +    dpif_netdev_recv_purge,                           \
 +
  const struct dpif_class dpif_netdev_class = {
      "netdev",
-     DPIF_NETDEV_CLASS_FUNCTIONS
 -    dpif_netdev_enumerate,
 -    dpif_netdev_port_open_type,
 -    dpif_netdev_open,
 -    dpif_netdev_close,
 -    dpif_netdev_destroy,
 -    dpif_netdev_run,
 -    dpif_netdev_wait,
 -    dpif_netdev_get_stats,
 -    dpif_netdev_port_add,
 -    dpif_netdev_port_del,
 -    dpif_netdev_port_query_by_number,
 -    dpif_netdev_port_query_by_name,
 -    dpif_netdev_get_max_ports,
 -    NULL,                       /* port_get_pid */
 -    dpif_netdev_port_dump_start,
 -    dpif_netdev_port_dump_next,
 -    dpif_netdev_port_dump_done,
 -    dpif_netdev_port_poll,
 -    dpif_netdev_port_poll_wait,
 -    dpif_netdev_flow_get,
 -    dpif_netdev_flow_put,
 -    dpif_netdev_flow_del,
 -    dpif_netdev_flow_flush,
 -    dpif_netdev_flow_dump_start,
 -    dpif_netdev_flow_dump_next,
 -    dpif_netdev_flow_dump_done,
 -    dpif_netdev_execute,
 -    NULL,                       /* operate */
 -    dpif_netdev_recv_set,
 -    dpif_netdev_queue_to_priority,
 -    dpif_netdev_recv,
 -    dpif_netdev_recv_wait,
 -    dpif_netdev_recv_purge,
++    DPIF_NETDEV_CLASS_FUNCTIONS(dpif_netdev_port_open_type)
 +};
 +
 +const struct dpif_class dpif_planetlab_class = {
 +    "planetlab",
-     DPIF_NETDEV_CLASS_FUNCTIONS
++    DPIF_NETDEV_CLASS_FUNCTIONS(dpif_planetlab_port_open_type)
  };
  
  static void
@@@ -1348,4 -1353,3 +1370,4 @@@ dpif_dummy_register(bool override
  
      dpif_dummy_register__("dummy");
  }
 +
diff --combined lib/dpif-provider.h
@@@ -80,6 -80,17 +80,17 @@@ struct dpif_class 
       * case this function may be a null pointer. */
      int (*enumerate)(struct sset *all_dps);
  
+     /* Returns the type to pass to netdev_open() when a dpif of class
+      * 'dpif_class' has a port of type 'type', for a few special cases
+      * when a netdev type differs from a port type.  For example, when
+      * using the userspace datapath, a port of type "internal" needs to
+      * be opened as "tap".
+      *
+      * Returns either 'type' itself or a string literal, which must not
+      * be freed. */
+     const char *(*port_open_type)(const struct dpif_class *dpif_class,
+                                   const char *type);
      /* Attempts to open an existing dpif called 'name', if 'create' is false,
       * or to open an existing dpif or create a new one, if 'create' is true.
       *
      int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats);
  
      /* Adds 'netdev' as a new port in 'dpif'.  If '*port_no' is not
-      * UINT16_MAX, attempts to use that as the port's port number.
+      * UINT32_MAX, attempts to use that as the port's port number.
       *
       * If port is successfully added, sets '*port_no' to the new port's
       * port number.  Returns EBUSY if caller attempted to choose a port
       * number, and it was in use. */
      int (*port_add)(struct dpif *dpif, struct netdev *netdev,
-                     uint16_t *port_no);
+                     uint32_t *port_no);
  
      /* Removes port numbered 'port_no' from 'dpif'. */
-     int (*port_del)(struct dpif *dpif, uint16_t port_no);
+     int (*port_del)(struct dpif *dpif, uint32_t port_no);
  
-     /* Queries 'dpif' for a port with the given 'port_no' or 'devname'.  Stores
-      * information about the port into '*port' if successful.
+     /* Queries 'dpif' for a port with the given 'port_no' or 'devname'.
+      * If 'port' is not null, stores information about the port into
+      * '*port' if successful.
       *
-      * The caller takes ownership of data in 'port' and must free it with
-      * dpif_port_destroy() when it is no longer needed. */
-     int (*port_query_by_number)(const struct dpif *dpif, uint16_t port_no,
+      * If 'port' is not null, the caller takes ownership of data in
+      * 'port' and must free it with dpif_port_destroy() when it is no
+      * longer needed. */
+     int (*port_query_by_number)(const struct dpif *dpif, uint32_t port_no,
                                  struct dpif_port *port);
      int (*port_query_by_name)(const struct dpif *dpif, const char *devname,
                                struct dpif_port *port);
       * actions as the OVS_USERSPACE_ATTR_PID attribute's value, for use in
       * flows whose packets arrived on port 'port_no'.
       *
-      * A 'port_no' of UINT16_MAX should be treated as a special case.  The
+      * A 'port_no' of UINT32_MAX should be treated as a special case.  The
       * implementation should return a reserved PID, not allocated to any port,
       * that the client may use for special purposes.
       *
       *
       * A dpif provider that doesn't have meaningful Netlink PIDs can use NULL
       * for this function.  This is equivalent to always returning 0. */
-     uint32_t (*port_get_pid)(const struct dpif *dpif, uint16_t port_no);
+     uint32_t (*port_get_pid)(const struct dpif *dpif, uint32_t port_no);
  
      /* Attempts to begin dumping the ports in a dpif.  On success, returns 0
       * and initializes '*statep' with any data needed for iteration.  On
  
  extern const struct dpif_class dpif_linux_class;
  extern const struct dpif_class dpif_netdev_class;
 +extern const struct dpif_class dpif_planetlab_class;
  
  #ifdef  __cplusplus
  }
diff --combined lib/dpif.c
@@@ -62,7 -62,6 +62,7 @@@ static const struct dpif_class *base_dp
      &dpif_linux_class,
  #endif
      &dpif_netdev_class,
 +    &dpif_planetlab_class,
  };
  
  struct registered_dpif_class {
@@@ -373,6 -372,13 +373,13 @@@ dpif_base_name(const struct dpif *dpif
      return dpif->base_name;
  }
  
+ /* Returns the type of datapath 'dpif'. */
+ const char *
+ dpif_type(const struct dpif *dpif)
+ {
+     return dpif->dpif_class->type;
+ }
  /* Returns the fully spelled out name for the given datapath 'type'.
   *
   * Normalized type string can be compared with strcmp().  Unnormalized type
@@@ -411,19 -417,36 +418,36 @@@ dpif_get_dp_stats(const struct dpif *dp
      return error;
  }
  
+ const char *
+ dpif_port_open_type(const char *datapath_type, const char *port_type)
+ {
+     struct registered_dpif_class *registered_class;
+     datapath_type = dpif_normalize_type(datapath_type);
+     registered_class = shash_find_data(&dpif_classes, datapath_type);
+     if (!registered_class
+             || !registered_class->dpif_class->port_open_type) {
+         return port_type;
+     }
+     return registered_class->dpif_class->port_open_type(
+                           registered_class->dpif_class, port_type);
+ }
  /* Attempts to add 'netdev' as a port on 'dpif'.  If 'port_nop' is
-  * non-null and its value is not UINT16_MAX, then attempts to use the
+  * non-null and its value is not UINT32_MAX, then attempts to use the
   * value as the port number.
   *
   * If successful, returns 0 and sets '*port_nop' to the new port's port
   * number (if 'port_nop' is non-null).  On failure, returns a positive
-  * errno value and sets '*port_nop' to UINT16_MAX (if 'port_nop' is
+  * errno value and sets '*port_nop' to UINT32_MAX (if 'port_nop' is
   * non-null). */
  int
- dpif_port_add(struct dpif *dpif, struct netdev *netdev, uint16_t *port_nop)
+ dpif_port_add(struct dpif *dpif, struct netdev *netdev, uint32_t *port_nop)
  {
      const char *netdev_name = netdev_get_name(netdev);
-     uint16_t port_no = UINT16_MAX;
+     uint32_t port_no = UINT32_MAX;
      int error;
  
      COVERAGE_INC(dpif_port_add);
  
      error = dpif->dpif_class->port_add(dpif, netdev, &port_no);
      if (!error) {
-         VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
+         VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu32,
                      dpif_name(dpif), netdev_name, port_no);
      } else {
          VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s",
                       dpif_name(dpif), netdev_name, strerror(error));
-         port_no = UINT16_MAX;
+         port_no = UINT32_MAX;
      }
      if (port_nop) {
          *port_nop = port_no;
  /* Attempts to remove 'dpif''s port number 'port_no'.  Returns 0 if successful,
   * otherwise a positive errno value. */
  int
- dpif_port_del(struct dpif *dpif, uint16_t port_no)
+ dpif_port_del(struct dpif *dpif, uint32_t port_no)
  {
      int error;
  
  
      error = dpif->dpif_class->port_del(dpif, port_no);
      if (!error) {
-         VLOG_DBG_RL(&dpmsg_rl, "%s: port_del(%"PRIu16")",
+         VLOG_DBG_RL(&dpmsg_rl, "%s: port_del(%"PRIu32")",
                      dpif_name(dpif), port_no);
      } else {
          log_operation(dpif, "port_del", error);
@@@ -487,6 -510,20 +511,20 @@@ dpif_port_destroy(struct dpif_port *dpi
      free(dpif_port->type);
  }
  
+ /* Checks if port named 'devname' exists in 'dpif'.  If so, returns
+  * true; otherwise, returns false. */
+ bool
+ dpif_port_exists(const struct dpif *dpif, const char *devname)
+ {
+     int error = dpif->dpif_class->port_query_by_name(dpif, devname, NULL);
+     if (error != 0 && error != ENOENT && error != ENODEV) {
+         VLOG_WARN_RL(&error_rl, "%s: failed to query port %s: %s",
+                      dpif_name(dpif), devname, strerror(error));
+     }
+     return !error;
+ }
  /* Looks up port number 'port_no' in 'dpif'.  On success, returns 0 and
   * initializes '*port' appropriately; on failure, returns a positive errno
   * value.
   * The caller owns the data in 'port' and must free it with
   * dpif_port_destroy() when it is no longer needed. */
  int
- dpif_port_query_by_number(const struct dpif *dpif, uint16_t port_no,
+ dpif_port_query_by_number(const struct dpif *dpif, uint32_t port_no,
                            struct dpif_port *port)
  {
      int error = dpif->dpif_class->port_query_by_number(dpif, port_no, port);
      if (!error) {
-         VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu16" is device %s",
+         VLOG_DBG_RL(&dpmsg_rl, "%s: port %"PRIu32" is device %s",
                      dpif_name(dpif), port_no, port->name);
      } else {
          memset(port, 0, sizeof *port);
-         VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu16": %s",
+         VLOG_WARN_RL(&error_rl, "%s: failed to query port %"PRIu32": %s",
                       dpif_name(dpif), port_no, strerror(error));
      }
      return error;
@@@ -521,7 -558,7 +559,7 @@@ dpif_port_query_by_name(const struct dp
  {
      int error = dpif->dpif_class->port_query_by_name(dpif, devname, port);
      if (!error) {
-         VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu16,
+         VLOG_DBG_RL(&dpmsg_rl, "%s: device %s is on port %"PRIu32,
                      dpif_name(dpif), devname, port->port_no);
      } else {
          memset(port, 0, sizeof *port);
@@@ -550,7 -587,7 +588,7 @@@ dpif_get_max_ports(const struct dpif *d
   * as the OVS_USERSPACE_ATTR_PID attribute's value, for use in flows whose
   * packets arrived on port 'port_no'.
   *
-  * A 'port_no' of UINT16_MAX is a special case: it returns a reserved PID, not
+  * A 'port_no' of UINT32_MAX is a special case: it returns a reserved PID, not
   * allocated to any port, that the client may use for special purposes.
   *
   * The return value is only meaningful when DPIF_UC_ACTION has been enabled in
   * update all of the flows that it installed that contain
   * OVS_ACTION_ATTR_USERSPACE actions. */
  uint32_t
- dpif_port_get_pid(const struct dpif *dpif, uint16_t port_no)
+ dpif_port_get_pid(const struct dpif *dpif, uint32_t port_no)
  {
      return (dpif->dpif_class->port_get_pid
              ? (dpif->dpif_class->port_get_pid)(dpif, port_no)
   * result is null-terminated.  On failure, returns a positive errno value and
   * makes 'name' the empty string. */
  int
- dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
+ dpif_port_get_name(struct dpif *dpif, uint32_t port_no,
                     char *name, size_t name_size)
  {
      struct dpif_port port;
diff --combined lib/netdev-provider.h
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
+  * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -139,6 -139,13 +139,13 @@@ struct netdev_class 
       * pointer. */
      int (*set_config)(struct netdev_dev *netdev_dev, const struct smap *args);
  
+     /* Returns the tunnel configuration of 'netdev_dev'.  If 'netdev_dev' is
+      * not a tunnel, returns null.
+      *
+      * If this function would always return null, it may be null instead. */
+     const struct netdev_tunnel_config *
+         (*get_tunnel_config)(const struct netdev_dev *netdev_dev);
      /* Attempts to open a network device.  On success, sets 'netdevp'
       * to the new network device. */
      int (*open)(struct netdev_dev *netdev_dev, struct netdev **netdevp);
  
      /* Retrieves driver information of the device.
       *
-      * Populates 'sh' with key-value pairs representing the status of the
-      * device.  Driver info is a set of key-value string pairs
-      * representing netdev type specific information.  For more information see
+      * Populates 'smap' with key-value pairs representing the status of the
+      * device.  'smap' is a set of key-value string pairs representing netdev
+      * type specific information.  For more information see
       * ovs-vswitchd.conf.db(5).
       *
       * The caller is responsible for destroying 'smap' and its data.
       *
       * This function may be set to null if it would always return EOPNOTSUPP
       * anyhow. */
-     int (*get_drv_info)(const struct netdev *netdev, struct smap *smap);
+     int (*get_status)(const struct netdev *netdev, struct smap *smap);
  
      /* Looks up the ARP table entry for 'ip' on 'netdev' and stores the
       * corresponding MAC address in 'mac'.  A return value of ENXIO, in
@@@ -600,9 -607,6 +607,9 @@@ extern const struct netdev_class netdev
  extern const struct netdev_class netdev_bsd_class;
  #endif
  
 +extern const struct netdev_class netdev_tunnel_class;
 +extern const struct netdev_class netdev_pltap_class;
 +
  #ifdef  __cplusplus
  }
  #endif
diff --combined lib/netdev.c
@@@ -1,5 -1,5 +1,5 @@@
  /*
-  * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+  * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
@@@ -85,8 -85,6 +85,8 @@@ netdev_initialize(void
          netdev_register_provider(&netdev_tap_class);
          netdev_register_provider(&netdev_bsd_class);
  #endif
 +      netdev_register_provider(&netdev_tunnel_class);
 +      netdev_register_provider(&netdev_pltap_class);
      }
  }
  
@@@ -292,6 -290,18 +292,18 @@@ netdev_get_config(const struct netdev *
      return error;
  }
  
+ const struct netdev_tunnel_config *
+ netdev_get_tunnel_config(const struct netdev *netdev)
+ {
+     struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
+     if (netdev_dev->netdev_class->get_tunnel_config) {
+         return netdev_dev->netdev_class->get_tunnel_config(netdev_dev);
+     } else {
+         return NULL;
+     }
+ }
  /* Closes and destroys 'netdev'. */
  void
  netdev_close(struct netdev *netdev)
@@@ -622,9 -632,10 +634,10 @@@ netdev_get_features(const struct netde
  
  /* Returns the maximum speed of a network connection that has the NETDEV_F_*
   * bits in 'features', in bits per second.  If no bits that indicate a speed
-  * are set in 'features', assumes 100Mbps. */
+  * are set in 'features', returns 'default_bps'. */
  uint64_t
- netdev_features_to_bps(enum netdev_features features)
+ netdev_features_to_bps(enum netdev_features features,
+                        uint64_t default_bps)
  {
      enum {
          F_1000000MB = NETDEV_F_1TB_FD,
              : features & F_1000MB    ? UINT64_C(1000000000)
              : features & F_100MB     ? UINT64_C(100000000)
              : features & F_10MB      ? UINT64_C(10000000)
-                                      : UINT64_C(100000000));
+                                      : default_bps);
  }
  
  /* Returns true if any of the NETDEV_F_* bits that indicate a full-duplex link
@@@ -772,12 -783,12 +785,12 @@@ netdev_get_next_hop(const struct netde
   * information may be used to populate the status column of the Interface table
   * as defined in ovs-vswitchd.conf.db(5). */
  int
- netdev_get_drv_info(const struct netdev *netdev, struct smap *smap)
+ netdev_get_status(const struct netdev *netdev, struct smap *smap)
  {
      struct netdev_dev *dev = netdev_get_dev(netdev);
  
-     return (dev->netdev_class->get_drv_info
-             ? dev->netdev_class->get_drv_info(netdev, smap)
+     return (dev->netdev_class->get_status
+             ? dev->netdev_class->get_status(netdev, smap)
              : EOPNOTSUPP);
  }