Skip to content

Commit

Permalink
bfd: Allow setting OAM bit when encapsulated in tunnel.
Browse files Browse the repository at this point in the history
Some tunnel protocols, such as Geneve, have a bit in the tunnel
header to indicate that it is an OAM packet. This means that the
packet should be processed as a tunnel control frame and not be
passed onto connected links.

When BFD is used inside of a tunnel it is often used in this control
capacity, so this adds an option to enable marking the outer header
when the output port is a tunnel that supports the OAM concept. It is
also possible to use tunnels as point-to-point links that are simply
carrying BFD as payload, so this is not always turned on.

Conceptually, this may also apply to other types of packets locally
generated by the switch, most obviously CFM. However, BFD seems to
be most commonly used for this type of tunnel monitoring application
so this only adds the option to BFD for the time being to avoid
unnecessarily adding configuration knobs that might never get used.

Signed-off-by: Jesse Gross <[email protected]>
Acked-by: Pravin B Shelar <[email protected]>
  • Loading branch information
jessegross committed Jun 29, 2016
1 parent a5a41e4 commit 2eb7914
Show file tree
Hide file tree
Showing 8 changed files with 50 additions and 23 deletions.
7 changes: 6 additions & 1 deletion lib/bfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,8 @@ struct bfd {
enum flags flags; /* Flags sent on messages. */
enum flags rmt_flags; /* Flags last received. */

bool oam; /* Set tunnel OAM flag if applicable. */

uint32_t rmt_disc; /* bfd.RemoteDiscr. */

struct eth_addr local_eth_src; /* Local eth src address. */
Expand Down Expand Up @@ -390,6 +392,8 @@ bfd_configure(struct bfd *bfd, const char *name, const struct smap *cfg,
bfd_status_changed(bfd);
}

bfd->oam = smap_get_bool(cfg, "oam", false);

atomic_store_relaxed(&bfd->check_tnl_key,
smap_get_bool(cfg, "check_tnl_key", false));
min_tx = smap_get_int(cfg, "min_tx", 100);
Expand Down Expand Up @@ -586,7 +590,7 @@ bfd_should_send_packet(const struct bfd *bfd) OVS_EXCLUDED(mutex)

void
bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
const struct eth_addr eth_src) OVS_EXCLUDED(mutex)
const struct eth_addr eth_src, bool *oam) OVS_EXCLUDED(mutex)
{
long long int min_tx, min_rx;
struct udp_header *udp;
Expand Down Expand Up @@ -654,6 +658,7 @@ bfd_put_packet(struct bfd *bfd, struct dp_packet *p,
msg->min_rx = htonl(min_rx * 1000);

bfd->flags &= ~FLAG_FINAL;
*oam = bfd->oam;

log_msg(VLL_DBG, msg, "Sending BFD Message", bfd);

Expand Down
2 changes: 1 addition & 1 deletion lib/bfd.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ void bfd_run(struct bfd *);

bool bfd_should_send_packet(const struct bfd *);
void bfd_put_packet(struct bfd *bfd, struct dp_packet *packet,
const struct eth_addr eth_src);
const struct eth_addr eth_src, bool *oam);

bool bfd_should_process_flow(const struct bfd *, const struct flow *,
struct flow_wildcards *);
Expand Down
10 changes: 6 additions & 4 deletions ofproto/ofproto-dpif-monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -277,17 +277,19 @@ monitor_mport_run(struct mport *mport, struct dp_packet *packet)
if (mport->cfm && cfm_should_send_ccm(mport->cfm)) {
dp_packet_clear(packet);
cfm_compose_ccm(mport->cfm, packet, mport->hw_addr);
ofproto_dpif_send_packet(mport->ofport, packet);
ofproto_dpif_send_packet(mport->ofport, false, packet);
}
if (mport->bfd && bfd_should_send_packet(mport->bfd)) {
bool oam;

dp_packet_clear(packet);
bfd_put_packet(mport->bfd, packet, mport->hw_addr);
ofproto_dpif_send_packet(mport->ofport, packet);
bfd_put_packet(mport->bfd, packet, mport->hw_addr, &oam);
ofproto_dpif_send_packet(mport->ofport, oam, packet);
}
if (mport->lldp && lldp_should_send_packet(mport->lldp)) {
dp_packet_clear(packet);
lldp_put_packet(mport->lldp, packet, mport->hw_addr);
ofproto_dpif_send_packet(mport->ofport, packet);
ofproto_dpif_send_packet(mport->ofport, false, packet);
}

if (mport->cfm) {
Expand Down
26 changes: 18 additions & 8 deletions ofproto/ofproto-dpif-xlate.c
Original file line number Diff line number Diff line change
Expand Up @@ -5724,18 +5724,21 @@ xlate_resume(struct ofproto_dpif *ofproto,
return error == XLATE_BRIDGE_NOT_FOUND ? OFPERR_NXR_STALE : 0;
}

/* Sends 'packet' out 'ofport'.
/* Sends 'packet' out 'ofport'. If 'port' is a tunnel and that tunnel type
* supports a notion of an OAM flag, sets it if 'oam' is true.
* May modify 'packet'.
* Returns 0 if successful, otherwise a positive errno value. */
int
xlate_send_packet(const struct ofport_dpif *ofport, struct dp_packet *packet)
xlate_send_packet(const struct ofport_dpif *ofport, bool oam,
struct dp_packet *packet)
{
struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
struct xport *xport;
struct ofpact_output output;
uint64_t ofpacts_stub[1024 / 8];
struct ofpbuf ofpacts;
struct flow flow;

ofpact_init(&output.ofpact, OFPACT_OUTPUT, sizeof output);
ofpbuf_use_stack(&ofpacts, ofpacts_stub, sizeof ofpacts_stub);
/* Use OFPP_NONE as the in_port to avoid special packet processing. */
flow_extract(packet, &flow);
flow.in_port.ofp_port = OFPP_NONE;
Expand All @@ -5744,12 +5747,19 @@ xlate_send_packet(const struct ofport_dpif *ofport, struct dp_packet *packet)
if (!xport) {
return EINVAL;
}
output.port = xport->ofp_port;
output.max_len = 0;

if (oam) {
struct ofpact_set_field *sf = ofpact_put_SET_FIELD(&ofpacts);

sf->field = mf_from_id(MFF_TUN_FLAGS);
sf->value.be16 = htons(NX_TUN_FLAG_OAM);
sf->mask.be16 = htons(NX_TUN_FLAG_OAM);
}

ofpact_put_OUTPUT(&ofpacts)->port = xport->ofp_port;

return ofproto_dpif_execute_actions(xport->xbridge->ofproto, &flow, NULL,
&output.ofpact, sizeof output,
packet);
ofpacts.data, ofpacts.size, packet);
}

struct xlate_cache *
Expand Down
2 changes: 1 addition & 1 deletion ofproto/ofproto-dpif-xlate.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ enum ofperr xlate_resume(struct ofproto_dpif *,
const struct ofputil_packet_in_private *,
struct ofpbuf *odp_actions, enum slow_path_reason *);

int xlate_send_packet(const struct ofport_dpif *, struct dp_packet *);
int xlate_send_packet(const struct ofport_dpif *, bool oam, struct dp_packet *);

struct xlate_cache *xlate_cache_new(void);
void xlate_push_stats(struct xlate_cache *, const struct dpif_flow_stats *);
Expand Down
16 changes: 9 additions & 7 deletions ofproto/ofproto-dpif.c
Original file line number Diff line number Diff line change
Expand Up @@ -2219,7 +2219,7 @@ rstp_send_bpdu_cb(struct dp_packet *pkt, void *ofport_, void *ofproto_)
"does not have a configured source MAC address.",
ofproto->up.name, ofp_to_u16(ofport->up.ofp_port));
} else {
ofproto_dpif_send_packet(ofport, pkt);
ofproto_dpif_send_packet(ofport, false, pkt);
}
dp_packet_delete(pkt);
}
Expand All @@ -2243,7 +2243,7 @@ send_bpdu_cb(struct dp_packet *pkt, int port_num, void *ofproto_)
VLOG_WARN_RL(&rl, "%s: cannot send BPDU on port %d "
"with unknown MAC", ofproto->up.name, port_num);
} else {
ofproto_dpif_send_packet(ofport, pkt);
ofproto_dpif_send_packet(ofport, false, pkt);
}
}
dp_packet_delete(pkt);
Expand Down Expand Up @@ -3093,7 +3093,7 @@ send_pdu_cb(void *port_, const void *pdu, size_t pdu_size)
pdu_size);
memcpy(packet_pdu, pdu, pdu_size);

