/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include "discovery.h"
#include "dpif.h"
#include "dynamic-string.h"
-#include "executer.h"
#include "fail-open.h"
#include "in-band.h"
#include "mac-learning.h"
#include "netflow.h"
#include "odp-util.h"
#include "ofp-print.h"
+#include "ofproto-sflow.h"
#include "ofpbuf.h"
#include "openflow/nicira-ext.h"
#include "openflow/openflow.h"
-#include "openflow/openflow-mgmt.h"
#include "openvswitch/datapath-protocol.h"
#include "packets.h"
#include "pinsched.h"
#include "shash.h"
#include "status.h"
#include "stp.h"
+#include "stream-ssl.h"
#include "svec.h"
#include "tag.h"
#include "timeval.h"
#include "unixctl.h"
#include "vconn.h"
-#include "vconn-ssl.h"
#include "xtoxll.h"
#define THIS_MODULE VLM_ofproto
#include "vlog.h"
-enum {
- DP_GROUP_FLOOD = 0,
- DP_GROUP_ALL = 1
-};
+#include "sflow_api.h"
enum {
TABLEID_HASH = 0,
};
static struct ofconn *ofconn_create(struct ofproto *, struct rconn *);
-static void ofconn_destroy(struct ofconn *, struct ofproto *);
+static void ofconn_destroy(struct ofconn *);
static void ofconn_run(struct ofconn *, struct ofproto *);
static void ofconn_wait(struct ofconn *);
static void queue_tx(struct ofpbuf *msg, const struct ofconn *ofconn,
/* Settings. */
uint64_t datapath_id; /* Datapath ID. */
uint64_t fallback_dpid; /* Datapath ID if no better choice found. */
- uint64_t mgmt_id; /* Management channel identifier. */
char *manufacturer; /* Manufacturer. */
char *hardware; /* Hardware. */
char *software; /* Software version. */
struct discovery *discovery;
struct fail_open *fail_open;
struct pinsched *miss_sched, *action_sched;
- struct executer *executer;
struct netflow *netflow;
+ struct ofproto_sflow *sflow;
/* Flow table. */
struct classifier cls;
static void handle_openflow(struct ofconn *, struct ofproto *,
struct ofpbuf *);
-static void refresh_port_group(struct ofproto *, unsigned int group);
+static void refresh_port_groups(struct ofproto *);
+
static void update_port(struct ofproto *, const char *devname);
static int init_ports(struct ofproto *);
static void reinit_ports(struct ofproto *);
int
-ofproto_create(const char *datapath, const struct ofhooks *ofhooks, void *aux,
+ofproto_create(const char *datapath, const char *datapath_type,
+ const struct ofhooks *ofhooks, void *aux,
struct ofproto **ofprotop)
{
struct odp_stats stats;
*ofprotop = NULL;
/* Connect to datapath and start listening for messages. */
- error = dpif_open(datapath, &dpif);
+ error = dpif_open(datapath, datapath_type, &dpif);
if (error) {
VLOG_ERR("failed to open datapath %s: %s", datapath, strerror(error));
return error;
dpif_close(dpif);
return error;
}
- error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION);
+ error = dpif_recv_set_mask(dpif, ODPL_MISS | ODPL_ACTION | ODPL_SFLOW);
if (error) {
VLOG_ERR("failed to listen on datapath %s: %s",
datapath, strerror(error));
p->discovery = NULL;
p->fail_open = NULL;
p->miss_sched = p->action_sched = NULL;
- p->executer = NULL;
p->netflow = NULL;
+ p->sflow = NULL;
/* Initialize flow table. */
classifier_init(&p->cls);
p->ss_cat = switch_status_register(p->switch_status, "remote",
rconn_status_cb, p->controller->rconn);
- /* Almost done... */
- error = init_ports(p);
- if (error) {
- ofproto_destroy(p);
- return error;
- }
-
/* Pick final datapath ID. */
p->datapath_id = pick_datapath_id(p);
VLOG_INFO("using datapath ID %012"PRIx64, p->datapath_id);
}
}
-void
-ofproto_set_mgmt_id(struct ofproto *p, uint64_t mgmt_id)
-{
- p->mgmt_id = mgmt_id;
-}
-
void
ofproto_set_probe_interval(struct ofproto *p, int probe_interval)
{
ofproto_set_netflow(struct ofproto *ofproto,
const struct netflow_options *nf_options)
{
- if (nf_options->collectors.n) {
+ if (nf_options && nf_options->collectors.n) {
if (!ofproto->netflow) {
ofproto->netflow = netflow_create();
}
}
}
+void
+ofproto_set_sflow(struct ofproto *ofproto,
+ const struct ofproto_sflow_options *oso)
+{
+ struct ofproto_sflow *os = ofproto->sflow;
+ if (oso) {
+ if (!os) {
+ struct ofport *ofport;
+ unsigned int odp_port;
+
+ os = ofproto->sflow = ofproto_sflow_create(ofproto->dpif);
+ refresh_port_groups(ofproto);
+ PORT_ARRAY_FOR_EACH (ofport, &ofproto->ports, odp_port) {
+ ofproto_sflow_add_port(os, odp_port,
+ netdev_get_name(ofport->netdev));
+ }
+ }
+ ofproto_sflow_set_options(os, oso);
+ } else {
+ ofproto_sflow_destroy(os);
+ ofproto->sflow = NULL;
+ }
+}
+
void
ofproto_set_failure(struct ofproto *ofproto, bool fail_open)
{
}
}
-int
-ofproto_set_remote_execution(struct ofproto *ofproto, const char *command_acl,
- const char *command_dir)
-{
- if (command_acl) {
- if (!ofproto->executer) {
- return executer_create(command_acl, command_dir,
- &ofproto->executer);
- } else {
- executer_set_acl(ofproto->executer, command_acl, command_dir);
- }
- } else {
- executer_destroy(ofproto->executer);
- ofproto->executer = NULL;
- }
- return 0;
-}
-
uint64_t
ofproto_get_datapath_id(const struct ofproto *ofproto)
{
return ofproto->datapath_id;
}
-uint64_t
-ofproto_get_mgmt_id(const struct ofproto *ofproto)
-{
- return ofproto->mgmt_id;
-}
-
int
ofproto_get_probe_interval(const struct ofproto *ofproto)
{
LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
&p->all_conns) {
- ofconn_destroy(ofconn, p);
+ ofconn_destroy(ofconn);
}
dpif_close(p->dpif);
fail_open_destroy(p->fail_open);
pinsched_destroy(p->miss_sched);
pinsched_destroy(p->action_sched);
- executer_destroy(p->executer);
netflow_destroy(p->netflow);
+ ofproto_sflow_destroy(p->sflow);
switch_status_unregister(p->ss_cat);
int error;
int i;
+ if (shash_is_empty(&p->port_by_name)) {
+ init_ports(p);
+ }
+
for (i = 0; i < 50; i++) {
struct ofpbuf *buf;
int error;
}
pinsched_run(p->miss_sched, send_packet_in_miss, p);
pinsched_run(p->action_sched, send_packet_in_action, p);
- if (p->executer) {
- executer_run(p->executer);
- }
LIST_FOR_EACH_SAFE (ofconn, next_ofconn, struct ofconn, node,
&p->all_conns) {
if (p->netflow) {
netflow_run(p->netflow);
}
+ if (p->sflow) {
+ ofproto_sflow_run(p->sflow);
+ }
return 0;
}
}
pinsched_wait(p->miss_sched);
pinsched_wait(p->action_sched);
- if (p->executer) {
- executer_wait(p->executer);
+ if (p->sflow) {
+ ofproto_sflow_wait(p->sflow);
}
if (!tag_set_is_empty(&p->revalidate_set)) {
poll_immediate_wake();
svec_destroy(&devnames);
}
-static void
+static size_t
refresh_port_group(struct ofproto *p, unsigned int group)
{
uint16_t *ports;
}
dpif_port_group_set(p->dpif, group, ports, n_ports);
free(ports);
+
+ return n_ports;
}
static void
refresh_port_groups(struct ofproto *p)
{
- refresh_port_group(p, DP_GROUP_FLOOD);
- refresh_port_group(p, DP_GROUP_ALL);
+ size_t n_flood = refresh_port_group(p, DP_GROUP_FLOOD);
+ size_t n_all = refresh_port_group(p, DP_GROUP_ALL);
+ if (p->sflow) {
+ ofproto_sflow_set_group_sizes(p->sflow, n_flood, n_all);
+ }
}
static struct ofport *
make_ofport(const struct odp_port *odp_port)
{
+ struct netdev_options netdev_options;
enum netdev_flags flags;
struct ofport *ofport;
struct netdev *netdev;
bool carrier;
int error;
- error = netdev_open(odp_port->devname, NETDEV_ETH_TYPE_NONE, &netdev);
+ memset(&netdev_options, 0, sizeof netdev_options);
+ netdev_options.name = odp_port->devname;
+ netdev_options.ethertype = NETDEV_ETH_TYPE_NONE;
+ netdev_options.may_open = true;
+
+ error = netdev_open(&netdev_options, &netdev);
if (error) {
VLOG_WARN_RL(&rl, "ignoring port %s (%"PRIu16") because netdev %s "
"cannot be opened (%s)",
static void
ofport_install(struct ofproto *p, struct ofport *ofport)
{
+ uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
+ const char *netdev_name = (const char *) ofport->opp.name;
+
netdev_monitor_add(p->netdev_monitor, ofport->netdev);
- port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no),
- ofport);
- shash_add(&p->port_by_name, (char *) ofport->opp.name, ofport);
+ port_array_set(&p->ports, odp_port, ofport);
+ shash_add(&p->port_by_name, netdev_name, ofport);
+ if (p->sflow) {
+ ofproto_sflow_add_port(p->sflow, odp_port, netdev_name);
+ }
}
static void
ofport_remove(struct ofproto *p, struct ofport *ofport)
{
+ uint16_t odp_port = ofp_port_to_odp_port(ofport->opp.port_no);
+
netdev_monitor_remove(p->netdev_monitor, ofport->netdev);
- port_array_set(&p->ports, ofp_port_to_odp_port(ofport->opp.port_no), NULL);
+ port_array_set(&p->ports, odp_port, NULL);
shash_delete(&p->port_by_name,
shash_find(&p->port_by_name, (char *) ofport->opp.name));
+ if (p->sflow) {
+ ofproto_sflow_del_port(p->sflow, odp_port);
+ }
}
static void
}
static void
-ofconn_destroy(struct ofconn *ofconn, struct ofproto *p)
+ofconn_destroy(struct ofconn *ofconn)
{
- if (p->executer) {
- executer_rconn_closing(p->executer, ofconn->rconn);
- }
-
list_remove(&ofconn->node);
rconn_destroy(ofconn->rconn);
rconn_packet_counter_destroy(ofconn->packet_in_counter);
}
if (ofconn != p->controller && !rconn_is_alive(ofconn->rconn)) {
- ofconn_destroy(ofconn, p);
+ ofconn_destroy(ofconn);
}
}
#undef REVALIDATE_BITS
if (mask & OFPPC_NO_FLOOD) {
port->opp.config ^= OFPPC_NO_FLOOD;
- refresh_port_group(p, DP_GROUP_FLOOD);
+ refresh_port_groups(p);
}
if (mask & OFPPC_NO_PACKET_IN) {
port->opp.config ^= OFPPC_NO_PACKET_IN;
}
}
-static void
-send_capability_reply(struct ofproto *p, struct ofconn *ofconn, uint32_t xid)
-{
- struct ofmp_capability_reply *ocr;
- struct ofpbuf *b;
- char capabilities[] = "com.nicira.mgmt.manager=false\n";
-
- ocr = make_openflow_xid(sizeof(*ocr), OFPT_VENDOR, xid, &b);
- ocr->header.header.vendor = htonl(NX_VENDOR_ID);
- ocr->header.header.subtype = htonl(NXT_MGMT);
- ocr->header.type = htons(OFMPT_CAPABILITY_REPLY);
-
- ocr->format = htonl(OFMPCOF_SIMPLE);
- ocr->mgmt_id = htonll(p->mgmt_id);
-
- ofpbuf_put(b, capabilities, strlen(capabilities));
-
- queue_tx(b, ofconn, ofconn->reply_counter);
-}
-
-static int
-handle_ofmp(struct ofproto *p, struct ofconn *ofconn,
- struct ofmp_header *ofmph)
-{
- size_t msg_len = ntohs(ofmph->header.header.length);
- if (msg_len < sizeof(*ofmph)) {
- VLOG_WARN_RL(&rl, "dropping short managment message: %zu\n", msg_len);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
- }
-
- if (ofmph->type == htons(OFMPT_CAPABILITY_REQUEST)) {
- struct ofmp_capability_request *ofmpcr;
-
- if (msg_len < sizeof(struct ofmp_capability_request)) {
- VLOG_WARN_RL(&rl, "dropping short capability request: %zu\n",
- msg_len);
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LENGTH);
- }
-
- ofmpcr = (struct ofmp_capability_request *)ofmph;
- if (ofmpcr->format != htonl(OFMPCAF_SIMPLE)) {
- /* xxx Find a better type than bad subtype */
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-
- send_capability_reply(p, ofconn, ofmph->header.header.xid);
- return 0;
- } else {
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
- }
-}
-
static int
handle_vendor(struct ofproto *p, struct ofconn *ofconn, void *msg)
{
case NXT_STATUS_REQUEST:
return switch_status_handle_request(p->switch_status, ofconn->rconn,
msg);
-
- case NXT_ACT_SET_CONFIG:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
-
- case NXT_ACT_GET_CONFIG:
- return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE); /* XXX */
-
- case NXT_COMMAND_REQUEST:
- if (p->executer) {
- return executer_handle_request(p->executer, ofconn->rconn, msg);
- }
- break;
-
- case NXT_MGMT:
- return handle_ofmp(p, ofconn, msg);
}
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_SUBTYPE);
}
\f
static void
-handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
+handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
{
struct odp_msg *msg = packet->data;
uint16_t in_port = odp_port_to_ofp_port(msg->port);
struct ofpbuf payload;
flow_t flow;
- /* Handle controller actions. */
- if (msg->type == _ODPL_ACTION_NR) {
- COVERAGE_INC(ofproto_ctlr_action);
- pinsched_send(p->action_sched, in_port, packet,
- send_packet_in_action, p);
- return;
- }
-
payload.data = msg + 1;
payload.size = msg->length - sizeof *msg;
flow_extract(&payload, msg->port, &flow);
ofpbuf_delete(packet);
}
}
+
+static void
+handle_odp_msg(struct ofproto *p, struct ofpbuf *packet)
+{
+ struct odp_msg *msg = packet->data;
+
+ switch (msg->type) {
+ case _ODPL_ACTION_NR:
+ COVERAGE_INC(ofproto_ctlr_action);
+ pinsched_send(p->action_sched, odp_port_to_ofp_port(msg->port), packet,
+ send_packet_in_action, p);
+ break;
+
+ case _ODPL_SFLOW_NR:
+ if (p->sflow) {
+ ofproto_sflow_received(p->sflow, msg);
+ }
+ ofpbuf_delete(packet);
+ break;
+
+ case _ODPL_MISS_NR:
+ handle_odp_miss_msg(p, packet);
+ break;
+
+ default:
+ VLOG_WARN_RL(&rl, "received ODP message of unexpected type %"PRIu32,
+ msg->type);
+ break;
+ }
+}
\f
static void
revalidate_cb(struct cls_rule *sub_, void *cbdata_)
pick_fallback_dpid(void)
{
uint8_t ea[ETH_ADDR_LEN];
- eth_addr_random(ea);
- ea[0] = 0x00; /* Set Nicira OUI. */
- ea[1] = 0x23;
- ea[2] = 0x20;
+ eth_addr_nicira_random(ea);
return eth_addr_to_uint64(ea);
}
\f