]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
network: set mtu of unpriv veth to the bridge's mtu
authorSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 19 Feb 2014 04:42:34 +0000 (22:42 -0600)
committerSerge Hallyn <serge.hallyn@ubuntu.com>
Wed, 19 Feb 2014 05:16:27 +0000 (23:16 -0600)
That's to make sure that if the bridge has a higher than 1500
mtu, the new veth (defaulting to 1500) doesn't lower it.

Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
src/lxc/lxc_user_nic.c
src/lxc/network.c
src/lxc/network.h

index a67c63d64e9bf36519ce123db5ceafc14f9e1014..0e665495b90bb34eaf22b22e8f838c3632eff06e 100644 (file)
@@ -226,12 +226,18 @@ static int instanciate_veth(char *n1, char **n2)
        return netdev_set_flag(n1, IFF_UP);
 }
 
+static int get_mtu(char *name)
+{
+       int idx = if_nametoindex(name);
+       return netdev_get_mtu(idx);
+}
+
 static bool create_nic(char *nic, char *br, int pid, char **cnic)
 {
        char *veth1buf, *veth2buf;
        veth1buf = alloca(IFNAMSIZ);
        veth2buf = alloca(IFNAMSIZ);
-       int ret;
+       int ret, mtu;
 
        ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
        if (ret < 0 || ret >= IFNAMSIZ) {
@@ -245,6 +251,16 @@ static bool create_nic(char *nic, char *br, int pid, char **cnic)
                return false;
        }
 
+       /* copy the bridge's mtu to both ends */
+       mtu = get_mtu(br);
+       if (mtu != -1) {
+               if (lxc_netdev_set_mtu(veth1buf, mtu) < 0 ||
+                               lxc_netdev_set_mtu(veth2buf, mtu) < 0) {
+                       fprintf(stderr, "Failed setting mtu\n");
+                       goto out_del;
+               }
+       }
+
        /* attach veth1 to bridge */
        if (lxc_bridge_attach(br, veth1buf) < 0) {
                fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
index 34845d1a9d048f08b1b8b8dbe07c5e63968241bc..090b9bd6bbc59050e9b51ce79c88bf4b9b7884a8 100644 (file)
@@ -297,6 +297,116 @@ out:
        return err;
 }
 
+int netdev_get_mtu(int ifindex)
+{
+       struct nl_handler nlh;
+       struct nlmsg *nlmsg = NULL, *answer = NULL;
+       struct ip_req *ip_req;
+       struct nlmsghdr *msg;
+       int err, res;
+       int recv_len = 0, answer_len;
+       int readmore = 0;
+
+       err = netlink_open(&nlh, NETLINK_ROUTE);
+       if (err)
+               return err;
+
+       err = -ENOMEM;
+       nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!nlmsg)
+               goto out;
+
+       answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
+       if (!answer)
+               goto out;
+
+       /* Save the answer buffer length, since it will be overwritten
+        * on the first receive (and we might need to receive more than
+        * once. */
+       answer_len = answer->nlmsghdr.nlmsg_len;
+
+       ip_req = (struct ip_req *)nlmsg;
+       ip_req->nlmsg.nlmsghdr.nlmsg_len =
+               NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+       ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+       ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_GETLINK;
+       ip_req->ifa.ifa_family = AF_UNSPEC;
+
+       /* Send the request for addresses, which returns all addresses
+        * on all interfaces. */
+       err = netlink_send(&nlh, nlmsg);
+       if (err < 0)
+               goto out;
+
+       do {
+               /* Restore the answer buffer length, it might have been
+                * overwritten by a previous receive. */
+               answer->nlmsghdr.nlmsg_len = answer_len;
+
+               /* Get the (next) batch of reply messages */
+               err = netlink_rcv(&nlh, answer);
+               if (err < 0)
+                       goto out;
+
+               recv_len = err;
+               err = 0;
+
+               /* Satisfy the typing for the netlink macros */
+               msg = &answer->nlmsghdr;
+
+               while (NLMSG_OK(msg, recv_len)) {
+
+                       /* Stop reading if we see an error message */
+                       if (msg->nlmsg_type == NLMSG_ERROR) {
+                               struct nlmsgerr *errmsg = (struct nlmsgerr*)NLMSG_DATA(msg);
+                               err = errmsg->error;
+                               goto out;
+                       }
+
+                       /* Stop reading if we see a NLMSG_DONE message */
+                       if (msg->nlmsg_type == NLMSG_DONE) {
+                               readmore = 0;
+                               break;
+                       }
+
+                       struct ifinfomsg *ifi = NLMSG_DATA(msg);
+                       if (ifi->ifi_index == ifindex) {
+                               struct rtattr *rta = IFLA_RTA(ifi);
+                               int attr_len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
+                               res = 0;
+                               while(RTA_OK(rta, attr_len)) {
+                                       /* Found a local address for the requested interface,
+                                        * return it. */
+                                       if (rta->rta_type == IFLA_MTU) {
+                                               memcpy(&res, RTA_DATA(rta), sizeof(int));
+                                               err = res;
+                                               goto out;
+                                       }
+                                       rta = RTA_NEXT(rta, attr_len);
+                               }
+
+                       }
+
+                       /* Keep reading more data from the socket if the
+                        * last message had the NLF_F_MULTI flag set */
+                       readmore = (msg->nlmsg_flags & NLM_F_MULTI);
+
+                       /* Look at the next message received in this buffer */
+                       msg = NLMSG_NEXT(msg, recv_len);
+               }
+       } while (readmore);
+
+       /* If we end up here, we didn't find any result, so signal an
+        * error */
+       err = -1;
+
+out:
+       netlink_close(&nlh);
+       nlmsg_free(answer);
+       nlmsg_free(nlmsg);
+       return err;
+}
+
 int lxc_netdev_set_mtu(const char *name, int mtu)
 {
        struct nl_handler nlh;
index 3ea99ac2cf41cdc9d8e06c87d2060ccb76fbfbd1..97f6b4d3375c159efbe0d6b7fb4276c80029b3a3 100644 (file)
@@ -138,4 +138,5 @@ extern char *lxc_mkifname(char *template);
 
 extern const char *lxc_net_type_to_str(int type);
 extern int setup_private_host_hw_addr(char *veth1);
+extern int netdev_get_mtu(int ifindex);
 #endif