summaryrefslogtreecommitdiff
path: root/lib/packets.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/packets.c')
-rw-r--r--lib/packets.c46
1 files changed, 46 insertions, 0 deletions
diff --git a/lib/packets.c b/lib/packets.c
index 4a7643c5d..d0fba8176 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -418,6 +418,40 @@ push_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse)
pkt_metadata_init_conn(&packet->md);
}
+void
+add_mpls(struct dp_packet *packet, ovs_be16 ethtype, ovs_be32 lse,
+ bool l3_encap)
+{
+ if (!eth_type_mpls(ethtype)) {
+ return;
+ }
+
+ if (!l3_encap) {
+ ovs_be32 *header = dp_packet_push_uninit(packet, MPLS_HLEN);
+
+ *header = lse;
+ packet->l2_5_ofs = 0;
+ packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
+ ntohs(ethtype));
+ } else {
+ size_t len;
+ char *header;
+
+ if (!is_mpls(packet)) {
+ /* Set MPLS label stack offset. */
+ packet->l2_5_ofs = packet->l3_ofs;
+ }
+ set_ethertype(packet, ethtype);
+
+ /* Push new MPLS shim header onto packet. */
+ len = packet->l2_5_ofs;
+ header = dp_packet_resize_l2_5(packet, MPLS_HLEN);
+ memmove(header, header + MPLS_HLEN, len);
+ memcpy(header + len, &lse, sizeof lse);
+ }
+ pkt_metadata_init_conn(&packet->md);
+}
+
/* If 'packet' is an MPLS packet, removes its outermost MPLS label stack entry.
* If the label that was removed was the only MPLS label, changes 'packet''s
* Ethertype to 'ethtype' (which ordinarily should not be an MPLS
@@ -440,6 +474,18 @@ pop_mpls(struct dp_packet *packet, ovs_be16 ethtype)
/* Invalidate offload flags as they are not valid after
* decapsulation of MPLS header. */
dp_packet_reset_offload(packet);
+
+ /* packet_type must be reset for the MPLS packets with no l2 header */
+ if (!len) {
+ if (ethtype == htons(ETH_TYPE_TEB)) {
+ /* The inner packet must be classified as ethernet if the
+ * ethtype is ETH_TYPE_TEB. */
+ packet->packet_type = htonl(PT_ETH);
+ } else {
+ packet->packet_type = PACKET_TYPE_BE(OFPHTN_ETHERTYPE,
+ ntohs(ethtype));
+ }
+ }
}
}