Skip to content

Commit 33158a1

Browse files
author
Justin Pettit
committed
ofproto-dpif: Fake-up OFPP_NONE input bundle for mirroring and normal.
Both mirroring and "normal" processing make use of the input bundle to perform various sanity checks. Controller-generated traffic typically uses an ingress port of OFPP_NONE, which doesn't have a corresponding input bundle. This commit fakes one up well enough that mirroring and "normal" processing succeed. We looked at creating an actual bundle based on the "real" OFPP_NONE. This was even uglier, since there were even more special-cases that needed to be handled, including having to hide it from port queries. Reported-by: Jesse Gross <jesse@nicira.com> Signed-off-by: Justin Pettit <jpettit@nicira.com>
1 parent 3581c12 commit 33158a1

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

ofproto/ofproto-dpif.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ static void bundle_wait(struct ofbundle *);
179179
static struct ofbundle *lookup_input_bundle(struct ofproto_dpif *,
180180
uint16_t in_port, bool warn);
181181

182+
/* A controller may use OFPP_NONE as the ingress port to indicate that
183+
* it did not arrive on a "real" port. 'ofpp_none_bundle' exists for
184+
* when an input bundle is needed for validation (e.g., mirroring or
185+
* OFPP_NORMAL processing). It is not connected to an 'ofproto' or have
186+
* any 'port' structs, so care must be taken when dealing with it. */
187+
static struct ofbundle ofpp_none_bundle = {
188+
.name = "OFPP_NONE",
189+
.vlan_mode = PORT_VLAN_TRUNK
190+
};
191+
182192
static void stp_run(struct ofproto_dpif *ofproto);
183193
static void stp_wait(struct ofproto_dpif *ofproto);
184194

@@ -4858,6 +4868,11 @@ input_vid_to_vlan(const struct ofbundle *in_bundle, uint16_t vid)
48584868
static bool
48594869
input_vid_is_valid(uint16_t vid, struct ofbundle *in_bundle, bool warn)
48604870
{
4871+
/* Allow any VID on the OFPP_NONE port. */
4872+
if (in_bundle == &ofpp_none_bundle) {
4873+
return true;
4874+
}
4875+
48614876
switch (in_bundle->vlan_mode) {
48624877
case PORT_VLAN_ACCESS:
48634878
if (vid) {
@@ -5171,6 +5186,11 @@ update_learning_table(struct ofproto_dpif *ofproto,
51715186
{
51725187
struct mac_entry *mac;
51735188

5189+
/* Don't learn the OFPP_NONE port. */
5190+
if (in_bundle == &ofpp_none_bundle) {
5191+
return;
5192+
}
5193+
51745194
if (!mac_learning_may_learn(ofproto->ml, flow->dl_src, vlan)) {
51755195
return;
51765196
}
@@ -5206,6 +5226,12 @@ lookup_input_bundle(struct ofproto_dpif *ofproto, uint16_t in_port, bool warn)
52065226
{
52075227
struct ofport_dpif *ofport;
52085228

5229+
/* Special-case OFPP_NONE, which a controller may use as the ingress
5230+
* port for traffic that it is sourcing. */
5231+
if (in_port == OFPP_NONE) {
5232+
return &ofpp_none_bundle;
5233+
}
5234+
52095235
/* Find the port and bundle for the received packet. */
52105236
ofport = get_ofp_port(ofproto, in_port);
52115237
if (ofport && ofport->bundle) {
@@ -5299,7 +5325,8 @@ xlate_normal(struct action_xlate_ctx *ctx)
52995325
return;
53005326
}
53015327

5302-
/* We know 'in_port' exists, since lookup_input_bundle() succeeded. */
5328+
/* We know 'in_port' exists unless it is "ofpp_none_bundle",
5329+
* since lookup_input_bundle() succeeded. */
53035330
in_port = get_ofp_port(ctx->ofproto, ctx->flow.in_port);
53045331

53055332
/* Drop malformed frames. */
@@ -5333,7 +5360,8 @@ xlate_normal(struct action_xlate_ctx *ctx)
53335360
vlan = input_vid_to_vlan(in_bundle, vid);
53345361

53355362
/* Check other admissibility requirements. */
5336-
if (!is_admissible(ctx->ofproto, &ctx->flow, in_port, vlan, &ctx->tags)) {
5363+
if (in_port &&
5364+
!is_admissible(ctx->ofproto, &ctx->flow, in_port, vlan, &ctx->tags)) {
53375365
return;
53385366
}
53395367

tests/ofproto-dpif.at

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,36 @@ AT_CHECK_UNQUOTED([tail -1 stdout], [0],
460460
OVS_VSWITCHD_STOP
461461
AT_CLEANUP
462462

463+
AT_SETUP([ofproto-dpif - mirroring, OFPP_NONE ingress port])
464+
OVS_VSWITCHD_START(
465+
[add-port br0 p1 -- set Interface p1 type=dummy --\
466+
add-port br0 p2 -- set Interface p2 type=dummy --\
467+
set Bridge br0 mirrors=@m --\
468+
--id=@p2 get Port p2 --\
469+
--id=@m create Mirror name=mymirror \
470+
select_all=true output_port=@p2], [<0>
471+
])
472+
473+
AT_CHECK(
474+
[ovs-vsctl \
475+
-- get Interface p1 ofport \
476+
-- get Interface p2 ofport],
477+
[0], [stdout])
478+
set `cat stdout`
479+
p1=$1 p2=$2
480+
481+
AT_CHECK([ovs-ofctl add-flow br0 action=output:1])
482+
483+
# "in_port" defaults to OFPP_NONE if it's not specified.
484+
flow="eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"
485+
AT_CHECK([ovs-appctl ofproto/trace br0 "$flow"], [0], [stdout])
486+
AT_CHECK_UNQUOTED([tail -1 stdout], [0],
487+
[Datapath actions: $p1,$p2
488+
])
489+
490+
OVS_VSWITCHD_STOP
491+
AT_CLEANUP
492+
463493

464494
AT_SETUP([ofproto-dpif - mirroring, select_dst])
465495
OVS_VSWITCHD_START(

0 commit comments

Comments
 (0)