}
}
-
-/* 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)
+/* Parses string 's', which must be an IP address with an optional netmask or
+ * CIDR prefix length. Stores the IP address into '*ip' and the netmask into
+ * '*mask'. (If 's' does not contain a netmask, 255.255.255.255 is
+ * assumed.)
+ *
+ * Returns NULL if successful, otherwise an error message that the caller must
+ * free(). */
+char * OVS_WARN_UNUSED_RESULT
+ip_parse_masked(const char *s, ovs_be32 *ip, ovs_be32 *mask)
{
- inet_ntop(AF_INET6, addr, addr_str, INET6_ADDRSTRLEN);
+ int prefix;
+ int n;
+
+ if (ovs_scan(s, IP_SCAN_FMT"/"IP_SCAN_FMT"%n",
+ IP_SCAN_ARGS(ip), IP_SCAN_ARGS(mask), &n) && !s[n]) {
+ /* OK. */
+ } else if (ovs_scan(s, IP_SCAN_FMT"/%d%n", IP_SCAN_ARGS(ip), &prefix, &n)
+ && !s[n]) {
+ if (prefix <= 0 || prefix > 32) {
+ return xasprintf("%s: network prefix bits not between 0 and "
+ "32", s);
+ }
+ *mask = be32_prefix_mask(prefix);
+ } else if (ovs_scan(s, IP_SCAN_FMT"%n", IP_SCAN_ARGS(ip), &n) && !s[n]) {
+ *mask = OVS_BE32_MAX;
+ } else {
+ return xasprintf("%s: invalid IP address", s);
+ }
+ return NULL;
}
void
-print_ipv6_addr(struct ds *string, const struct in6_addr *addr)
+ipv6_format_addr(const struct in6_addr *addr, struct ds *s)
{
char *dst;
- ds_reserve(string, string->length + INET6_ADDRSTRLEN);
+ ds_reserve(s, s->length + INET6_ADDRSTRLEN);
- dst = string->string + string->length;
- format_ipv6_addr(dst, addr);
- string->length += strlen(dst);
+ dst = s->string + s->length;
+ inet_ntop(AF_INET6, addr, dst, INET6_ADDRSTRLEN);
+ s->length += strlen(dst);
}
void
-print_ipv6_mapped(struct ds *s, const struct in6_addr *addr)
+ipv6_format_mapped(const struct in6_addr *addr, struct ds *s)
{
if (IN6_IS_ADDR_V4MAPPED(addr)) {
ds_put_format(s, IP_FMT, addr->s6_addr[12], addr->s6_addr[13],
addr->s6_addr[14], addr->s6_addr[15]);
} else {
- print_ipv6_addr(s, addr);
+ ipv6_format_addr(addr, s);
}
}
void
-print_ipv6_masked(struct ds *s, const struct in6_addr *addr,
- const struct in6_addr *mask)
+ipv6_format_masked(const struct in6_addr *addr, const struct in6_addr *mask,
+ struct ds *s)
{
- print_ipv6_addr(s, addr);
+ ipv6_format_addr(addr, s);
if (mask && !ipv6_mask_is_exact(mask)) {
if (ipv6_is_cidr(mask)) {
int cidr_bits = ipv6_count_cidr_bits(mask);
ds_put_format(s, "/%d", cidr_bits);
} else {
ds_put_char(s, '/');
- print_ipv6_addr(s, mask);
+ ipv6_format_addr(mask, s);
}
}
}
put_16aligned_be32(&sh->sctp_csum, old_csum ^ old_correct_csum ^ new_csum);
}
+/* Sets the ICMP type and code of the ICMP header contained in 'packet'.
+ * 'packet' must be a valid ICMP packet with its l4 offset properly
+ * populated. */
+void
+packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code)
+{
+ struct icmp_header *ih = dp_packet_l4(packet);
+ ovs_be16 orig_tc = htons(ih->icmp_type << 8 | ih->icmp_code);
+ ovs_be16 new_tc = htons(type << 8 | code);
+
+ if (orig_tc != new_tc) {
+ ih->icmp_type = type;
+ ih->icmp_code = code;
+
+ ih->icmp_csum = recalc_csum16(ih->icmp_csum, orig_tc, new_tc);
+ }
+}
+
void
packet_set_nd(struct dp_packet *packet, const ovs_be32 target[4],
const struct eth_addr sll, const struct eth_addr tll) {
return partial;
}
+