@@ -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. */
@@ -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);
@@ -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;
@@ -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);
@@ -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 *);
@@ -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) {
@@ -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;
@@ -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 *
@@ -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 *);
@@ -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);
}
@@ -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);
@@ -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 "
@@ -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) {
@@ -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++;
@@ -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 *);
@@ -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">
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 <jesse@kernel.org> --- lib/bfd.c | 7 ++++++- lib/bfd.h | 2 +- ofproto/ofproto-dpif-monitor.c | 10 ++++++---- ofproto/ofproto-dpif-xlate.c | 26 ++++++++++++++++++-------- ofproto/ofproto-dpif-xlate.h | 2 +- ofproto/ofproto-dpif.c | 16 +++++++++------- ofproto/ofproto-dpif.h | 3 ++- vswitchd/vswitch.xml | 7 +++++++ 8 files changed, 50 insertions(+), 23 deletions(-)