aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2008-12-29 13:47:41 +0200
committerTimo Teras <timo.teras@iki.fi>2008-12-29 13:47:41 +0200
commitdbe877cdca9a693462d776dd978592ed1068da0f (patch)
tree7907bd5d64750e5d15439cd7e533c2a7f826895f
parentcab8b9de73a8471ae69485dddebfa1e91c0a28eb (diff)
downloadpingu-dbe877cdca9a693462d776dd978592ed1068da0f.tar.bz2
pingu-dbe877cdca9a693462d776dd978592ed1068da0f.tar.xz
mtu: write discovered mtu to interface mtu
-rw-r--r--mtu.c74
-rw-r--r--netlink.c54
-rw-r--r--netlink.h2
3 files changed, 110 insertions, 20 deletions
diff --git a/mtu.c b/mtu.c
index e2fb7c3..1ef1bce 100644
--- a/mtu.c
+++ b/mtu.c
@@ -5,6 +5,8 @@
#include <string.h>
#include <unistd.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
#include <netinet/ip_icmp.h>
#include "icmp.h"
@@ -17,7 +19,8 @@ static void usage(void)
fprintf(stderr,
"usage: mtu -i <mtu-size> <host>\n"
" mtu -I <host>\n"
- " mtu -d <host>\n");
+ " mtu -d <host>\n"
+ " mtu -D <host>\n");
exit(3);
}
@@ -58,16 +61,14 @@ static int do_ping(int seq, int size)
return -1;
}
-static void do_discover(void)
+static int discover_mtu(void)
{
int seq = 1;
int low_mtu, high_mtu, try_mtu;
/* Check if the host is up */
- if (do_ping(seq++, 0) < 0) {
- fprintf(stderr, "Host is not up\n");
- return;
- }
+ if (do_ping(seq++, 0) < 0)
+ return -1;
/* Check if there is no PMTU or if PMTU discovery works */
low_mtu = do_ping(seq++, 1500);
@@ -85,7 +86,59 @@ static void do_discover(void)
low_mtu = 1500;
}
- fprintf(stdout, "%d\n", low_mtu);
+ return low_mtu;
+}
+
+static void do_discover(void)
+{
+ int mtu;
+
+ mtu = discover_mtu();
+ if (mtu > 0)
+ fprintf(stdout, "%d\n", mtu);
+ else
+ fprintf(stderr, "Host is not up\n");
+}
+
+static int set_mtu(const char *dev, int mtu)
+{
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ ifr.ifr_mtu = mtu;
+ if (ioctl(fd, SIOCSIFMTU, &ifr) < 0) {
+ perror("SIOCSIFMTU");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+static void do_discover_and_write(void)
+{
+ int mtu;
+ char iface[IFNAMSIZ];
+
+ mtu = discover_mtu();
+ if (mtu < 0) {
+ fprintf(stderr, "Failed to determine MTU\n");
+ return;
+ }
+
+ if (!netlink_route_get(&to, NULL, iface)) {
+ fprintf(stderr, "Failed to determine route interface\n");
+ return;
+ }
+
+ printf("Writing %d to %s\n", mtu, iface);
+ set_mtu(iface, mtu);
}
static void do_inject(void)
@@ -121,7 +174,7 @@ static void do_inject_pmtu(void)
{
u_int16_t mtu;
- if (netlink_route_get(&to, &mtu) < 0) {
+ if (!netlink_route_get(&to, &mtu, NULL)) {
fprintf(stderr, "Failed to determine Path MTU\n");
return;
}
@@ -139,8 +192,11 @@ int main(int argc, char **argv)
char *target;
int opt;
- while ((opt = getopt(argc, argv, "dIi:")) != -1) {
+ while ((opt = getopt(argc, argv, "DdIi:")) != -1) {
switch (opt) {
+ case 'D':
+ action = do_discover_and_write;
+ break;
case 'd':
action = do_discover;
break;
diff --git a/netlink.c b/netlink.c
index 3e85e6f..5e43116 100644
--- a/netlink.c
+++ b/netlink.c
@@ -220,16 +220,21 @@ out:
return ret;
}
-int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu)
+int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname)
{
struct {
struct nlmsghdr n;
- struct rtmsg r;
+ union {
+ struct rtmsg r;
+ struct ifinfomsg i;
+ };
char buf[1024];
} req;
struct rtmsg *r = NLMSG_DATA(&req.n);
struct rtattr *rta[RTA_MAX+1];
struct rtattr *rtax[RTAX_MAX+1];
+ struct rtattr *ifla[IFLA_MAX+1];
+ int index;
memset(&req, 0, sizeof(req));
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
@@ -243,15 +248,44 @@ int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu)
if (!netlink_talk(&req.n, sizeof(req), &req.n))
return FALSE;
- netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n));
- if (rta[RTA_METRICS] == NULL)
- return FALSE;
+ netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r),
+ RTM_PAYLOAD(&req.n));
- netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]),
- RTA_PAYLOAD(rta[RTA_METRICS]));
- if (rtax[RTAX_MTU] == NULL)
- return FALSE;
+ if (mtu != NULL) {
+ if (rta[RTA_METRICS] == NULL)
+ return FALSE;
+
+ netlink_parse_rtattr(rtax, RTAX_MAX,
+ RTA_DATA(rta[RTA_METRICS]),
+ RTA_PAYLOAD(rta[RTA_METRICS]));
+ if (rtax[RTAX_MTU] == NULL)
+ return FALSE;
+
+ *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]);
+ }
+
+ if (ifname != NULL) {
+ if (rta[RTA_OIF] == NULL)
+ return FALSE;
+
+ index = *(int*) RTA_DATA(rta[RTA_OIF]);
+
+ memset(&req, 0, sizeof(req));
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETLINK;
+ req.i.ifi_index = index;
+ if (!netlink_talk(&req.n, sizeof(req), &req.n))
+ return FALSE;
+
+ netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r),
+ IFLA_PAYLOAD(&req.n));
+ if (ifla[IFLA_IFNAME] == NULL)
+ return FALSE;
+
+ memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]),
+ RTA_PAYLOAD(ifla[IFLA_IFNAME]));
+ }
- *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]);
return TRUE;
}
diff --git a/netlink.h b/netlink.h
index 8c44925..4e2ceb2 100644
--- a/netlink.h
+++ b/netlink.h
@@ -1,6 +1,6 @@
#ifndef PINGU_NETLINK_H
#define PINGU_NETLINK_H
-int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu);
+int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname);
#endif