bfd: Implement Bidirectional Forwarding Detection.
[sliver-openvswitch.git] / ofproto / ofproto.c
index c0d94f7..262493e 100644 (file)
@@ -640,6 +640,19 @@ ofproto_set_sflow(struct ofproto *ofproto,
         return oso ? EOPNOTSUPP : 0;
     }
 }
+
+int
+ofproto_set_ipfix(struct ofproto *ofproto,
+                  const struct ofproto_ipfix_bridge_exporter_options *bo,
+                  const struct ofproto_ipfix_flow_exporter_options *fo,
+                  size_t n_fo)
+{
+    if (ofproto->ofproto_class->set_ipfix) {
+        return ofproto->ofproto_class->set_ipfix(ofproto, bo, fo, n_fo);
+    } else {
+        return (bo || fo) ? EOPNOTSUPP : 0;
+    }
+}
 \f
 /* Spanning Tree Protocol (STP) configuration. */
 
@@ -786,6 +799,45 @@ ofproto_port_set_cfm(struct ofproto *ofproto, uint16_t ofp_port,
     }
 }
 
+/* Configures BFD on 'ofp_port' in 'ofproto'.  This function has no effect if
+ * 'ofproto' does not have a port 'ofp_port'. */
+void
+ofproto_port_set_bfd(struct ofproto *ofproto, uint16_t ofp_port,
+                     const struct smap *cfg)
+{
+    struct ofport *ofport;
+    int error;
+
+    ofport = ofproto_get_port(ofproto, ofp_port);
+    if (!ofport) {
+        VLOG_WARN("%s: cannot configure bfd on nonexistent port %"PRIu16,
+                  ofproto->name, ofp_port);
+    }
+
+    error = (ofproto->ofproto_class->set_bfd
+             ? ofproto->ofproto_class->set_bfd(ofport, cfg)
+             : EOPNOTSUPP);
+    if (error) {
+        VLOG_WARN("%s: bfd configuration on port %"PRIu16" (%s) failed (%s)",
+                  ofproto->name, ofp_port, netdev_get_name(ofport->netdev),
+                  strerror(error));
+    }
+}
+
+/* Populates 'status' with key value pairs indicating the status of the BFD
+ * session on 'ofp_port'.  This information is intended to be populated in the
+ * OVS database.  Has no effect if 'ofp_port' is not na OpenFlow port in
+ * 'ofproto'. */
+int
+ofproto_port_get_bfd_status(struct ofproto *ofproto, uint16_t ofp_port,
+                            struct smap *status)
+{
+    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
+    return (ofport && ofproto->ofproto_class->get_bfd_status
+            ? ofproto->ofproto_class->get_bfd_status(ofport, status)
+            : EOPNOTSUPP);
+}
+
 /* Checks the status of LACP negotiation for 'ofp_port' within ofproto.
  * Returns 1 if LACP partner information for 'ofp_port' is up-to-date,
  * 0 if LACP partner information is not current (generally indicating a
@@ -2238,7 +2290,7 @@ handle_set_config(struct ofconn *ofconn, const struct ofp_header *oh)
     uint16_t flags = ntohs(osc->flags);
 
     if (ofconn_get_type(ofconn) != OFCONN_PRIMARY
-        || ofconn_get_role(ofconn) != NX_ROLE_SLAVE) {
+        || ofconn_get_role(ofconn) != OFPCR12_ROLE_SLAVE) {
         enum ofp_config_flags cur = ofproto->frag_handling;
         enum ofp_config_flags next = flags & OFPC_FRAG_MASK;
 
@@ -2272,7 +2324,7 @@ static enum ofperr
 reject_slave_controller(struct ofconn *ofconn)
 {
     if (ofconn_get_type(ofconn) == OFCONN_PRIMARY
-        && ofconn_get_role(ofconn) == NX_ROLE_SLAVE) {
+        && ofconn_get_role(ofconn) == OFPCR12_ROLE_SLAVE) {
         return OFPERR_OFPBRC_EPERM;
     } else {
         return 0;
@@ -2843,62 +2895,21 @@ ofproto_get_netflow_ids(const struct ofproto *ofproto,
     ofproto->ofproto_class->get_netflow_ids(ofproto, engine_type, engine_id);
 }
 
-/* Checks the fault status of CFM for 'ofp_port' within 'ofproto'.  Returns a
- * bitmask of 'cfm_fault_reason's to indicate a CFM fault (generally
- * indicating a connectivity problem).  Returns zero if CFM is not faulted,
- * and -1 if CFM is not enabled on 'ofp_port'. */
-int
-ofproto_port_get_cfm_fault(const struct ofproto *ofproto, uint16_t ofp_port)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_fault
-            ? ofproto->ofproto_class->get_cfm_fault(ofport)
-            : -1);
-}
-
-/* Checks the operational status reported by the remote CFM endpoint of
- * 'ofp_port'  Returns 1 if operationally up, 0 if operationally down, and -1
- * if CFM is not enabled on 'ofp_port' or does not support operational status.
- */
-int
-ofproto_port_get_cfm_opup(const struct ofproto *ofproto, uint16_t ofp_port)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_opup
-            ? ofproto->ofproto_class->get_cfm_opup(ofport)
-            : -1);
-}
-
-/* Gets the MPIDs of the remote maintenance points broadcasting to 'ofp_port'
- * within 'ofproto'.  Populates 'rmps' with an array of MPIDs owned by
- * 'ofproto', and 'n_rmps' with the number of MPIDs in 'rmps'.  Returns a
- * number less than 0 if CFM is not enabled on 'ofp_port'. */
-int
-ofproto_port_get_cfm_remote_mpids(const struct ofproto *ofproto,
-                                  uint16_t ofp_port, const uint64_t **rmps,
-                                  size_t *n_rmps)
-{
-    struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-
-    *rmps = NULL;
-    *n_rmps = 0;
-    return (ofport && ofproto->ofproto_class->get_cfm_remote_mpids
-            ? ofproto->ofproto_class->get_cfm_remote_mpids(ofport, rmps,
-                                                           n_rmps)
-            : -1);
-}
-
-/* Checks the health of the CFM for 'ofp_port' within 'ofproto'.  Returns an
- * integer value between 0 and 100 to indicate the health of the port as a
- * percentage which is the average of cfm health of all the remote_mpids or
- * returns -1 if CFM is not enabled on 'ofport'. */
-int
-ofproto_port_get_cfm_health(const struct ofproto *ofproto, uint16_t ofp_port)
+/* Checks the status of CFM configured on 'ofp_port' within 'ofproto'.  Returns
+ * true if the port's CFM status was successfully stored into '*status'.
+ * Returns false if the port did not have CFM configured, in which case
+ * '*status' is indeterminate.
+ *
+ * The caller must provide and owns '*status', but it does not own and must not
+ * modify or free the array returned in 'status->rmps'. */
+bool
+ofproto_port_get_cfm_status(const struct ofproto *ofproto, uint16_t ofp_port,
+                            struct ofproto_cfm_status *status)
 {
     struct ofport *ofport = ofproto_get_port(ofproto, ofp_port);
-    return (ofport && ofproto->ofproto_class->get_cfm_health
-            ? ofproto->ofproto_class->get_cfm_health(ofport)
-            : -1);
+    return (ofport
+            && ofproto->ofproto_class->get_cfm_status
+            && ofproto->ofproto_class->get_cfm_status(ofport, status));
 }
 
 static enum ofperr