ofproto_dpif_send_packet(port, &packet);
ofproto_dpif_send_packet(port, false, &packet);
dp_packet_uninit(&packet);
} else {
VLOG_ERR_RL(&rl, "port %s: cannot obtain Ethernet address of iface "
Expand Down Expand Up @@ -3132,7 +3132,7 @@ bundle_send_learning_packets(struct ofbundle *bundle)
LIST_FOR_EACH_POP (pkt_node, list_node, &packets) {
int ret;

ret = ofproto_dpif_send_packet(pkt_node->port, pkt_node->pkt);
ret = ofproto_dpif_send_packet(pkt_node->port, false, pkt_node->pkt);
dp_packet_delete(pkt_node->pkt);
free(pkt_node);
if (ret) {
Expand Down Expand Up @@ -4382,16 +4382,18 @@ group_dpif_get_selection_method(const struct group_dpif *group)
return group->up.props.selection_method;
}

/* Sends 'packet' out 'ofport'.
/* Sends 'packet' out 'ofport'. If 'port' is a tunnel and that tunnel type
* supports a notion of an OAM flag, sets it if 'oam' is true.
* May modify 'packet'.
* Returns 0 if successful, otherwise a positive errno value. */
int
ofproto_dpif_send_packet(const struct ofport_dpif *ofport, struct dp_packet *packet)
ofproto_dpif_send_packet(const struct ofport_dpif *ofport, bool oam,
struct dp_packet *packet)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
int error;

error = xlate_send_packet(ofport, packet);
error = xlate_send_packet(ofport, oam, packet);

ovs_mutex_lock(&ofproto->stats_mutex);
ofproto->stats.tx_packets++;
Expand Down
3 changes: 2 additions & 1 deletion ofproto/ofproto-dpif.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ int ofproto_dpif_execute_actions__(struct ofproto_dpif *, const struct flow *,
void ofproto_dpif_send_async_msg(struct ofproto_dpif *,
struct ofproto_async_msg *);
bool ofproto_dpif_wants_packet_in_on_miss(struct ofproto_dpif *);
int ofproto_dpif_send_packet(const struct ofport_dpif *, struct dp_packet *);
int ofproto_dpif_send_packet(const struct ofport_dpif *, bool oam,
struct dp_packet *);
void ofproto_dpif_flow_mod(struct ofproto_dpif *,
const struct ofputil_flow_mod *);
struct rule_dpif *ofproto_dpif_refresh_rule(struct rule_dpif *);
Expand Down
7 changes: 7 additions & 0 deletions vswitchd/vswitch.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,13 @@
Set to an IPv4 address to set the IP address used as destination
for transmitted BFD packets. The default is <code>169.254.1.0</code>.
</column>

<column name="bfd" key="oam">
Some tunnel protocols (such as Geneve) include a bit in the header
to indicate that the encapsulated packet is an OAM frame. By setting
this to true, BFD packets will be marked as OAM if encapsulated in
one of these tunnels.
</column>
</group>

<group title="BFD Status">
Expand Down

0 comments on commit 2eb7914

Please sign in to comment.