X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fforward.c;h=97aceb9c81339bafa805f59f322cd28cc9bc3231;hb=b5e9402df53a1f0cd745bf8b91c246e1c5e4b11d;hp=239e80153d6a79b9325b2e76c58cdade09ea3ae3;hpb=9bf3d9301e2473c034c947b45ee06ab6b5af5877;p=openvswitch diff --git a/datapath/forward.c b/datapath/forward.c index 239e8015..97aceb9c 100644 --- a/datapath/forward.c +++ b/datapath/forward.c @@ -4,6 +4,8 @@ * Stanford Junior University */ +#include +#include #include #include #include @@ -26,59 +28,70 @@ static int make_writable(struct sk_buff **); static struct sk_buff *retrieve_skb(uint32_t id); static void discard_skb(uint32_t id); -/* 'skb' was received on 'in_port', a physical switch port between 0 and - * OFPP_MAX. Process it according to 'chain'. Returns 0 if successful, in - * which case 'skb' is destroyed, or -ESRCH if there is no matching flow, in - * which case 'skb' still belongs to the caller. */ +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain'. Returns 0 + * if successful, in which case 'skb' is destroyed, or -ESRCH if there is no + * matching flow, in which case 'skb' still belongs to the caller. */ int run_flow_through_tables(struct sw_chain *chain, struct sk_buff *skb, - int in_port) + struct net_bridge_port *p) { + /* Ethernet address used as the destination for STP frames. */ + static const uint8_t stp_eth_addr[ETH_ALEN] + = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x01 }; struct sw_flow_key key; struct sw_flow *flow; - if (flow_extract(skb, in_port, &key) + if (flow_extract(skb, p ? p->port_no : OFPP_NONE, &key) && (chain->dp->flags & OFPC_FRAG_MASK) == OFPC_FRAG_DROP) { /* Drop fragment. */ kfree_skb(skb); return 0; } + if (p && p->flags & (OFPPFL_NO_RECV | OFPPFL_NO_RECV_STP) && + p->flags & (compare_ether_addr(key.dl_dst, stp_eth_addr) + ? OFPPFL_NO_RECV : OFPPFL_NO_RECV_STP)) { + kfree_skb(skb); + return 0; + } flow = chain_lookup(chain, &key); if (likely(flow != NULL)) { flow_used(flow, skb); execute_actions(chain->dp, skb, &key, - flow->actions, flow->n_actions); + flow->actions, flow->n_actions, 0); return 0; } else { return -ESRCH; } } -/* 'skb' was received on 'in_port', a physical switch port between 0 and - * OFPP_MAX. Process it according to 'chain', sending it up to the controller - * if no flow matches. Takes ownership of 'skb'. */ -void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, int in_port) +/* 'skb' was received on port 'p', which may be a physical switch port, the + * local port, or a null pointer. Process it according to 'chain', sending it + * up to the controller if no flow matches. Takes ownership of 'skb'. */ +void fwd_port_input(struct sw_chain *chain, struct sk_buff *skb, + struct net_bridge_port *p) { - if (run_flow_through_tables(chain, skb, in_port)) + if (run_flow_through_tables(chain, skb, p)) dp_output_control(chain->dp, skb, fwd_save_skb(skb), chain->dp->miss_send_len, OFPR_NO_MATCH); } static int do_output(struct datapath *dp, struct sk_buff *skb, size_t max_len, - int out_port) + int out_port, int ignore_no_fwd) { if (!skb) return -ENOMEM; return (likely(out_port != OFPP_CONTROLLER) - ? dp_output_port(dp, skb, out_port) + ? dp_output_port(dp, skb, out_port, ignore_no_fwd) : dp_output_control(dp, skb, fwd_save_skb(skb), max_len, OFPR_ACTION)); } void execute_actions(struct datapath *dp, struct sk_buff *skb, - const struct sw_flow_key *key, - const struct ofp_action *actions, int n_actions) + const struct sw_flow_key *key, + const struct ofp_action *actions, int n_actions, + int ignore_no_fwd) { /* Every output action needs a separate clone of 'skb', but the common * case is just a single output action, so that doing a clone and @@ -97,7 +110,7 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb, if (prev_port != -1) { do_output(dp, skb_clone(skb, GFP_ATOMIC), - max_len, prev_port); + max_len, prev_port, ignore_no_fwd); prev_port = -1; } @@ -119,7 +132,7 @@ void execute_actions(struct datapath *dp, struct sk_buff *skb, } } if (prev_port != -1) - do_output(dp, skb, max_len, prev_port); + do_output(dp, skb, max_len, prev_port, ignore_no_fwd); else kfree_skb(skb); } @@ -367,7 +380,7 @@ recv_packet_out(struct sw_chain *chain, const struct sender *sender, dp_set_origin(chain->dp, ntohs(opo->in_port), skb); flow_extract(skb, ntohs(opo->in_port), &key); - execute_actions(chain->dp, skb, &key, opo->actions, n_actions); + execute_actions(chain->dp, skb, &key, opo->actions, n_actions, 1); return 0; } @@ -452,7 +465,7 @@ add_flow(struct sw_chain *chain, const struct ofp_flow_mod *ofm) struct sw_flow_key key; flow_used(flow, skb); flow_extract(skb, ntohs(ofm->match.in_port), &key); - execute_actions(chain->dp, skb, &key, ofm->actions, n_actions); + execute_actions(chain->dp, skb, &key, ofm->actions, n_actions, 0); } else error = -ESRCH;