diff options
Diffstat (limited to 'lib/packets.c')
| -rw-r--r-- | lib/packets.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/lib/packets.c b/lib/packets.c index f16e74951..83c852c13 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -75,6 +75,36 @@ compose_benign_packet(struct ofpbuf *b, const char *tag, uint16_t snap_type, memcpy(payload + tag_size, eth_src, ETH_ADDR_LEN); } +/* Modify the TCI field of 'packet', whose data must begin with an Ethernet + * header. If a VLAN tag is present, its TCI field is replaced by 'tci'. If a + * VLAN tag is not present, one is added with the TCI field set to 'tci'. + * + * Also sets 'packet->l2' to point to the new Ethernet header. */ +void +eth_set_vlan_tci(struct ofpbuf *packet, ovs_be16 tci) +{ + struct eth_header *eh = packet->data; + struct vlan_eth_header *veh; + + if (packet->size >= sizeof(struct vlan_eth_header) + && eh->eth_type == htons(ETH_TYPE_VLAN)) { + veh = packet->data; + veh->veth_tci = tci; + } else { + /* Insert new 802.1Q header. */ + struct vlan_eth_header tmp; + memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN); + memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN); + tmp.veth_type = htons(ETH_TYPE_VLAN); + tmp.veth_tci = tci; + tmp.veth_next_type = eh->eth_type; + + veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN); + memcpy(veh, &tmp, sizeof tmp); + } + packet->l2 = packet->data; +} + /* Stores the string representation of the IPv6 address 'addr' into the * character array 'addr_str', which must be at least INET6_ADDRSTRLEN * bytes long. */ @@ -163,7 +193,6 @@ ipv6_count_cidr_bits(const struct in6_addr *netmask) return count; } - /* Returns true if 'netmask' is a CIDR netmask, that is, if it consists of N * high-order 1-bits and 128-N low-order 0-bits. */ bool |