@@ -3576,38 +3587,34 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofconn *ofconn,
 static enum ofperr
 handle_role_request(struct ofconn *ofconn, const struct ofp_header *oh)
 {
-    struct ofputil_role_request rr;
+    struct ofputil_role_request request;
+    struct ofputil_role_request reply;
     struct ofpbuf *buf;
-    uint32_t role;
     enum ofperr error;
 
-    error = ofputil_decode_role_message(oh, &rr);
+    error = ofputil_decode_role_message(oh, &request);
     if (error) {
         return error;
     }
 
-    if (rr.request_current_role_only) {
-        role = ofconn_get_role(ofconn); /* NX_ROLE_* */
-        goto reply;
-    }
-
-    role = rr.role;
-
-    if (ofconn_get_role(ofconn) != role
-        && ofconn_has_pending_opgroups(ofconn)) {
-        return OFPROTO_POSTPONE;
-    }
+    if (request.role != OFPCR12_ROLE_NOCHANGE) {
+        if (ofconn_get_role(ofconn) != request.role
+            && ofconn_has_pending_opgroups(ofconn)) {
+            return OFPROTO_POSTPONE;
+        }
 
-    if (rr.have_generation_id) {
-        if (!ofconn_set_master_election_id(ofconn, rr.generation_id)) {
-            return OFPERR_OFPRRFC_STALE;
+        if (request.have_generation_id
+            && !ofconn_set_master_election_id(ofconn, request.generation_id)) {
+                return OFPERR_OFPRRFC_STALE;
         }
-    }
 
-    ofconn_set_role(ofconn, role);
+        ofconn_set_role(ofconn, request.role);
+    }
 
-reply:
-    buf = ofputil_encode_role_reply(oh, role);
+    reply.role = ofconn_get_role(ofconn);
+    reply.have_generation_id = ofconn_get_master_election_id(
+        ofconn, &reply.generation_id);
+    buf = ofputil_encode_role_reply(oh, &reply);
     ofconn_send_reply(ofconn, buf);
 
     return 0;