/*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
static void bundle_del_port(struct ofport_dpif *);
static void bundle_run(struct ofbundle *);
static void bundle_wait(struct ofbundle *);
-static struct ofport_dpif *lookup_input_bundle(struct ofproto_dpif *,
- uint16_t in_port, bool warn);
+static struct ofbundle *lookup_input_bundle(struct ofproto_dpif *,
+ uint16_t in_port, bool warn);
+
+/* A controller may use OFPP_NONE as the ingress port to indicate that
+ * it did not arrive on a "real" port. 'ofpp_none_bundle' exists for
+ * when an input bundle is needed for validation (e.g., mirroring or
+ * OFPP_NORMAL processing). It is not connected to an 'ofproto' or have
+ * any 'port' structs, so care must be taken when dealing with it. */
+static struct ofbundle ofpp_none_bundle = {
+ .name = "OFPP_NONE",
+ .vlan_mode = PORT_VLAN_TRUNK
+};
static void stp_run(struct ofproto_dpif *ofproto);
static void stp_wait(struct ofproto_dpif *ofproto);
if (e->port.p != bundle) {
struct ofpbuf *learning_packet;
struct ofport_dpif *port;
+ void *port_void;
int ret;
- learning_packet = bond_compose_learning_packet(bundle->bond, e->mac,
- e->vlan,
- (void **)&port);
+ /* The assignment to "port" is unnecessary but makes "grep"ing for
+ * struct ofport_dpif more effective. */
+ learning_packet = bond_compose_learning_packet(bundle->bond,
+ e->mac, e->vlan,
+ &port_void);
+ port = port_void;
ret = send_packet(port, learning_packet);
ofpbuf_delete(learning_packet);
if (ret) {
static bool
input_vid_is_valid(uint16_t vid, struct ofbundle *in_bundle, bool warn)
{
+ /* Allow any VID on the OFPP_NONE port. */
+ if (in_bundle == &ofpp_none_bundle) {
+ return true;
+ }
+
switch (in_bundle->vlan_mode) {
case PORT_VLAN_ACCESS:
if (vid) {
{
struct ofproto_dpif *ofproto = ctx->ofproto;
mirror_mask_t mirrors;
- struct ofport_dpif *in_port;
struct ofbundle *in_bundle;
uint16_t vlan;
uint16_t vid;
const struct nlattr *a;
size_t left;
- /* Obtain in_port from orig_flow.in_port.
- *
- * lookup_input_bundle() also ensures that in_port belongs to a bundle. */
- in_port = lookup_input_bundle(ctx->ofproto, orig_flow->in_port,
- ctx->packet != NULL);
- if (!in_port) {
+ in_bundle = lookup_input_bundle(ctx->ofproto, orig_flow->in_port,
+ ctx->packet != NULL);
+ if (!in_bundle) {
return;
}
- in_bundle = in_port->bundle;
mirrors = in_bundle->src_mirrors;
/* Drop frames on bundles reserved for mirroring. */
{
struct mac_entry *mac;
+ /* Don't learn the OFPP_NONE port. */
+ if (in_bundle == &ofpp_none_bundle) {
+ return;
+ }
+
if (!mac_learning_may_learn(ofproto->ml, flow->dl_src, vlan)) {
return;
}
}
}
-static struct ofport_dpif *
+static struct ofbundle *
lookup_input_bundle(struct ofproto_dpif *ofproto, uint16_t in_port, bool warn)
{
struct ofport_dpif *ofport;
+ /* Special-case OFPP_NONE, which a controller may use as the ingress
+ * port for traffic that it is sourcing. */
+ if (in_port == OFPP_NONE) {
+ return &ofpp_none_bundle;
+ }
+
/* Find the port and bundle for the received packet. */
ofport = get_ofp_port(ofproto, in_port);
if (ofport && ofport->bundle) {
- return ofport;
+ return ofport->bundle;
}
/* Odd. A few possible reasons here:
ctx->has_normal = true;
- /* Obtain in_port from ctx->flow.in_port.
- *
- * lookup_input_bundle() also ensures that in_port belongs to a bundle. */
- in_port = lookup_input_bundle(ctx->ofproto, ctx->flow.in_port,
+ in_bundle = lookup_input_bundle(ctx->ofproto, ctx->flow.in_port,
ctx->packet != NULL);
- if (!in_port) {
+ if (!in_bundle) {
return;
}
- in_bundle = in_port->bundle;
+
+ /* We know 'in_port' exists unless it is "ofpp_none_bundle",
+ * since lookup_input_bundle() succeeded. */
+ in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
/* Drop malformed frames. */
if (ctx->flow.dl_type == htons(ETH_TYPE_VLAN) &&
vlan = input_vid_to_vlan(in_bundle, vid);
/* Check other admissibility requirements. */
- if (!is_admissible(ctx->ofproto, &ctx->flow, in_port, vlan, &ctx->tags)) {
+ if (in_port &&
+ !is_admissible(ctx->ofproto, &ctx->flow, in_port, vlan, &ctx->tags)) {
return;
}
if (mac->port.p != in_bundle) {
output_normal(ctx, mac->port.p, vlan);
}
- } else if (!ctx->packet && !eth_addr_is_multicast(ctx->flow.dl_dst)) {
- /* If we are revalidating but don't have a learning entry then eject
- * the flow. Installing a flow that floods packets opens up a window
- * of time where we could learn from a packet reflected on a bond and
- * blackhole packets before the learning table is updated to reflect
- * the correct port. */
- ctx->may_set_up_flow = false;
- return;
} else {
struct ofbundle *bundle;