X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fpackets.c;h=8791a3ce09a244b20719a484a23d30eeaa191d21;hb=e868fb3d322f5c46385f1fc6db5bb1ab33f90305;hp=5c51feb1f3d289490de750063c8e9d79214df822;hpb=02dd3123a0e312f1d33403e744af52dd6096f12d;p=openvswitch diff --git a/lib/packets.c b/lib/packets.c index 5c51feb1..8791a3ce 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Nicira Networks. + * Copyright (c) 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,26 @@ #include #include "packets.h" +#include +#include #include #include +#include "byte-order.h" +#include "dynamic-string.h" #include "ofpbuf.h" +const struct in6_addr in6addr_exact = IN6ADDR_EXACT_INIT; + +/* Parses 's' as a 16-digit hexadecimal number representing a datapath ID. On + * success stores the dpid into '*dpidp' and returns true, on failure stores 0 + * into '*dpidp' and returns false. + * + * Rejects an all-zeros dpid as invalid. */ bool dpid_from_string(const char *s, uint64_t *dpidp) { *dpidp = (strlen(s) == 16 && strspn(s, "0123456789abcdefABCDEF") == 16 - ? strtoll(s, NULL, 16) + ? strtoull(s, NULL, 16) : 0); return *dpidp != 0; } @@ -78,3 +89,173 @@ compose_benign_packet(struct ofpbuf *b, const char *tag, uint16_t snap_type, memcpy(llc_snap->snap.snap_org, "\x00\x23\x20", 3); llc_snap->snap.snap_type = htons(snap_type); } + +/* Stores the string representation of the IPv6 address 'addr' into the + * character array 'addr_str', which must be at least INET6_ADDRSTRLEN + * bytes long. */ +void +format_ipv6_addr(char *addr_str, const struct in6_addr *addr) +{ + inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN); +} + +void +print_ipv6_addr(struct ds *string, const struct in6_addr *addr) +{ + char addr_str[INET6_ADDRSTRLEN]; + + format_ipv6_addr(addr_str, addr); + ds_put_format(string, "%s", addr_str); +} + +struct in6_addr ipv6_addr_bitand(const struct in6_addr *a, + const struct in6_addr *b) +{ + int i; + struct in6_addr dst; + +#ifdef s6_addr32 + for (i=0; i<4; i++) { + dst.s6_addr32[i] = a->s6_addr32[i] & b->s6_addr32[i]; + } +#else + for (i=0; i<16; i++) { + dst.s6_addr[i] = a->s6_addr[i] & b->s6_addr[i]; + } +#endif + + return dst; +} + +/* Returns an in6_addr consisting of 'mask' high-order 1-bits and 128-N + * low-order 0-bits. */ +struct in6_addr +ipv6_create_mask(int mask) +{ + struct in6_addr netmask; + uint8_t *netmaskp = &netmask.s6_addr[0]; + + memset(&netmask, 0, sizeof netmask); + while (mask > 8) { + *netmaskp = 0xff; + netmaskp++; + mask -= 8; + } + + if (mask) { + *netmaskp = 0xff << (8 - mask); + } + + return netmask; +} + +/* Given the IPv6 netmask 'netmask', returns the number of bits of the + * IPv6 address that it wildcards. 'netmask' must be a CIDR netmask (see + * ipv6_is_cidr()). */ +int +ipv6_count_cidr_bits(const struct in6_addr *netmask) +{ + int i; + int count = 0; + const uint8_t *netmaskp = &netmask->s6_addr[0]; + + assert(ipv6_is_cidr(netmask)); + + for (i=0; i<16; i++) { + if (netmaskp[i] == 0xff) { + count += 8; + } else { + uint8_t nm; + + for(nm = netmaskp[i]; nm; nm <<= 1) { + count++; + } + break; + } + + } + + 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 +ipv6_is_cidr(const struct in6_addr *netmask) +{ + const uint8_t *netmaskp = &netmask->s6_addr[0]; + int i; + + for (i=0; i<16; i++) { + if (netmaskp[i] != 0xff) { + uint8_t x = ~netmaskp[i]; + if (x & (x + 1)) { + return false; + } + while (++i < 16) { + if (netmaskp[i]) { + return false; + } + } + } + } + + return true; +} + +/* Fills 'b' with a LACP packet whose source address is 'eth_src', LACP actor + * information is 'actor', and LACP partner information is 'partner'. */ +void +compose_lacp_packet(struct ofpbuf *b, struct lacp_info *actor, + struct lacp_info *partner, + const uint8_t eth_src[ETH_ADDR_LEN]) +{ + struct eth_header *eth; + struct lacp_pdu *pdu; + + ofpbuf_clear(b); + + ofpbuf_prealloc_tailroom(b, ETH_HEADER_LEN + LACP_PDU_LEN); + eth = ofpbuf_put_zeros(b, ETH_HEADER_LEN); + pdu = ofpbuf_put_zeros(b, LACP_PDU_LEN); + + memcpy(eth->eth_dst, eth_addr_lacp, ETH_ADDR_LEN); + memcpy(eth->eth_src, eth_src, ETH_ADDR_LEN); + eth->eth_type = htons(ETH_TYPE_LACP); + + pdu->subtype = 1; + pdu->version = 1; + + pdu->actor_type = 1; + pdu->actor_len = 20; + pdu->actor = *actor; + + pdu->partner_type = 2; + pdu->partner_len = 20; + pdu->partner = *partner; + + pdu->collector_type = 3; + pdu->collector_len = 16; + pdu->collector_delay = htons(0); +} + +/* Parses 'b' which represents a packet containing a LACP PDU. This function + * returns NULL if 'b' is malformed, or does not represent a LACP PDU format + * supported by OVS. Otherwise, it returns a pointer to the lacp_pdu contained + * within 'b'. */ +const struct lacp_pdu * +parse_lacp_packet(const struct ofpbuf *b) +{ + const struct lacp_pdu *pdu; + + pdu = ofpbuf_at(b, (uint8_t *)b->l3 - (uint8_t *)b->data, LACP_PDU_LEN); + + if (pdu && pdu->subtype == 1 + && pdu->actor_type == 1 && pdu->actor_len == 20 + && pdu->partner_type == 2 && pdu->partner_len == 20) { + return pdu; + } else { + return NULL; + } +}