/*
*/
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <config.h>
#include "dpif-solaris.h"
#include <fcntl.h>
#include <strings.h>
#include <unistd.h>
#include "classifier.h"
#include "dpif-provider.h"
#include "dynamic-string.h"
#include "netdev-solaris.h"
#include "netdev-vport.h"
#include "netlink.h"
#include "odp-execute.h"
#include "poll-loop.h"
#include "shash.h"
#include "socket-util.h"
#include "sset.h"
#include "vlog.h"
#include <zone.h>
#include <libdllink.h>
#ifndef MAC_OFPORT_ARRAY
/*
* Keeping a bitbucket of each containing 64-bits (uint64_t)
* for kernel ofports to effectively lookup a free ofport.
*/
#endif
/* Datapath interface for the openvswitch Solaris kernel module. */
struct dpif_solaris {
char *name;
/* BRIDGES */
/* PORT */
/* FLOW */
/* Upcall messages. */
bool recv_set;
int event_rfd;
int event_wfd;
/*
* List of lower links of the OVS ports, over which the upcall_fd(s)
* are created
*/
};
struct dpif_solaris_lowerlink {
};
/* Contains all 'struct dpif_solaris's. */
struct dpif_solaris_handler {
int upcall_fd;
};
struct dpif_solaris_bridge {
char *name;
};
struct dpif_solaris_port {
char *name;
char *linkname;
char *physname;
/* uplink_port_list */
/* Receive the upcalls */
/* Send the packet */
};
struct dpif_solaris_flow {
/* Packet classification. */
/* Hash table index by unmasked flow. */
char *physname;
};
struct dpif_solaris_port *port)
struct dpif_solaris_port *port);
enum ovs_vport_type *vtypep);
struct dpif_solaris_flow *flow)
struct dpif_solaris_lowerlink *lowerlink);
static struct dpif_solaris *
{
}
static int
{
int error;
VLOG_DBG("dpif_solaris_enumerate");
error = solaris_init_rad();
if (error != 0)
return (error);
if (netdev_impl_etherstub_exists()) {
VLOG_DBG("dpif_solaris_enumerate ovs-system");
}
return (0);
}
static int
{
int error = 0;
VLOG_DBG("dpif_solaris_open class type %s name %s do %screate",
return (ENODEV);
error = solaris_init_rad();
if (error != 0)
return (error);
/*
* The same function is shared by ovs-vswitchd and other utilities as
* they call into the same library. Note that for other utilities,
* dpif does not exists at first, create it here if dp_exists indicate
* the datapath already exists.
*/
if (error != 0) {
return (error);
}
if (!dp_exists) {
if (error != 0) {
return (error);
}
}
/* UPCALL related */
/* uplink related */
/* port related */
dpif->n_handlers = 0;
/* flow related */
if (!create) {
goto again;
}
} else if (!dp_exists) {
} else {
}
if (!error) {
/* Choose dp_ifindex to be used as netflow engine type and id */
dpif->dp_ifindex);
}
return (error);
}
/*
* Requires dp_netdev_mutex so that we can't get a new reference to 'dp'
* through the 'dp_netdevs' shash while freeing 'dp'.
*/
static void
{
}
}
static void
{
/*
* Take dp_solaris_mutex so that, if dpif->ref_cnt falls to
* zero, we can't get a hold of 'dpif'.
*/
}
}
}
static void
{
}
static int
{
int cnt;
if (cnt <= 2) {
}
}
return (0);
}
static int
{
char *name;
if (!kstat2_handle_initialized) {
VLOG_DBG("dpif_solaris_get_stats initializing handle");
if (!kstat_handle_init(&dpif_khandle)) {
VLOG_DBG("dpif_solaris_get_stats: error initializing"
" kstat handle");
return (-1);
}
} else if (!kstat_handle_update(dpif_khandle)) {
VLOG_DBG("dpif_solaris_get_stats: error updating kstats");
return (-1);
}
instance = 0;
(void) solaris_dlparse_zonelinkname(
name = kstat_name;
}
if (stat != KSTAT2_S_OK) {
VLOG_WARN("dpif_solaris_get_stats kstat_lookup "
"of %s failed: %s", kuri,
return (-1);
}
}
}
if (stat != KSTAT2_S_OK) {
VLOG_WARN("dpif_solaris_get_stats kstat_lookup "
"of %s failed: %s", kuri,
return (-1);
}
}
return (0);
}
static enum ovs_vport_type
{
return (OVS_VPORT_TYPE_NETDEV);
return (OVS_VPORT_TYPE_INTERNAL);
return (OVS_VPORT_TYPE_VXLAN);
} else {
return (OVS_VPORT_TYPE_UNSPEC);
}
}
static int
struct dpif_solaris_port *port)
{
int fd;
int error;
return (0);
return (errno);
}
if (error != 0) {
return (error);
}
return (error);
}
return (0);
}
/*
* Choose an unused, non-zero port number and return it on success.
* Return ODPP_NONE on failure.
* The current approach to choose unused port number is quite inefficient,
* need improvement. TBD
*/
static odp_port_t
choose_port(void)
{
continue;
return (u32_to_odp(port_no));
}
return (ODPP_NONE);
}
static void
{
}
static boolean_t
{
int i;
for (i = 0; i < lowerlink->n_handlers; i++) {
return (true);
}
}
return (false);
}
/*
* Choose an unused, non-zero port number and return it on success.
* Return ODPP_NONE on failure.
* The current approach to choose unused port number is quite inefficient,
* need improvement. TBD
*/
static odp_port_t
struct dpif_solaris_lowerlink *lowerlink, int n)
{
int i;
pf_port_no++) {
continue;
for (i = 0; i < n; i++) {
break;
}
if (i < n)
continue;
return (u32_to_odp(pf_port_no));
}
return (ODPP_NONE);
}
static struct dpif_solaris_bridge *
const char *brname)
{
return (bridge);
}
}
return (NULL);
}
static struct dpif_solaris_bridge *
{
VLOG_DBG("dpif_solaris_bridge_add_port adding port %d to uplink %s",
else
/*
* For vxlan or for such cases where we couldn't obtain
* brname
*/
}
VLOG_DBG("dpif_solaris_bridge_add_port creating bridge %s",
brname);
}
VLOG_DBG("dpif_solaris_bridge_add_port add port %s portno %d to "
VLOG_DBG("Insert port %s into bridge %s uplink_port_list",
}
return (bridge);
}
static void
struct dpif_solaris_port *port)
{
VLOG_DBG("dpif_solaris_bridge_del_port port %d not assigned "
return;
}
VLOG_DBG("dpif_solaris_bridge_del_port deleting port %d from %s",
/*
* The extra thing we do if it's uplink (other than vxlan)
* is to remove the uplink port from bridge's uplink_port_list.
*/
VLOG_DBG("dpif_solaris_port_del__: Removed the "
"uplink %s from bridge's(%s) "
break;
}
}
}
VLOG_DBG("dpif_solaris_bridge_del_port destroying bridge");
}
}
static int
{
int error = 0;
if (vtype == OVS_VPORT_TYPE_UNSPEC) {
return (EINVAL);
}
VLOG_DBG("dpif_solaris_port_add %s (%s) type %s port_no %d vtype %d",
physname[0] = '\0';
vtype == OVS_VPORT_TYPE_INTERNAL) {
sizeof (dlbuffer));
if (error != 0)
return (error);
if (solaris_is_uplink_class(dlbuffer)) {
sizeof (physname))
return (EINVAL);
VLOG_DBG("dpif_solaris_port_add primary port %s",
name);
is_uplink = true;
} else {
sizeof (dlbuffer));
if (error != 0)
return (error);
sizeof (physname))
return (EINVAL);
VLOG_DBG("dpif_solaris_port_add non-primary port "
}
} else {
VLOG_DBG("dpif_solaris_port_add adding unknown type");
return (EINVAL);
}
*port_nop = choose_port();
goto portno_fail;
}
}
vtype == OVS_VPORT_TYPE_INTERNAL) {
linkname);
VLOG_ERR("set portno %d on %s failed: %s",
goto portno_fail;
}
}
/* Only create the TX PF_SOCKET on the physical link */
if (is_uplink) {
if (error != 0) {
VLOG_ERR("dpif_solaris_create_xsocket on %s failed: %s",
goto fail;
}
}
if (error != 0) {
VLOG_ERR("dpif_solaris_refresh_port_channel on %s failed %s",
goto fail;
}
return (0);
fail:
}
vtype == OVS_VPORT_TYPE_INTERNAL) {
B_TRUE);
}
return (error);
}
static int
{
int error;
return (error);
}
static int
struct dpif_solaris_port **portp)
{
return (EINVAL);
}
return (0);
}
}
return (ENOENT);
}
static int
enum ovs_vport_type *vtypep)
{
break;
goto done;
return (0);
}
}
done:
return (ENOENT);
}
static void
struct dpif_solaris_port *port)
{
VLOG_DBG("dpif_solaris_port_del__ primary port "
}
}
}
static int
{
int error;
if (port_no == ODPP_LOCAL) {
return (EINVAL);
}
if (error) {
error);
return (error);
}
return (0);
}
static int
{
int error;
}
return (error);
}
static int
{
if (dpif_port) {
}
return (0);
}
}
return (ENOENT);
}
struct dpif_solaris_port_state {
char *name;
};
static void
{
}
static int
void **statep)
{
return (0);
}
static int
{
int retval;
if (node) {
retval = 0;
} else {
}
return (retval);
}
static int
{
}
return (0);
}
static int
char **devnamep OVS_UNUSED)
{
return (EAGAIN);
}
static void
{
}
static int
struct flow *f)
{
/*
* 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
* debugging.
*/
if (!VLOG_DROP_ERR(&rl)) {
struct ds s;
ds_init(&s);
VLOG_ERR("internal error parsing flow key %s",
ds_cstr(&s));
ds_destroy(&s);
}
return (EINVAL);
}
return (0);
}
static int
{
/*
* Force unwildcard the in_port.
* We need to do this even in the case where we unwildcard "everything"
* above because "everything" only includes the 16-bit OpenFlow port
* number mask->in_port.ofp_port, which only covers half of the 32-bit
* datapath port number mask->in_port.odp_port.
*/
if (!mask_key_len) {
/*
* No mask key, unwildcard everything except fields whose
* prerequisities are not met.
*/
memset(m, 0x0, sizeof (*m));
/* Skip registers and metadata. */
id != MFF_METADATA) {
if (mf_are_prereqs_ok(mf, f)) {
mf_mask_field(mf, m);
}
}
}
return (0);
}
if (fitness) {
/*
* This should not happen: it indicates that
* odp_flow_key_from_mask() and odp_flow_key_to_mask()
* disagree on the acceptable form of a mask.
* Log the problem as an error, with enough details to
* enable debugging.
*/
if (!VLOG_DROP_ERR(&rl)) {
struct ds s;
ds_init(&s);
NULL, &s, true);
VLOG_ERR("internal error parsing flow mask %s (%s)",
ds_destroy(&s);
}
return (EINVAL);
}
return (0);
}
static struct dpif_solaris_flow *
{
}
static struct dpif_solaris_flow *
{
return (solaris_flow);
}
static struct dpif_solaris_flow *
{
return (solaris_flow);
}
}
return (NULL);
}
static struct dpif_solaris_flow *
const char *flowname)
{
return (solaris_flow);
}
}
return (NULL);
}
static struct dpif_solaris_flow *
{
"%p.sys.of", (void *)solaris_flow);
return (solaris_flow);
}
static void
{
}
static int
{
int error;
if (error == 0) {
}
return (error);
}
static int
struct dpif_flow_stats *stats)
{
struct flow f, m;
int error;
VLOG_DBG("dpif_solaris_flow_get");
if (error) {
return (error);
}
if (solaris_flow == NULL) {
return (error);
}
if (error) {
return (error);
}
/* Allocate buffer big enough for everything. */
/* Mask. */
SIZE_MAX);
/* Actions. */
ofpbuf_init(&actions, 0);
if (ofpbuf_size(&actions) == 0) {
*actions_len = 0;
} else {
ofpbuf_size(&actions));
}
/* Stats. */
return (0);
}
int
{
int error = 0;
VLOG_DBG("dpif_solaris_get_priority_details: "
if (error != 0) {
VLOG_DBG("dpif_solaris_get_priority_details: "
"failed to get port %d\n", outport);
return (error);
}
if (error != 0) {
VLOG_DBG("dpif_solaris_get_priority_details: "
"failed to get queue %d\n", queueid);
return (error);
}
VLOG_DBG("dpif_solaris_get_priority_details: done");
return (0);
}
void
{
if (err == 0)
else
}
static int
{
struct flow f;
int error;
VLOG_DBG("dpif_solaris_flow_put");
if (error) {
goto done;
}
if (error) {
goto done;
}
miniflow_init(&miniflow, &f);
if (solaris_flow == NULL) {
VLOG_ERR("dpif_solaris_flow_put mask %s "
goto done;
}
&port);
if (error != 0) {
VLOG_DBG("dpif_solaris_flow_put(): "
"failed to get inport %d\n", inport);
goto done;
}
VLOG_DBG("dpif_solaris_flow_put %s mask %s "
/*
* workaround to passing a struct dpif to
* solaris_add_flow adding dpif_provider.h to
* util-solaris brings up a conflict in
* Solaris's list and the OVS list
* implementations.
*/
if (error != 0) {
VLOG_ERR("dpif_solaris_flow_put "
"solaris_add_flow %s on %s failed "
goto done;
}
VLOG_DBG("dpif_solaris_flow_put "
"solaris_add_flow %s on %s succeed"
} else {
VLOG_DBG("dpif_solaris_flow_put exsting flow %s found for "
if (error != 0) {
VLOG_ERR("dpif_solaris_flow_put "
"exsting flow %s found but update "
"failed %d, for mask %s actions %s",
goto done;
}
VLOG_DBG("dpif_solaris_flow_put "
"exsting flow %s found and updated,"
"for mask %s actions %s", flowname,
VLOG_DBG("dpif_solaris_flow_put existing flow "
"%s already exists for mask %s actions %s",
goto done;
} else {
/*
* Overlapping flow. (Flow & Mask) matches but flow
* itself does not match
*/
VLOG_ERR("dpif_solaris_flow_put overlapped "
"with existing flow %s, for mask %s actions %s",
goto done;
}
}
VLOG_DBG("dpif_solaris_flow_put "
"get_flowstats %s succeed", flowname);
} else {
VLOG_ERR("dpif_solaris_flow_put "
"get_flowstats %s failed", flowname);
}
}
/*
* If DPIF_FP_MODIFY and DPIF_FP_ZERO_STATS is set in
* put->flags, we should zero out the statistics of the
* given flow. This is currently not supported, and so far,
* we don't see any problem yet.
*/
done:
ds_destroy(&fs);
ds_destroy(&as);
return (error);
}
static int
{
char *physname;
struct flow f;
int error;
ds_destroy(&fs);
if (error) {
return (error);
}
if (solaris_flow == NULL) {
return (error);
}
if (error == 0) {
VLOG_DBG("dpif_solaris_flow_del "
"get_flowstats %s succeed", flowname);
} else {
VLOG_ERR("dpif_solaris_flow_del "
}
}
if (error == 0) {
VLOG_DBG("dpif_solaris_flow_del solaris_remove_flow %s "
"succeed", flowname);
} else {
VLOG_ERR("dpif_solaris_flow_del solaris_remove_flow %s "
}
return (error);
}
static int
{
int i = 0, flow_count = 0;
}
for (i = 0; i < flow_count; i++) {
}
return (0);
}
static int
{
return (dpif_solaris_flow_flush__(dpif));
}
struct dpif_solaris_flow_state {
};
struct dpif_solaris_flow_ent {
struct flow f;
struct flow m;
};
struct dpif_solaris_flow_iter {
int status;
};
static void
{
}
static void
{
}
static void
{
VLOG_DBG("dpif_solaris_flow_dump_start walk flow %s found "
"tunnel 0x%lx src 0x%x dst 0x%x\n", name,
} else {
VLOG_DBG("dpif_solaris_flow_dump_start walk flow %s not found"
"\n", name);
}
if (ofpbuf_size(action) != 0) {
}
ofpbuf_reinit(action, 0);
}
static int
{
ofpbuf_init(&action, 0);
return (0);
}
static int
const struct dpif_flow_stats **stats)
{
int error;
if (!error) {
if (node) {
struct dpif_solaris_flow_ent, node);
VLOG_DBG("dpif_solaris_flow_dump_next %s",
} else {
}
}
if (error) {
return (error);
}
if (key) {
struct ds s;
ds_init(&s);
VLOG_DBG("dpif_solaris_flow_dump_next %s key %s",
ds_destroy(&s);
}
struct ds s;
ds_init(&s);
true);
VLOG_DBG("dpif_solaris_flow_dump_next %s mask %s "
ds_destroy(&s);
}
if (actions) {
}
if (stats) {
}
}
VLOG_DBG("dpif_solaris_flow_dump_next %s succeed",
return (0);
}
static int
{
}
return (0);
}
static int
{
if (may_steal) {
}
return (error);
}
auxdata.tp_tun_type = 0;
}
if (nbytes == -1) {
break;
}
nbytes = 0;
} else if (nbytes == 0) {
break;
}
}
return (0);
}
static struct dpif_solaris *
{
if (!dpif) {
VLOG_ERR("get_dp_by_name: couldn't get a hold on dpif for %s",
dp_name);
}
return (dpif);
}
struct netdev *
{
*error = true;
return (NULL);
}
VLOG_ERR("dpif_solaris_obtain_netdev_to_migrate: Could not "
"locate bridge for %s", brname);
*error = true;
return (NULL);
}
/*
* If bridge has no uplinks migrate bridge vnic to implicit etherstub.
* If it has uplinks, look for an uplink which is not etherstub. If not
* get the first uplink from the uplink_port_list.
*/
return (NULL);
} else {
"dpif_solaris_obtain_netdev_to_migrate:"
" Could not obtain netdev for %s",
*error = true;
return (NULL);
}
"etherstub") != 0) {
break;
}
}
if (netdev_to_migrate == NULL) {
VLOG_DBG("Couldn't find a netdev other than etherstub. "
"Thus migrating to first etherstub");
if (netdev_to_migrate == NULL) {
"dpif_solaris_obtain_netdev_to_migrate:"
" Could not obtain netdev for %s",
*error = true;
return (NULL);
}
}
}
return (netdev_to_migrate);
}
/*
* Migrate the internal port to a different lower link, sets its physname, and
* refresh its port channel.
*
* Note that the internal port's name is the same as bridge name
*/
void
{
int err;
physname);
continue;
false);
if (err == 0)
VLOG_DBG("dpif_solaris_migrate_internal_port %s"
else
VLOG_ERR("dpif_solaris_migrate_internal_port %s"
break;
}
}
}
static void
{
int err;
switch ((enum ovs_action_attr)type) {
case OVS_ACTION_ATTR_OUTPUT: {
VLOG_DBG("dp_solaris_execute_cb OVS_ACTION_ATTR_OUTPUT "
/*
* If in_port number is OFPP_NONE, this means this packet out
* request comes from the controller.
*
* if the in or outport is the internal port, and its uplink
* can not be found, it means there is no physical uplink
* added to the bridge yet, directly drop the packet.
*/
if (err != 0) {
if (vtype != OVS_VPORT_TYPE_INTERNAL) {
VLOG_DBG("dp_solaris_execute_cb "
"OVS_ACTION_ATTR_OUTPUT failed to"
"get uplink for inport %d ",
}
if (may_steal)
break;
}
if (err != 0) {
if (vtype != OVS_VPORT_TYPE_INTERNAL) {
VLOG_DBG("dp_solaris_execute_cb "
"OVS_ACTION_ATTR_OUTPUT failed to "
"get uplink for outport %d",
port_no);
}
if (may_steal)
break;
}
/*
* Bridging across different uplinks is not supported
* in the kernel currently, so we disable that support
* here as well.
*/
VLOG_DBG("dp_solaris_execute_cb "
"OVS_ACTION_ATTR_OUTPUT inport %d and "
"outport %d on different uplinks",
if (may_steal)
break;
}
}
break;
}
/*
* We'll send the packet back to the kernel and it'll be classified
* and we should get it back. XXX Check if this could cause an
* infinite loop. This is not terribly effective, but if we use
* sockets, it will still get to the kernel before coming back.
* Need a short-cut. Note we don't care about any userland data
* since we will get it when the packets comes back from the
* kernel. Also, currently we always send using the uplink associated
* with the in_port number.
*/
case OVS_ACTION_ATTR_USERSPACE: { /* controller */
VLOG_DBG("dp_solaris_execute_cb OVS_ACTION_ATTR_USERSPACE");
if (err != 0) {
if (vtype != OVS_VPORT_TYPE_INTERNAL) {
VLOG_DBG("dp_solaris_execute_cb "
"OVS_ACTION_ATTR_USERSPACE failed to get "
"uplink for inport %d",
} else {
VLOG_DBG("dp_solaris_execute_cb "
"OVS_ACTION_ATTR_USERSPACE from an internal"
"port %d which is not associated with a "
"physical uplink",
}
if (may_steal)
break;
}
VLOG_DBG("dp_solaris_execute_cb OVS_ACTION_ATTR_USERSPACE "
"%d", pin);
break;
}
case OVS_ACTION_ATTR_HASH: /* for bonding */
case OVS_ACTION_ATTR_RECIRC: /* for bonding */
case OVS_ACTION_ATTR_POP_VLAN:
case OVS_ACTION_ATTR_POP_MPLS:
case OVS_ACTION_ATTR_SET:
case OVS_ACTION_ATTR_SAMPLE:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
}
}
static int
{
VLOG_ERR("dpif_solaris_execute invalid size %d",
return (EINVAL);
}
return (0);
}
static void
struct dpif_solaris_lowerlink *lowerlink)
{
int i;
for (i = 0; i < lowerlink->n_handlers; i++) {
}
}
static void
struct dpif_solaris_port *port)
{
return;
VLOG_DBG("dpif_solaris_destroy_port_channel port %s lower-link %s",
}
static void
{
return;
VLOG_DBG("dpif_solaris_destroy_channels");
}
dpif->n_handlers = 0;
}
static int
{
return (0);
VLOG_DBG("dpif_solaris_refresh_port_channel(%s) port_no %d on %s%s",
lowerlink_found = true;
break;
}
}
/* Create the lower link if it is not found */
if (!lowerlink_found) {
&lowerlink);
if (error != 0) {
VLOG_DBG("dpif_solaris_refresh_port_channel lowerlink "
return (error);
}
}
VLOG_DBG("dpif_solaris_refresh_port_channel(%s) port_no %d pf_port_no "
&mofport, sizeof (mac_of_ports_t)) != 0) {
VLOG_ERR("dpif_solaris_refresh_port_channel %s failed to set "
if (!lowerlink_found)
return (error);
}
/* Inform the event_rfd that the port->upcall_fd has been changed */
sizeof (odp_port_t)) < 0) {
VLOG_ERR("dpif_solaris_refresh_port_channel %s event "
}
return (0);
}
static int
{
int error;
return (EINVAL);
if (fd == -1) {
VLOG_ERR("dpif_solaris_create_upfd %s failed to "
return (errno);
}
if (error != 0) {
VLOG_ERR("dpif_solaris_create_upfd %s failed to get "
return (error);
}
VLOG_ERR("dpif_solaris_create_upfd %s failed to bind: "
return (error);
}
VLOG_ERR("dpif_solaris_create_upfd %s failed to set "
"PACKET_AUXDATAQ: %s", physname,
return (error);
}
/* Disable the promiscous mode on this socket */
&mofport, sizeof (mac_of_ports_t)) != 0) {
VLOG_ERR("dpif_solaris_create_upfd %s failed to set "
"PACKET_ADD_OF_DEFFLOW port 0: %s", physname,
return (error);
}
/* must not block */
VLOG_ERR("dpif_solaris_create_upfd %s failed to set "
return (error);
}
*upcall_fdp = fd;
return (0);
}
static int
struct dpif_solaris_lowerlink **lowerlinkp)
{
int i, err;
return (0);
VLOG_DBG("dpif_solaris_create_lowerlink create %d upfds over lower "
return (ENOBUFS);
}
sizeof (struct dpif_solaris_handler));
for (i = 0; i < lowerlink->n_handlers; i++)
for (i = 0; i < lowerlink->n_handlers; i++) {
if (err != 0) {
VLOG_ERR("dpif_solaris_create_lowerlink create %dth "
ovs_strerror(err));
goto fail;
} else {
VLOG_DBG("dpif_solaris_create_lowerlink create %dth "
}
pf_port_no = (i == 0) ? PORT_PF_PACKET_UPLINK :
if (pf_port_no == ODPP_NONE) {
VLOG_ERR("dpif_solaris_create_lowerlink no usable "
"port_no avaiable for %dth upfd over %s", i,
goto fail;
} else {
VLOG_DBG("dpif_solaris_create_lowerlink "
"avaiable pf_port_no for %dth upfd over %s: %d", i,
}
}
*lowerlinkp = lowerlink;
return (0);
fail:
return (err);
}
/*
* Synchronizes 'channels' in 'dpif->handlers' with the set of vports
* currently in 'dpif' in the kernel, by adding a new set of channels for
* any kernel vport that lacks one and deleting any channels that have no
* backing kernel vports.
*/
static int
{
/*
* Setup the event pipe to monitor the port changes, so that
* port_channel_fd is able to be refreshed into the pollfds set.
*/
return (error);
}
/* must not block */
return (error);
}
return (error);
}
if (error != 0) {
return (error);
}
}
/* Inform the event_rfd that all ports' upcall_fd has been changed */
VLOG_ERR("dpif_solaris_refresh_channels event notify"
}
return (0);
}
static int
{
return (0);
if (!enable) {
return (0);
} else {
}
}
static int
{
int error = 0;
return (error);
}
/*
* For Solaris we will use the queue_id as the priority. The queue id
* will be used to get the QoS information and used to configure
* the bandwidth and priority
*/
static int
{
return (0);
}
static int
{
void *data;
VLOG_DBG("dpif_solaris_parse_pkt");
buf_size);
return (EINVAL);
}
/* Allocate buffer big enough for everything. */
if (action_type == FLOW_ACTION_OF_CONTROLLER) {
const struct nlattr *a;
VLOG_DBG("dpif_solaris_parse_p:: FLOW_ACTION_OF_CONTROLLER!!");
if (a != NULL) {
}
}
}
return (0);
}
static int
{
int pktlen;
return (EAGAIN);
}
sizeof (odp_port_t));
for (i = 0; i < lowerlink->n_handlers; i++) {
continue;
msg.msg_namelen = 0;
if (pktlen > 0) {
sizeof (struct tpacket_auxdata)) ||
continue;
sizeof (aux));
break;
}
if (action_type != FLOW_ACTION_MISSED_PKT &&
VLOG_ERR("dpif_solaris_recv__ on %s fd "
"%d len %d but with unknown "
"auxdata type %d",
continue;
}
if (port_no == 0) {
VLOG_ERR("dpif_solaris_recv__ on %s fd "
"%d len %d but with unknown "
"port_no 0",
continue;
}
VLOG_DBG("dpif_solaris_recv__ on %s fd %d len "
"%d type %s (src_port = %u)",
/* TBD? */
}
if (error != 0) {
VLOG_ERR("dpif_solaris_recv__ "
"parse_pkt on %s fd %d action %s "
fd, action_type ==
"miss_pkt" : "fwd_to_controller",
error);
} else {
return (0);
}
}
}
}
return (EAGAIN);
}
static int
{
int error;
return (error);
}
static void
{
int i, fd;
goto done;
for (i = 0; i < lowerlink->n_handlers; i++) {
}
}
}
done:
}
static void
{
int i, fd;
return;
for (i = 0; i < lowerlink->n_handlers; i++) {
}
}
}
}
static void
{
VLOG_DBG("dpif_solaris_recv_purge");
}
static int
{
int err = 0;
return (err);
}
"system",
NULL, /* port_open_type */
NULL, /* run */
NULL, /* wait */
NULL, /* port_get_pid */
NULL, /* flow_dump_next_may_destroy_keys */
NULL, /* operate */
dpif_solaris_handlers_set, /* handlers_set */
};