const struct ofputil_flow_mod *,
const struct ofp_header *);
-/* This return value tells handle_openflow() that processing of the current
- * OpenFlow message must be postponed until some ongoing operations have
- * completed.
- *
- * This particular value is a good choice because it is negative (so it won't
- * collide with any errno value or any value returned by ofp_mkerr()) and large
- * (so it won't accidentally collide with EOF or a negative errno value). */
-enum { OFPROTO_POSTPONE = -100000 };
-
static bool handle_openflow(struct ofconn *, struct ofpbuf *);
+static int handle_flow_mod__(struct ofproto *, struct ofconn *,
+ const struct ofputil_flow_mod *,
+ const struct ofp_header *);
static void update_port(struct ofproto *, const char *devname);
static int init_ports(struct ofproto *);
static void reinit_ports(struct ofproto *);
+static void set_internal_devs_mtu(struct ofproto *);
static void ofproto_unixctl_init(void);
}
}
+/* Executes the flow modification specified in 'fm'. Returns 0 on success, an
+ * OpenFlow error code as encoded by ofp_mkerr() on failure, or
+ * OFPROTO_POSTPONE if the operation cannot be initiated now but may be retried
+ * later.
+ *
+ * This is a helper function for in-band control and fail-open. */
+int
+ofproto_flow_mod(struct ofproto *ofproto, const struct ofputil_flow_mod *fm)
+{
+ return handle_flow_mod__(ofproto, NULL, fm, NULL);
+}
+
/* Searches for a rule with matching criteria exactly equal to 'target' in
* ofproto's table 0 and, if it finds one, deletes it.
*
{
const char *netdev_name = netdev_get_name(netdev);
struct ofport *ofport;
+ int dev_mtu;
int error;
/* Create ofport. */
hmap_insert(&p->ports, &ofport->hmap_node, hash_int(ofport->ofp_port, 0));
shash_add(&p->port_by_name, netdev_name, ofport);
+ if (!netdev_get_mtu(netdev, &dev_mtu)) {
+ set_internal_devs_mtu(p);
+ ofport->mtu = dev_mtu;
+ } else {
+ ofport->mtu = 0;
+ }
+
/* Let the ofproto_class initialize its private data. */
error = p->ofproto_class->port_construct(ofport);
if (error) {
port = ofproto_get_port(ofproto, ofproto_port.ofp_port);
if (port && !strcmp(netdev_get_name(port->netdev), name)) {
struct netdev *old_netdev = port->netdev;
+ int dev_mtu;
/* 'name' hasn't changed location. Any properties changed? */
if (!ofport_equal(&port->opp, &opp)) {
ofport_modified(port, &opp);
}
+ /* If this is a non-internal port and the MTU changed, check
+ * if the datapath's MTU needs to be updated. */
+ if (strcmp(netdev_get_type(netdev), "internal")
+ && !netdev_get_mtu(netdev, &dev_mtu)
+ && port->mtu != dev_mtu) {
+ set_internal_devs_mtu(ofproto);
+ port->mtu = dev_mtu;
+ }
+
/* Install the newly opened netdev in case it has changed.
* Don't close the old netdev yet in case port_modified has to
* remove a retained reference to it.*/
return 0;
}
+
+/* Find the minimum MTU of all non-datapath devices attached to 'p'.
+ * Returns ETH_PAYLOAD_MAX or the minimum of the ports. */
+static int
+find_min_mtu(struct ofproto *p)
+{
+ struct ofport *ofport;
+ int mtu = 0;
+
+ HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+ struct netdev *netdev = ofport->netdev;
+ int dev_mtu;
+
+ /* Skip any internal ports, since that's what we're trying to
+ * set. */
+ if (!strcmp(netdev_get_type(netdev), "internal")) {
+ continue;
+ }
+
+ if (netdev_get_mtu(netdev, &dev_mtu)) {
+ continue;
+ }
+ if (!mtu || dev_mtu < mtu) {
+ mtu = dev_mtu;
+ }
+ }
+
+ return mtu ? mtu: ETH_PAYLOAD_MAX;
+}
+
+/* Set the MTU of all datapath devices on 'p' to the minimum of the
+ * non-datapath ports. */
+static void
+set_internal_devs_mtu(struct ofproto *p)
+{
+ struct ofport *ofport;
+ int mtu = find_min_mtu(p);
+
+ HMAP_FOR_EACH (ofport, hmap_node, &p->ports) {
+ struct netdev *netdev = ofport->netdev;
+
+ if (!strcmp(netdev_get_type(netdev), "internal")) {
+ netdev_set_mtu(netdev, mtu);
+ }
+ }
+}
\f
static void
ofproto_rule_destroy__(struct rule *rule)
struct ofpbuf request;
struct flow flow;
size_t n_ofp_actions;
- uint16_t in_port;
int error;
COVERAGE_INC(ofproto_packet_out);
/* Get payload. */
if (opo->buffer_id != htonl(UINT32_MAX)) {
error = ofconn_pktbuf_retrieve(ofconn, ntohl(opo->buffer_id),
- &buffer, &in_port);
+ &buffer, NULL);
if (error || !buffer) {
return error;
}
* in which no matching flow already exists in the flow table.
*
* Adds the flow specified by 'ofm', which is followed by 'n_actions'
- * ofp_actions, to the ofproto's flow table. Returns 0 on success or an
- * OpenFlow error code as encoded by ofp_mkerr() on failure.
+ * ofp_actions, to the ofproto's flow table. Returns 0 on success, an OpenFlow
+ * error code as encoded by ofp_mkerr() on failure, or OFPROTO_POSTPONE if the
+ * operation cannot be initiated now but may be retried later.
*
* 'ofconn' is used to retrieve the packet buffer specified in ofm->buffer_id,
* if any. */
static int
handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
- struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofputil_flow_mod fm;
int error;
return error;
}
- if (ofproto->n_pending >= 50) {
- assert(!list_is_empty(&ofproto->pending));
- return OFPROTO_POSTPONE;
- }
-
error = ofputil_decode_flow_mod(&fm, oh,
ofconn_get_flow_mod_table_id(ofconn));
if (error) {
return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
}
- switch (fm.command) {
+ return handle_flow_mod__(ofconn_get_ofproto(ofconn), ofconn, &fm, oh);
+}
+
+static int
+handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
+ const struct ofputil_flow_mod *fm,
+ const struct ofp_header *oh)
+{
+ if (ofproto->n_pending >= 50) {
+ assert(!list_is_empty(&ofproto->pending));
+ return OFPROTO_POSTPONE;
+ }
+
+ switch (fm->command) {
case OFPFC_ADD:
- return add_flow(ofproto, ofconn, &fm, oh);
+ return add_flow(ofproto, ofconn, fm, oh);
case OFPFC_MODIFY:
- return modify_flows_loose(ofproto, ofconn, &fm, oh);
+ return modify_flows_loose(ofproto, ofconn, fm, oh);
case OFPFC_MODIFY_STRICT:
- return modify_flow_strict(ofproto, ofconn, &fm, oh);
+ return modify_flow_strict(ofproto, ofconn, fm, oh);
case OFPFC_DELETE:
- return delete_flows_loose(ofproto, ofconn, &fm, oh);
+ return delete_flows_loose(ofproto, ofconn, fm, oh);
case OFPFC_DELETE_STRICT:
- return delete_flow_strict(ofproto, ofconn, &fm, oh);
+ return delete_flow_strict(ofproto, ofconn, fm, oh);
default:
- if (fm.command > 0xff) {
+ if (fm->command > 0xff) {
VLOG_WARN_RL(&rl, "flow_mod has explicit table_id but "
"flow_mod_table_id extension is not enabled");
}