aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/cfm.c11
-rw-r--r--lib/cfm.h1
-rw-r--r--lib/packets.c6
-rw-r--r--vswitchd/bridge.c2
-rw-r--r--vswitchd/vswitch.xml7
5 files changed, 24 insertions, 3 deletions
diff --git a/lib/cfm.c b/lib/cfm.c
index 0d79beed..8acbd093 100644
--- a/lib/cfm.c
+++ b/lib/cfm.c
@@ -93,6 +93,7 @@ struct cfm {
uint32_t seq; /* The sequence number of our last CCM. */
uint8_t ccm_interval; /* The CCM transmission interval. */
int ccm_interval_ms; /* 'ccm_interval' in milliseconds. */
+ uint16_t ccm_vlan; /* Vlan tag of CCM PDUs. */
uint8_t maid[CCM_MAID_LEN]; /* The MAID of this CFM. */
struct timer tx_timer; /* Send CCM when expired. */
@@ -345,8 +346,13 @@ cfm_compose_ccm(struct cfm *cfm, struct ofpbuf *packet,
struct ccm *ccm;
timer_set_duration(&cfm->tx_timer, cfm->ccm_interval_ms);
- ccm = eth_compose(packet, cfm_ccm_addr(cfm), eth_src, ETH_TYPE_CFM,
- sizeof *ccm);
+ eth_compose(packet, cfm_ccm_addr(cfm), eth_src, ETH_TYPE_CFM, sizeof *ccm);
+
+ if (cfm->ccm_vlan) {
+ eth_push_vlan(packet, htons(cfm->ccm_vlan));
+ }
+
+ ccm = packet->l3;
ccm->mdlevel_version = 0;
ccm->opcode = CCM_OPCODE;
ccm->tlv_offset = 70;
@@ -400,6 +406,7 @@ cfm_configure(struct cfm *cfm, const struct cfm_settings *s)
interval = ms_to_ccm_interval(s->interval);
interval_ms = ccm_interval_to_ms(interval);
+ cfm->ccm_vlan = s->ccm_vlan & VLAN_VID_MASK;
if (cfm->extended && interval_ms != s->interval) {
interval = 0;
interval_ms = MIN(s->interval, UINT16_MAX);
diff --git a/lib/cfm.h b/lib/cfm.h
index 1c46ffa8..334b80c0 100644
--- a/lib/cfm.h
+++ b/lib/cfm.h
@@ -29,6 +29,7 @@ struct cfm_settings {
int interval; /* The requested transmission interval. */
bool extended; /* Run in extended mode. */
bool opup; /* Operational State. */
+ uint16_t ccm_vlan; /* CCM Vlan tag. Zero if none. */
};
void cfm_init(void);
diff --git a/lib/packets.c b/lib/packets.c
index b704276c..03f92e36 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -259,7 +259,8 @@ ipv6_is_cidr(const struct in6_addr *netmask)
/* Populates 'b' with an Ethernet II packet headed with the given 'eth_dst',
* 'eth_src' and 'eth_type' parameters. A payload of 'size' bytes is allocated
* in 'b' and returned. This payload may be populated with appropriate
- * information by the caller.
+ * information by the caller. Sets 'b''s 'l2' and 'l3' pointers to the
+ * Ethernet header and payload respectively.
*
* The returned packet has enough headroom to insert an 802.1Q VLAN header if
* desired. */
@@ -282,6 +283,9 @@ eth_compose(struct ofpbuf *b, const uint8_t eth_dst[ETH_ADDR_LEN],
memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN);
eth->eth_type = htons(eth_type);
+ b->l2 = eth;
+ b->l3 = data;
+
return data;
}
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 09696d5a..5100b787 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -3005,6 +3005,8 @@ iface_configure_cfm(struct iface *iface)
s.mpid = *cfg->cfm_mpid;
s.interval = atoi(get_interface_other_config(iface->cfg, "cfm_interval",
"0"));
+ s.ccm_vlan = atoi(get_interface_other_config(iface->cfg, "cfm_ccm_vlan",
+ "0"));
if (s.interval <= 0) {
s.interval = 1000;
}
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index bcb6b6fd..80d9cdcc 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -1642,6 +1642,13 @@
OpenFlow action. This setting is ignored when CFM is not in extended
mode. Defaults to <code>up</code>.
</column>
+
+ <column name="other_config" key="cfm_ccm_vlan"
+ type='{"type": "integer", "minInteger": 1, "maxInteger": 4095}'>
+ When set, the CFM module will apply a VLAN tag to all CCMs it generates
+ with the given value.
+ </column>
+
</group>
<group title="Bonding Configuration">